SI-7289 Less strict type application for TypeVar. #2354

Merged
merged 1 commit into from Apr 9, 2013
Commits on Apr 9, 2013
  1. @adriaanm

    SI-7289 Less strict type application for TypeVar.

    adriaanm committed Mar 23, 2013
    When a type constructor variable is applied to the wrong number of arguments,
    return a new type variable whose instance is `ErrorType`.
    
    Dissection of the reported test case by @retronym:
    
    Define the first implicit:
    
        scala> trait Schtroumpf[T]
        defined trait Schtroumpf
    
        scala> implicit def schtroumpf[T, U <: Coll[T], Coll[X] <: Traversable[X]]
             |     (implicit minorSchtroumpf: Schtroumpf[T]): Schtroumpf[U] = ???
        schtroumpf: [T, U <: Coll[T], Coll[X] <: Traversable[X]](implicit minorSchtroumpf: Schtroumpf[T])Schtroumpf[U]
    
    Call it explicitly => kind error during type inference reported.
    
        scala> schtroumpf(null): Schtroumpf[Int]
        <console>:10: error: inferred kinds of the type arguments (Nothing,Int,Int) do not conform to the expected kinds of the type parameters (type T,type U,type Coll).
        Int's type parameters do not match type Coll's expected parameters:
        class Int has no type parameters, but type Coll has one
                      schtroumpf(null): Schtroumpf[Int]
                      ^
        <console>:10: error: type mismatch;
         found   : Schtroumpf[U]
         required: Schtroumpf[Int]
                      schtroumpf(null): Schtroumpf[Int]
                                ^
    
    Add another implicit, and let implicit search weigh them up.
    
        scala> implicitly[Schtroumpf[Int]]
        <console>:10: error: diverging implicit expansion for type Schtroumpf[Int]
        starting with method schtroumpf
                      implicitly[Schtroumpf[Int]]
                                ^
    
        scala> implicit val qoo = new Schtroumpf[Int]{}
        qoo: Schtroumpf[Int] = $anon$1@c1b9b03
    
        scala> implicitly[Schtroumpf[Int]]
        <crash>
    
    Implicit search compares the two in-scope implicits in `isStrictlyMoreSpecific`,
    which constructs an existential type:
    
       type ET = Schtroumpf[U] forSome { type T; type U <: Coll[T]; type Coll[_] <: Traversable[_] }
    
    A subsequent subtype check `ET <:< Schtroumpf[Int]` gets to `withTypeVars`, which
    replaces the quantified types with type variables, checks conformance of that
    substitued underlying type against `Schtroumpf[Int]`, and then tries to solve
    the collected type constraints. The type var trace looks like:
    
        [    create] ?T                       ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] )
        [    create] ?U                       ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] )
        [    create] ?Coll                    ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] )
        [   setInst] Nothing                  ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], T=Nothing )
        [   setInst] scala.collection.immutable.Nil.type( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], U=scala.collection.immutable.Nil.type )
        [   setInst] =?scala.collection.immutable.Nil.type( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], Coll==?scala.collection.immutable.Nil.type )
        [    create] ?T                       ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] )
        [   setInst] Int                      ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], T=Int )
        [    create] ?T                       ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] )
        [    create] ?U                       ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] )
        [    create] ?Coll                    ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]] )
        [   setInst] Nothing                  ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], T=Nothing )
        [   setInst] Int                      ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], U=Int )
        [   setInst] =?Int                    ( In Test#schtroumpf[T,U <: Coll[T],Coll[_] <: Traversable[_]], Coll==?Int )
    
    The problematic part is when `?Int` (the type var originated from `U`) is registered
    as a lower bound for `Coll`. That happens in `solveOne`:
    
        for (tparam2 <- tparams)
          tparam2.info.bounds.hi.dealias match {
            case TypeRef(_, `tparam`, _) =>
              log(s"$tvar addLoBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)")
              tvar addLoBound tparam2.tpeHK.instantiateTypeParams(tparams, tvars)
            case _ =>
          }