Uploaded image for project: 'Scala Programming Language'
  1. Scala Programming Language
  2. SI-5829

instantiate gets confused if tvar is inferred to be a refinement type whose parent is a refinement type

    Details

      Description

      trait Universe {
        type Tree
       
        type SymTree <: Tree
        type NameTree <: Tree
        type RefTree <: SymTree with NameTree
       
        type Ident <: RefTree
        type Select <: RefTree
      }
       
      object Test extends App {
        val universe: Universe = null
        import universe._
        def select: Select = ???
        def ident: Ident = ???
        List(select, ident)
      }
      

      C:\Projects\KeplerUnderRefactoring\sandbox @ topic/reflection>myke compile Test.scala
      Test.scala:17: error: no type parameters for method apply: (xs: A*)List[A] in object List exist so that it can be applied to arguments (Test.universe.Select, Test.universe.Ident)
       --- because ---
      undetermined type
        List(select, ident)
        ^
      

        Attachments

          Activity

          Hide
          burmako Eugene Burmako added a comment - - edited

          As displayed in the debugger, `tvar` is a refinement type:

          Test.universe.RefTree with Test.universe.SymTree with Test.universe.NameTree
          

          Mapping over this type goes into:

          case rtp @ RefinedType(parents, decls) =>
            val parents1 = parents mapConserve this
            val decls1 = mapOver(decls)
            //if ((parents1 eq parents) && (decls1 eq decls)) tp
            //else refinementOfClass(tp.typeSymbol, parents1, decls1)
            copyRefinedType(rtp, parents1, decls1)
          

          `parents` for this refinement type are:

          Test.universe.RefTree // TypeRef(pre = Test.universe.type, sym = type RefTree /* AbstractTypeSymbol */, args = Nil)
          Test.universe.SymTree with Test.universe.NameTree // RefinementTypeRef (pre = NoType, sym = Universe /* RefinementClassSymbol */, args = Nil)
          

          `tvars map instantiate` in Infer.scala calls `instantiate`:

          object instantiate extends TypeMap {
            private var excludedVars = immutable.Set[TypeVar]()
            def apply(tp: Type): Type = tp match {
              case WildcardType | BoundedWildcardType(_) | NoType =>
                throw new NoInstance("undetermined type")
              case tv @ TypeVar(origin, constr) if !tv.untouchable =>
                if (constr.inst == NoType) {
                  throw new DeferredNoInstance(() =>
                    "no unique instantiation of type variable " + origin + " could be found")
                } else if (excludedVars(tv)) {
                  throw new NoInstance("cyclic instantiation")
                } else {
                  excludedVars += tv
                  val res = apply(constr.inst)
                  excludedVars -= tv
                  res
                }
              case _ =>
                mapOver(tp)
            }
          }
          

          When navigating the second parent, `instantiate` sees `NoType` in `pre` and bails with NoInstance.

          Show
          burmako Eugene Burmako added a comment - - edited As displayed in the debugger, `tvar` is a refinement type: Test.universe.RefTree with Test.universe.SymTree with Test.universe.NameTree Mapping over this type goes into: case rtp @ RefinedType(parents, decls) => val parents1 = parents mapConserve this val decls1 = mapOver(decls) //if ((parents1 eq parents) && (decls1 eq decls)) tp //else refinementOfClass(tp.typeSymbol, parents1, decls1) copyRefinedType(rtp, parents1, decls1) `parents` for this refinement type are: Test.universe.RefTree // TypeRef(pre = Test.universe.type, sym = type RefTree /* AbstractTypeSymbol */, args = Nil) Test.universe.SymTree with Test.universe.NameTree // RefinementTypeRef (pre = NoType, sym = Universe /* RefinementClassSymbol */, args = Nil) `tvars map instantiate` in Infer.scala calls `instantiate`: object instantiate extends TypeMap { private var excludedVars = immutable.Set[TypeVar]() def apply(tp: Type): Type = tp match { case WildcardType | BoundedWildcardType(_) | NoType => throw new NoInstance("undetermined type") case tv @ TypeVar(origin, constr) if !tv.untouchable => if (constr.inst == NoType) { throw new DeferredNoInstance(() => "no unique instantiation of type variable " + origin + " could be found") } else if (excludedVars(tv)) { throw new NoInstance("cyclic instantiation") } else { excludedVars += tv val res = apply(constr.inst) excludedVars -= tv res } case _ => mapOver(tp) } } When navigating the second parent, `instantiate` sees `NoType` in `pre` and bails with NoInstance.
          Hide
          burmako Eugene Burmako added a comment - - edited

          Also it's unclear why the lub is calculated as:

          List(Test.universe.RefTree, Test.universe.SymTree with Test.universe.NameTree)
          

          But not just to:

          List(Test.universe.RefTree)
          

          (the latter is how things work with concrete types)

          Show
          burmako Eugene Burmako added a comment - - edited Also it's unclear why the lub is calculated as: List(Test.universe.RefTree, Test.universe.SymTree with Test.universe.NameTree) But not just to: List(Test.universe.RefTree) (the latter is how things work with concrete types)
          Hide
          moors Adriaan Moors added a comment -

          it looks like refinement typerefs lost their prefix in the Great Types Refactor of https://github.com/scala/scala/commit/5f5029d2ac and https://github.com/scala/scala/commit/f7535f7290 (specifically: https://github.com/scala/scala/commit/f7535f7290#L2R2260)

          This issue is an example of where the prefix is something interesting, and not just good old `NoType` (as assumed by https://github.com/scala/scala/commit/f7535f7290#L2R1880). `NoType` indicates type inference failure. I could imagine it being `NoPrefix` once in a while, but never `NoType`.

          fix in https://github.com/adriaanm/scala/tree/ticket/5829 pending it passing the test suite

          Show
          moors Adriaan Moors added a comment - it looks like refinement typerefs lost their prefix in the Great Types Refactor of https://github.com/scala/scala/commit/5f5029d2ac and https://github.com/scala/scala/commit/f7535f7290 (specifically: https://github.com/scala/scala/commit/f7535f7290#L2R2260 ) This issue is an example of where the prefix is something interesting, and not just good old `NoType` (as assumed by https://github.com/scala/scala/commit/f7535f7290#L2R1880 ). `NoType` indicates type inference failure. I could imagine it being `NoPrefix` once in a while, but never `NoType`. fix in https://github.com/adriaanm/scala/tree/ticket/5829 pending it passing the test suite
          Show
          burmako Eugene Burmako added a comment - Fixed in https://github.com/scala/scala/commit/6bb5975289c5b11cb8c88dd4629286956b5d3d27
          Hide
          extempore Paul Phillips added a comment -

          Hey, I never saw this ticket.

          For the record, and maybe you know this because you say "prefix is something interesting" which sounds like a reference to the comment, but I did this because it was documented by martin that "refinements always have non-interesting prefixes."

          https://github.com/scala/scala/commit/7ebc41cda2#L0R1453

          Show
          extempore Paul Phillips added a comment - Hey, I never saw this ticket. For the record, and maybe you know this because you say "prefix is something interesting" which sounds like a reference to the comment, but I did this because it was documented by martin that "refinements always have non-interesting prefixes." https://github.com/scala/scala/commit/7ebc41cda2#L0R1453

            People

            • Assignee:
              burmako Eugene Burmako
              Reporter:
              burmako Eugene Burmako
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: