-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Erratic compiler behavior for inlined function definitions #15893
Comments
@Bersier Do you think you could give this a try to fix yourself? |
@odersky I have no familiarity with the compiler code. If someone gives me an introduction (in a video call) and is willing to help me when I get stuck, I could give it a try. |
@Bersier Sorry, I confused you with someone else, who had worked on dotc before. |
The first critical problem is if we just compare mod2 and dependentlyTypedMod2. The first is OK, the second fails with the runtime error. Here is their code after typer: def mod2(n: NatT): NatT =
n match
{
case Zero():Zero =>
Zero.apply()
case Succ.unapply[NatT](Zero():Zero):Succ[NatT] =>
Succ.apply[Zero](Zero.apply())
case
Succ.unapply[NatT](Succ.unapply[NatT](predPredN @ _):Succ[NatT]):
Succ[NatT]
=>
mod2(predPredN)
}
def dependentlyTypedMod2[N >: Nothing <: NatT](n: N): Mod2[N] =
(n match
{
case Zero():Zero =>
Zero.apply()
case Succ.unapply[Zero](Zero()):Succ[Zero] =>
Succ.apply[Zero](Zero.apply())
case
Succ.unapply[Succ[_]](Succ.unapply[_](predPredN @ _)):
Succ[Succ[_ @ >: Nothing <: Any]]
=>
dependentlyTypedMod2[_](predPredN):Mod2[_]
}
).$asInstanceOf[
N match {
case Zero => Zero
case Succ[Zero] => Succ[Zero]
case Succ[Succ[predPredN]] => Mod2[predPredN]
} <: NatT
] The failing case is the second. Here we see for case Succ.unapply[NatT](Zero():Zero):Succ[NatT] =>
Succ.apply[Zero](Zero.apply()) and for dependentlyTypedMod2: case Succ.unapply[Zero](Zero()):Succ[Zero] =>
Succ.apply[Zero](Zero.apply()) This seems to assume too much type information. If you show the code after pattern matching that's confirmed. The if x9.$isInstanceOf[Succ[NatT]] then
{
case val x17: Succ[NatT] =
Succ.unapply[NatT](x9.$asInstanceOf[Succ[NatT]])
case val x18: NatT = x17._1
if
x18.$isInstanceOf[Zero].&&(Zero.unapply(x18.$asInstanceOf[Zero])
)
then
return[matchResult7]
{
Succ.apply[Zero](Zero.apply())
}
else () The dependentlyTypedMod2 code is as follows: if x21.$isInstanceOf[Succ[Zero]] then
{
case val x28: Succ[Zero] =
Succ.unapply[Zero](x21.$asInstanceOf[Succ[Zero]])
case val x29: Zero = x28._1
if x29.ne(null).&&(Zero.unapply(x29)) then
return[matchResult8]
{
Succ.apply[Zero](Zero.apply())
}
else ()
}
else () Clearly, the RHS of I believe the difference of the behaviors is due to GADT reasoning in the second case. It seems we are using GADT reasoning (i.e. what can we conclude if the pattern matches) already as input for the pattern matching itself. |
In fact after further digging it looks it has nothing to do with GADT reasoning either. The culprit is combined unapply/type test pattern. It seems that's just handled incorrectly. case Zero(): Zero => Zero()
case Succ(Zero()): Succ[Zero] => Succ(Zero())
case Succ(Succ(predPredN)): Succ[Succ[_]] => dependentlyTypedMod2(predPredN) Note that patterns like this are disallowed in Scala 2. We might end up doing the same thing. |
@odersky so would you be ok with merging a rebased #11023? Generally it's nice to be able to combine and nest things, and I would look to go through and do all the things that need doing in #11801. But I'm just not sure it's clear to the average Scala user that in |
Yes, I think we should retract instead and go with #11023 |
See this discussion thread.
Compiler version
3.1.3
Minimized code
Output
Expectation
inlineFoo(Succ(Succ(Succ(Zero()))))
should not returnSucc(Succ(Succ(Zero())))
;inline
should not change function output.The text was updated successfully, but these errors were encountered: