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

resetLocalAttrs followed by typeCheck causes error

    Details

      Description

      This is a regression; it works fine in 2.10.0 but is broken in 2.10.1.

      Given this macro definition which does nothing but resetLocalAttrs and then typeCheck the result:

      def noop[A](expr: A): A = macro noopImpl[A]  
      def noopImpl[A](c: Context)(expr: c.Expr[A]): c.Expr[A] = c.Expr(c.typeCheck(c.resetLocalAttrs(expr.tree)))
      

      If you try to use it you'll get an error:

      scala> noop(List(1) match { case Nil => 0; case (x::xs) => x })
      error: exception during macro expansion:
      scala.reflect.macros.TypecheckException: not found: value _
      	at scala.reflect.macros.runtime.Typers$$anonfun$typeCheck$2.apply(Typers.scala:31)
      	at scala.reflect.macros.runtime.Typers$$anonfun$typeCheck$2.apply(Typers.scala:25)
      	at scala.tools.nsc.typechecker.Contexts$Context.withMacrosEnabled(Contexts.scala:240)
      	at scala.reflect.macros.runtime.Typers$$anonfun$3.apply(Typers.scala:18)
      	at scala.reflect.macros.runtime.Typers$$anonfun$3.apply(Typers.scala:18)
      	at scala.reflect.macros.runtime.Typers$$anonfun$wrapper$1$1.apply(Typers.scala:19)
      	at scala.reflect.macros.runtime.Typers$$anonfun$wrapper$1$1.apply(Typers.scala:19)
      	at scala.tools.nsc.typechecker.Contexts$Context.withImplicitsEnabled(Contexts.scala:209)
      	at scala.reflect.macros.runtime.Typers$$anonfun$1.apply(Typers.scala:17)
      	at scala.reflect.macros.runtime.Typers$$anonfun$1.apply(Typers.scala:17)
      	at scala.reflect.macros.runtime.Typers$class.wrapper$1(Typers.scala:19)
      	at scala.reflect.macros.runtime.Typers$class.typeCheck(Typers.scala:25)
      	at scala.reflect.macros.runtime.Context.typeCheck(Context.scala:6)
      	at scala.reflect.macros.runtime.Context.typeCheck(Context.scala:6)
      	at monadsyntax.package$.noopImpl(package.scala:12)
      

      It looks like possibly related to SI-5464, but seems distinct in that it is a regression.

        Activity

        Hide
        Eugene Burmako added a comment -

        Is this urgent? If yes, I'll take a look asap, otherwise I'd prefer to investigate later.

        Show
        Eugene Burmako added a comment - Is this urgent? If yes, I'll take a look asap, otherwise I'd prefer to investigate later.
        Hide
        Thomas Crockett added a comment -

        Not urgent, I can use 2.10.0 in the meantime, thanks.

        Show
        Thomas Crockett added a comment - Not urgent, I can use 2.10.0 in the meantime, thanks.
        Hide
        Jason Zaugg added a comment -

        Some breadcrumbs:

        def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = {
                val stableApplication = (fun.symbol ne null) && fun.symbol.isMethod && fun.symbol.isStable
                if (stableApplication && isPatternMode) {
                  // treat stable function applications f() as expressions.
                  typed1(tree, mode & ~PATTERNmode | EXPRmode, pt)
                
        
             def typedIdentOrWildcard(tree: Ident) = {
                val name = tree.name
                if (Statistics.canEnable) Statistics.incCounter(typedIdentCount)
                if ((name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode) ||
                    (name == tpnme.WILDCARD && (mode & TYPEmode) != 0))
                  tree setType makeFullyDefined(pt)
                else
                  typedIdent(tree, name)
              }
        

        In the original type check, we get to:

        normalTypedApply(tree = << ::((x @ _), (xs @ _)) >>, fun = << :: >>, ...)
        

        After a reset, the retypecheck gets to:

        normalTypedApply(tree = << scala.`package`.::((x @ _), (xs @ _)) >>, fun = << scala.`package`.:: >>, ...)
        

        The function is treated as a stable application, and the application is typed in expression mode, rather than pattern mode. Under this mode, the ident _ does not typecheck.

        I'm not sure yet what changed from 2.10.0 to 2.10.1 to lead us down this path.

        Show
        Jason Zaugg added a comment - Some breadcrumbs: def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = { val stableApplication = (fun.symbol ne null) && fun.symbol.isMethod && fun.symbol.isStable if (stableApplication && isPatternMode) { // treat stable function applications f() as expressions. typed1(tree, mode & ~PATTERNmode | EXPRmode, pt) def typedIdentOrWildcard(tree: Ident) = { val name = tree.name if (Statistics.canEnable) Statistics.incCounter(typedIdentCount) if ((name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode) || (name == tpnme.WILDCARD && (mode & TYPEmode) != 0)) tree setType makeFullyDefined(pt) else typedIdent(tree, name) } In the original type check, we get to: normalTypedApply(tree = << ::((x @ _), (xs @ _)) >>, fun = << :: >>, ...) After a reset, the retypecheck gets to: normalTypedApply(tree = << scala.`package`.::((x @ _), (xs @ _)) >>, fun = << scala.`package`.:: >>, ...) The function is treated as a stable application, and the application is typed in expression mode, rather than pattern mode. Under this mode, the ident _ does not typecheck. I'm not sure yet what changed from 2.10.0 to 2.10.1 to lead us down this path.
        Show
        Jason Zaugg added a comment - https://github.com/scala/scala/pull/2402

          People

          • Assignee:
            Jason Zaugg
            Reporter:
            Thomas Crockett
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development