Scala Programming Language
  1. Scala Programming Language
  2. SI-6436

String interpolation: error spawned by ambiguous implicit leads to an SO

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: Scala 2.10.0-M7, Scala 2.10.0
    • Component/s: Misc Compiler
    • Labels:
      None
    • Environment:

      Compiler 2.10.0-SNAPSHOT
      Java 1.6.0_35
      Mac OS X 10.8.2

      Description

      object quasiquotes {
        implicit def foo1(ctx: StringContext) = new { def q = ??? }
        implicit def foo2(ctx: StringContext) = new { def q = ??? }
      }
      
      object Test extends App {
        import quasiquotes._
        // new StringContext().q => doesn't crash
        println(q"hello") // => crashes
      }
      
      myke compile C:\Projects\Kepler\sandbox\Test.scala -Ydebug
      git: branch = 2.10.x, commit = 1d072fcb41 Merge pull request #1408 from scalamacros/topic/direct-test (Paul Phillips, 26.09.2012 22:54:01 -07:00)
      psi: filename = cmd.exe, arguments = /C c:\PROGRA~1\Java\JDK\bin\java.exe -cp "C:\Projects\Kepler\test\files\codelib\code.jar;C:\Projects\Kepler\lib\jline.jar;C:\Projects\Kepler\build\locker\lib\scala-partest.jar;C:\Projects\Kepler\lib\fjbg.jar;C:\Projects\Kepler\build\locker\classes\compiler;C:\Projects\Kepler\build\asm\classes;C:\Projects\Kepler\build\libs\forkjoin.jar;C:\Projects\Kepler\build\locker\classes\reflect;C:\Projects\Kepler\build\locker\classes\library" -Dscala.usejavacp=true -Dscala.repl.vids=1 -Dscala.repl.autoruncode=C:\Users\xeno.by/.scala_autorun -Dscala.repl.maxprintstring=0 scala.tools.nsc.Main -language:experimental.macros -Ydebug Test.scala, home = C:\Projects\Kepler\sandbox
      [running phase parser on Test.scala]
      [running phase namer on Test.scala]
      [running phase packageobjects on Test.scala]
      [running phase typer on Test.scala]
      warning: issue error: type mismatch;
       found   : scala.this.StringContext
       required: ?{<method> def q: ?}
      Note that implicit conversions are not applicable because they are ambiguous:
       both method foo1 in module class quasiquotes of type (<param> ctx: scala.this.StringContext)lang.this.Object{<method> def q: scala.this.Nothing}
       and method foo2 in module class quasiquotes of type (<param> ctx: scala.this.StringContext)lang.this.Object{<method> def q: scala.this.Nothing}
       are possible conversion functions from scala.this.StringContext to ?{<method> def q: ?}
      warning: update buffer: Set(scala.tools.nsc.typechecker.ContextErrors$AmbiguousTypeError)
      warning: issue error: type mismatch;
       found   : scala.this.StringContext
       required: ?{<method> def q: ?}
      Note that implicit conversions are not applicable because they are ambiguous:
       both method foo1 in module class quasiquotes of type (<param> ctx: scala.this.StringContext)lang.this.Object{<method> def q: scala.this.Nothing}
       and method foo2 in module class quasiquotes of type (<param> ctx: scala.this.StringContext)lang.this.Object{<method> def q: scala.this.Nothing}
       are possible conversion functions from scala.this.StringContext to ?{<method> def q: ?}
      warning: issue error: type mismatch;
       found   : scala.this.StringContext
       required: ?{<method> def q: ?}
      Note that implicit conversions are not applicable because they are ambiguous:
       both method foo1 in module class quasiquotes of type (<param> ctx: scala.this.StringContext)lang.this.Object{<method> def q: scala.this.Nothing}
       and method foo2 in module class quasiquotes of type (<param> ctx: scala.this.StringContext)lang.this.Object{<method> def q: scala.this.Nothing}
       are possible conversion functions from scala.this.StringContext to ?{<method> def q: ?}
      warning: update buffer: Set(scala.tools.nsc.typechecker.ContextErrors$AmbiguousTypeError)
      ..............
      ..............
      ..............
      ***snip***
      ..............
      ..............
      ..............
      warning: issue error: type mismatch;
       found   : scala.this.StringContext
       required: ?{<method> def q: ?}
      Note that implicit conversions are not applicable because they are ambiguous:
       both method foo1 in module class quasiquotes of type (<param> ctx: scala.this.StringContext)lang.this.Object{<method> def q: scala.this.Nothing}
       and method foo2 in module class quasiquotes of type (<param> ctx: scala.this.StringContext)lang.this.Object{<method> def q: scala.this.Nothing}
       are possible conversion functions from scala.this.StringContext to ?{<method> def q: ?}
      error:
           while compiling: Test.scala
              during phase: typer
           library version: version 2.10.0-20120926-202924-e1485dbea5
          compiler version: version 2.10.0-20120926-202924-e1485dbea5
        reconstructed args: -Ydebug -language:experimental.macros
      
        last tree to typer: Ident(foo2)
                    symbol: <none> (flags: )
         symbol definition: <none>
             symbol owners:
            context owners: value <local Test> -> module class Test -> package <empty>
      
      == Enclosing template or block ==
      
      Import( // val <import>: ImportType(quasiquotes)
        "quasiquotes" // <module> <triedcooking> object quasiquotes, tree.tpe=<empty>.this.quasiquotes.type
        List(
          ImportSelector(_,195,null,-1)
        )
      )
      
      == Current unit body ==
      
      <empty>
      
      
      uncaught exception during compilation: java.lang.StackOverflowError
      error: java.lang.StackOverflowError
        at scala.reflect.internal.Trees$TreeContextApiImpl.<init>(Trees.scala:76)
        at scala.reflect.internal.Trees$Tree.<init>(Trees.scala:17)
        at scala.reflect.internal.Trees$SymTree.<init>(Trees.scala:212)
        at scala.reflect.internal.Trees$Ident.<init>(Trees.scala:432)
        at scala.reflect.internal.Trees$StrictTreeCopier.Ident(Trees.scala:587)
        at scala.reflect.internal.Trees$StrictTreeCopier.Ident(Trees.scala:516)
        at scala.reflect.internal.Trees$class.itransform(Trees.scala:1173)
        at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:12)
        at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:12)
        at scala.reflect.api.Trees$Transformer.transform(Trees.scala:1910)
        at scala.reflect.internal.Trees$$anon$1.transform(Trees.scala:1459)
        at scala.reflect.internal.Trees$$anon$1.transform(Trees.scala:1456)
        at scala.reflect.internal.Trees$Tree.duplicate(Trees.scala:73)
        at scala.tools.nsc.typechecker.Typers$Typer.typedIdent$1(Typers.scala:4916)
        at scala.tools.nsc.typechecker.Typers$Typer.typedIdentOrWildcard$1(Typers.scala:4980)
        at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5311)
        at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5390)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$87.apply(Typers.scala:4389)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$87.apply(Typers.scala:4389)
        at scala.tools.nsc.typechecker.Typers$Typer.silent(Typers.scala:727)
        at scala.tools.nsc.typechecker.Typers$Typer.normalTypedApply$1(Typers.scala:4389)
        at scala.tools.nsc.typechecker.Typers$Typer.typedApply$1(Typers.scala:4440)
        at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5313)
        at scala.tools.nsc.typechecker.Implicits$ImplicitSearch.typedImplicit1(Implicits.scala:586)
        at scala.tools.nsc.typechecker.Implicits$ImplicitSearch.typedImplicit0(Implicits.scala:554)
        at scala.tools.nsc.typechecker.Implicits$ImplicitSearch.liftedTree1$1(Implicits.scala:406)
        at scala.tools.nsc.typechecker.Implicits$ImplicitSearch.scala$tools$nsc$typechecker$Implicits$ImplicitSearch$$typedImplicit(Implicits.scala:403)
        at scala.tools.nsc.typechecker.Implicits$ImplicitSearch$ImplicitComputation.tryImplicitInfo$1(Implicits.scala:830)
        at scala.tools.nsc.typechecker.Implicits$ImplicitSearch$ImplicitComputation.rankImplicits(Implicits.scala:833)
        at scala.tools.nsc.typechecker.Implicits$ImplicitSearch$ImplicitComputation.findBest(Implicits.scala:868)
        at scala.tools.nsc.typechecker.Implicits$ImplicitSearch.searchImplicit(Implicits.scala:927)
        at scala.tools.nsc.typechecker.Implicits$ImplicitSearch.bestImplicit(Implicits.scala:1378)
        at scala.tools.nsc.typechecker.Implicits$class.inferImplicit(Implicits.scala:82)
        at scala.tools.nsc.Global$$anon$1.inferImplicit(Global.scala:490)
        at scala.tools.nsc.typechecker.Implicits$class.inferImplicit(Implicits.scala:40)
        at scala.tools.nsc.Global$$anon$1.inferImplicit(Global.scala:490)
        at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$wrapImplicit$1(Typers.scala:197)
        at scala.tools.nsc.typechecker.Typers$Typer.inferView(Typers.scala:204)
        at scala.tools.nsc.typechecker.Typers$Typer.adaptToMember(Typers.scala:1305)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$17.apply(Typers.scala:1365)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$17.apply(Typers.scala:1365)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$silent$2.apply(Typers.scala:738)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$silent$2.apply(Typers.scala:737)
        at scala.tools.nsc.typechecker.Typers$Typer.withSavedContext(Typers.scala:520)
        at scala.tools.nsc.typechecker.Typers$Typer.silent(Typers.scala:737)
        at scala.tools.nsc.typechecker.Typers$Typer.adaptToMemberWithArgs(Typers.scala:1365)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$93.apply(Typers.scala:4580)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$93.apply(Typers.scala:4575)
        at scala.reflect.internal.Symbols$Symbol.orElse(Symbols.scala:2170)
        at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedSelect$1(Typers.scala:4575)
        at scala.tools.nsc.typechecker.Typers$Typer.typedSelectOrSuperCall$1(Typers.scala:4713)
        at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5312)
        at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5390)
        at scala.tools.nsc.typechecker.Typers$Typer.typedQualifier(Typers.scala:5463)
        at scala.tools.nsc.typechecker.Typers$Typer.typedQualifier(Typers.scala:5469)
        at scala.tools.nsc.typechecker.Typers$Typer.typedSelectOrSuperCall$1(Typers.scala:4693)
        at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5312)
        at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5390)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$93.apply(Typers.scala:4582)
        at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$93.apply(Typers.scala:4575)
        at scala.reflect.internal.Symbols$Symbol.orElse(Symbols.scala:2170)
        at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedSelect$1(Typers.scala:4575)
        at scala.tools.nsc.typechecker.Typers$Typer.typedSelectOrSuperCall$1(Typers.scala:4713)
        ***snip***
      

        Activity

        Hide
        Jason Zaugg added a comment -

        I'm working on a fix for this, we need to refine:

        if (name != nme.CONSTRUCTOR && inExprModeOr(mode, PATTERNmode)) {
          val qual1 = adaptToMemberWithArgs(tree, qual, name, mode, true, true)
          if (qual1 ne qual)
            return typed(treeCopy.Select(tree, qual1, name), mode, pt)
        }
        

        https://github.com/scala/scala/blob/886c40/src/compiler/scala/tools/nsc/typechecker/Typers.scala#L4603

        To something like:

        if (qual1 ne tree)
        

        or

        if (!qual1.isErrorTyped)
        

        I haven't pinpointed why a formatted literal spins into an infinite loop, whereas the desugared expression recovers with a sensible type error.

        I might not be able to submit a PR for this for a day or two.

        Show
        Jason Zaugg added a comment - I'm working on a fix for this, we need to refine: if (name != nme.CONSTRUCTOR && inExprModeOr(mode, PATTERNmode)) { val qual1 = adaptToMemberWithArgs(tree, qual, name, mode, true, true) if (qual1 ne qual) return typed(treeCopy.Select(tree, qual1, name), mode, pt) } https://github.com/scala/scala/blob/886c40/src/compiler/scala/tools/nsc/typechecker/Typers.scala#L4603 To something like: if (qual1 ne tree) or if (!qual1.isErrorTyped) I haven't pinpointed why a formatted literal spins into an infinite loop, whereas the desugared expression recovers with a sensible type error. I might not be able to submit a PR for this for a day or two.
        Hide
        Hubert Plociniczak added a comment -

        Indeed. I noticed it while working on https://github.com/scala/scala/pull/1406 and the fix is there (although this is for master).

        Show
        Hubert Plociniczak added a comment - Indeed. I noticed it while working on https://github.com/scala/scala/pull/1406 and the fix is there (although this is for master).
        Hide
        Jason Zaugg added a comment - - edited

        In addition, I believe that adaptToMemberWithArgs should return qual, not tree, when it encounters an error.

        https://github.com/scala/scala/blob/886c406/src/compiler/scala/tools/nsc/typechecker/Typers.scala#L1367

        This would be the same as adaptToMember.

        Show
        Jason Zaugg added a comment - - edited In addition, I believe that adaptToMemberWithArgs should return qual , not tree , when it encounters an error. https://github.com/scala/scala/blob/886c406/src/compiler/scala/tools/nsc/typechecker/Typers.scala#L1367 This would be the same as adaptToMember .
        Hide
        Grzegorz Kossakowski added a comment - - edited

        Jason: assigning to you. Any estimates how long will it take for you to address it?

        Also, do you think it's critical (means: blocking 2.10.0)?

        Show
        Grzegorz Kossakowski added a comment - - edited Jason: assigning to you. Any estimates how long will it take for you to address it? Also, do you think it's critical (means: blocking 2.10.0)?
        Hide
        Jason Zaugg added a comment -

        I'll submit a PR tonight. I would definitely include the fix in 2.10.0 (it is trivial and zero-risk).

        I don't know yet why the problem only manifests in such a specific and limited case; it looks like it ought to break more often.

        Show
        Jason Zaugg added a comment - I'll submit a PR tonight. I would definitely include the fix in 2.10.0 (it is trivial and zero-risk). I don't know yet why the problem only manifests in such a specific and limited case; it looks like it ought to break more often.
        Show
        Jason Zaugg added a comment - https://github.com/scala/scala/pull/1446
        Show
        Grzegorz Kossakowski added a comment - Fixed in https://github.com/scala/scala/pull/1446

          People

          • Assignee:
            Jason Zaugg
            Reporter:
            Denys Shabalin
          • Votes:
            0 Vote for this issue
            Watchers:
            7 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development