@@ -2390,13 +2390,19 @@ A type's typeSymbol should never be inspected directly.
23902390 new TypeVar (origin, constr, args, params)
23912391 }
23922392
2393- /** A class representing a type variable
2394- * Not used after phase `typer`.
2395- * A higher-kinded type variable has type arguments (a list of Type's) and type parameters (list of Symbols)
2396- * A TypeVar whose list of args is non-empty can only be instantiated by a higher-kinded type that can be applied to these args
2397- * a typevar is much like a typeref, except it has special logic for type equality/subtyping
2393+ /** A class representing a type variable: not used after phase `typer`.
2394+ *
2395+ * A higher-kinded TypeVar has params (Symbols) and typeArgs (Types).
2396+ * A TypeVar with nonEmpty typeArgs can only be instantiated by a higher-kinded
2397+ * type that can be applied to those args. A TypeVar is much like a TypeRef,
2398+ * except it has special logic for equality and subtyping.
23982399 */
2399- class TypeVar (val origin : Type , val constr0 : TypeConstraint , override val typeArgs : List [Type ], override val params : List [Symbol ]) extends Type {
2400+ class TypeVar (
2401+ val origin : Type ,
2402+ val constr0 : TypeConstraint ,
2403+ override val typeArgs : List [Type ],
2404+ override val params : List [Symbol ]
2405+ ) extends Type {
24002406 // params are needed to keep track of variance (see mapOverArgs in SubstMap)
24012407 assert(typeArgs.isEmpty || sameLength(typeArgs, params))
24022408 // var tid = { tidCount += 1; tidCount } //DEBUG
@@ -2409,14 +2415,16 @@ A type's typeSymbol should never be inspected directly.
24092415 val level = skolemizationLevel
24102416
24112417 /** Two occurrences of a higher-kinded typevar, e.g. `?CC[Int]` and `?CC[String]`, correspond to
2412- * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`
2413- * `constr` for `?CC` only tracks type constructors anyway, so when `?CC[Int] <:< List[Int]` and `?CC[String] <:< Iterable[String]`
2414- * `?CC's` hibounds contains List and Iterable
2418+ * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`.
2419+ *
2420+ * `constr` for `?CC` only tracks type constructors anyway,
2421+ * so when `?CC[Int] <:< List[Int]` and `?CC[String] <:< Iterable[String]`
2422+ * `?CC's` hibounds contains List and Iterable.
24152423 */
24162424 def applyArgs (newArgs : List [Type ]): TypeVar =
24172425 if (newArgs.isEmpty) this // SubstMap relies on this (though this check is redundant when called from appliedType...)
24182426 else TypeVar (origin, constr, newArgs, params) // @M TODO: interaction with undoLog??
2419- // newArgs.length may differ from args.length (could've been empty before)
2427+ // newArgs.length may differ from args.length (could've been empty before)
24202428 // example: when making new typevars, you start out with C[A], then you replace C by ?C, which should yield ?C[A], then A by ?A, ?C[?A]
24212429 // we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver)
24222430 // TypeVars get applied to different arguments over time (in asSeenFrom)
@@ -2427,15 +2435,16 @@ A type's typeSymbol should never be inspected directly.
24272435 // they share the same TypeConstraint instance
24282436
24292437 // <region name="constraint mutators + undoLog">
2430- // invariant: before mutating constr, save old state in undoLog (undoLog is used to reset constraints to avoid piling up unrelated ones)
2438+ // invariant: before mutating constr, save old state in undoLog
2439+ // (undoLog is used to reset constraints to avoid piling up unrelated ones)
24312440 def setInst (tp : Type ) {
24322441// assert(!(tp containsTp this), this)
24332442 undoLog record this
24342443 constr.inst = tp
24352444 }
24362445
24372446 def addLoBound (tp : Type , isNumericBound : Boolean = false ) {
2438- assert(tp != this ) // implies there is a cycle somewhere (?)
2447+ assert(tp != this , tp ) // implies there is a cycle somewhere (?)
24392448 // println("addLoBound: "+(safeToString, debugString(tp))) //DEBUG
24402449 undoLog record this
24412450 constr.addLoBound(tp, isNumericBound)
@@ -2504,27 +2513,38 @@ A type's typeSymbol should never be inspected directly.
25042513 * Checks subtyping of higher-order type vars, and uses variances as defined in the
25052514 * type parameter we're trying to infer (the result will be sanity-checked later).
25062515 */
2507- def unifyFull (tp : Type ) = sameLength(typeArgs, tp.typeArgs) && { // this is a higher-kinded type var with same arity as tp
2508- // side effect: adds the type constructor itself as a bound
2509- addBound(tp.typeConstructor)
2510- if (isLowerBound) isSubArgs(tp.typeArgs, typeArgs, params)
2511- else isSubArgs(typeArgs, tp.typeArgs, params)
2516+ def unifyFull (tpe : Type ) = {
2517+ // Since the alias/widen variations are often no-ops, this
2518+ // keenly collects them in a Set to avoid redundant tests.
2519+ Set (tpe, tpe.widen, tpe.dealias, tpe.widen.dealias) exists { tp =>
2520+ sameLength(typeArgs, tp.typeArgs) && {
2521+ // this is a higher-kinded type var with same arity as tp.
2522+ // side effect: adds the type constructor itself as a bound
2523+ addBound(tp.typeConstructor)
2524+ if (isLowerBound) isSubArgs(tp.typeArgs, typeArgs, params)
2525+ else isSubArgs(typeArgs, tp.typeArgs, params)
2526+ }
2527+ }
25122528 }
2529+
2530+ // There's a <:< test taking place right now, where tp is a concrete type and this is
2531+ // a typevar attempting to satisfy that test. If we determine that the subtype test is
2532+ // infeasible, we'll return false. Otherwise will retain all the constraints implied by
2533+ // this test, which will eventually be lub/glbed to instantiate the typevar. We must
2534+ // be able to find a type with the same number of typeargs among the base types of tp,
2535+ // or tp after dealiasing/widening.
25132536
25142537 /** TODO: need positive/negative test cases demonstrating this is correct. */
2515- def unifyParents =
2516- if (isLowerBound) tp.parents exists unifyFull
2517- else tp.parents forall unifyFull
2518-
2519- // TODO: fancier unification, maybe rewrite constraint as follows?
2520- // val sym = constr.hiBounds map {_.typeSymbol} find { _.typeParams.length == typeArgs.length}
2521- // this <: tp.baseType(sym)
2522- if (suspended) checkSubtype(tp, origin)
2523- else if (constr.instValid) checkSubtype(tp, constr.inst) // type var is already set
2524- else isRelatable(tp) && { // gradually let go of some type precision in hopes of finding a type that has the same shape as the type variable
2525- // okay, this just screams "CLEAN ME UP" -- I think we could use tp.widen instead of tp straight from the get-go in registerBound, since we don't infer singleton types anyway (but maybe that'll change?)
2526- unifySimple || unifyFull(tp) || unifyFull(tp.dealias) || unifyFull(tp.widen) || unifyFull(tp.widen.dealias) || unifyParents
2527- }
2538+ def unifyBaseTypes =
2539+ if (isLowerBound) tp.baseTypeSeq exists unifyFull
2540+ else tp.baseTypeSeq.toList forall unifyFull
2541+
2542+ if (suspended)
2543+ checkSubtype(tp, origin)
2544+ else if (constr.instValid) // type var is already set
2545+ checkSubtype(tp, constr.inst)
2546+ else // relax precision seeking a type whose shape matches the typevar
2547+ isRelatable(tp) && (unifySimple || unifyFull(tp) || unifyBaseTypes)
25282548 }
25292549
25302550 def registerTypeEquality (tp : Type , typeVarLHS : Boolean ): Boolean = {
0 commit comments