Skip to content
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

Infinite loop in Typers#adapt with overloaded types, erroneous trees #6912

Closed
scabug opened this issue Jan 4, 2013 · 6 comments
Closed

Infinite loop in Typers#adapt with overloaded types, erroneous trees #6912

scabug opened this issue Jan 4, 2013 · 6 comments

Comments

@scabug
Copy link

scabug commented Jan 4, 2013

I haven't minimized this one yet.

The loop appears:

  last tree to typer: Ident(QuotableKey)
              symbol: class <error: <none>> (flags: <synthetic> <is_error>)
   symbol definition: class <error: <none>> extends 
                 tpe: <error>
       symbol owners: class <error: <none>> -> method indexedPathCube -> trait FullPathLocator -> package mc
      context owners: method indexedPathCube -> trait FullPathLocator -> package mc


 at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1069)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)

  at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1070)
        case OverloadedType(pre, alts) if !inFunMode(mode) => // (1)
          inferExprAlternative(tree, pt)
          adapt(tree, mode, pt, original)
@scabug
Copy link
Author

scabug commented Jan 4, 2013

Imported From: https://issues.scala-lang.org/browse/SI-6912?orig=1
Reporter: @retronym
Affected Versions: 2.10.0

@scabug
Copy link
Author

scabug commented Jan 4, 2013

@JamesIry said:
Is there any reproducer for this, minimized or not?

@scabug
Copy link
Author

scabug commented Jan 4, 2013

@retronym said:
Sadly, no. It slipped through my fingers as I was porting a customer's codebase do 2.10. Maybe I'll be able to reverse engineer a reproduction, or add a sanity check to prevent the loop.

@scabug
Copy link
Author

scabug commented Jan 8, 2013

@retronym said (edited on Jan 8, 2013 9:19:54 AM UTC):
So inspecting the code in inferExprAlternative, it would appear that it could fall through if best != NoSymbol && !competing.isEmpty && !noAlternatives && pt.isErroneous.

        if (best == NoSymbol) {
          // ...
          NoBestExprAlternativeError(tree, pt, isSecondTry)
        } else if (!competing.isEmpty) {
          if (noAlternatives) NoBestExprAlternativeError(tree, pt, isSecondTry)
          else if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt, isSecondTry)
        } else {
          tree.setSymbol(best).setType(pre.memberType(best))
        }

This commit seems relevant:

scala/scala@b10b58

+        // since inferMethodAlternative modifies the state of the tree 
+        // we have to set the type of tree to ErrorType only in the very last
+        // fallback action that is done in the inference (tracking it manually is error prone).
+        // This avoids entering infinite loop in doTypeApply.
+        // TODO: maybe we should do the same thing with inferExprAlternative.
+        if (implicitly[Context].reportErrors) setError(tree)

It was refined later in:

scala/scala@1ddc93

See also:

      // side-effect on the tree, break the overloaded type cycle in infer
      private def setErrorOnLastTry(lastTry: Boolean, tree: Tree) = if (lastTry) setError(tree)

Actually, digging back a bit further:

scala/scala@c800d1

         } else if (!competing.isEmpty) {
-          if (secondTry) {
-            typeErrorTree(tree, tree.symbol.tpe, pt)
-          } else {
-            if (!pt.isErroneous)
-              context.ambiguousError(tree.pos, pre, best, competing.head, "expected type " + pt)
-            setError(tree)
-          }
+          if (secondTry) NoBestExprAlternativeError(tree, pt)
+          else { if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt) }
         } else {

Before that change, in the condition mentioned above, setError(tree) was called, which would have broken the loop.

@scabug
Copy link
Author

scabug commented Jan 8, 2013

@retronym said:
scala/scala#1859

@scabug
Copy link
Author

scabug commented Jan 13, 2013

@paulp said:
5d65772762

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants