summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/symtab/Types.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/symtab/Types.scala')
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala121
1 files changed, 69 insertions, 52 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 676f19205a..6145c4a0d7 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -88,7 +88,7 @@ trait Types {
/** Decrement depth unless it is a don't care */
private final def decr(depth: Int) = if (depth == AnyDepth) AnyDepth else depth - 1
- private final val printLubs = false //@MDEBUG
+ private final val printLubs = false
/** The current skolemization level, needed for the algorithms
* in isSameType, isSubType that do constraint solving under a prefix
@@ -391,8 +391,18 @@ trait Types {
*/
def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = this.subst(formals, actuals)
+ /** If this type is an existential, turn all existentially bound variables to type skolems.
+ * @param owner The owner of the created type skolems
+ * @param origin The tree whose type was an existential for which the skolem was created.
+ */
def skolemizeExistential(owner: Symbol, origin: AnyRef): Type = this
+
+ /** A simple version of skolemizeExistential for situations where
+ * owner or unpack location do not matter (typically used in subtype tests)
+ */
+ def skolemizeExistential: Type = skolemizeExistential(NoSymbol, null)
+
/** Reduce to beta eta-long normal form. Expands type aliases and converts higher-kinded TypeRef's to PolyTypes. @M */
def normalize = this // @MAT
@@ -1590,12 +1600,11 @@ A type's typeSymbol should never be inspected directly.
override def typeConstructor = rawTypeRef(pre, sym, List())
- // (args.isEmpty && !typeParamsDirect.isEmpty) && !isRawType(this)
- // check for isRawType: otherwise raw types are considered higher-kinded types during subtyping:
- override def isHigherKinded
- = (args.isEmpty && !typeParamsDirect.isEmpty) && (settings.YhigherKindedRaw.value || !isRaw(sym, args))
- // (args.isEmpty && !typeParamsDirect.isEmpty) && (phase.erasedTypes || !sym.hasFlag(JAVA))
-
+ // a reference (in a Scala program) to a type that has type parameters, but where the reference does not include type arguments
+ // note that it doesn't matter whether the symbol refers to a java or scala symbol,
+ // it does matter whether it occurs in java or scala code
+ // typerefs w/o type params that occur in java signatures/code are considered raw types, and are represented as existential types
+ override def isHigherKinded = (args.isEmpty && !typeParamsDirect.isEmpty)
override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type =
if (isHigherKinded) {
@@ -1952,13 +1961,12 @@ A type's typeSymbol should never be inspected directly.
def withTypeVars(op: Type => Boolean): Boolean = withTypeVars(op, AnyDepth)
def withTypeVars(op: Type => Boolean, depth: Int): Boolean = {
- val tvars = quantified map (tparam => TypeVar(tparam.tpe, new TypeConstraint)) // @M TODO
-//@M should probably change to handle HK type infer properly:
-// val tvars = quantified map (tparam => TypeVar(tparam))
- val underlying1 = underlying.instantiateTypeParams(quantified, tvars)
+ val quantifiedFresh = cloneSymbols(quantified)
+ val tvars = quantifiedFresh map (tparam => TypeVar(tparam))
+ val underlying1 = underlying.instantiateTypeParams(quantified, tvars) // fuse subst quantified -> quantifiedFresh -> tvars
op(underlying1) && {
- solve(tvars, quantified, quantified map (x => 0), false, depth) &&
- isWithinBounds(NoPrefix, NoSymbol, quantified, tvars map (_.constr.inst))
+ solve(tvars, quantifiedFresh, quantifiedFresh map (x => 0), false, depth) &&
+ isWithinBounds(NoPrefix, NoSymbol, quantifiedFresh, tvars map (_.constr.inst))
}
}
}
@@ -2010,7 +2018,7 @@ A type's typeSymbol should never be inspected directly.
* Not used after phase `typer'.
* A higher-kinded type variable has type arguments (a list of Type's) and type paramers (list of Symbols)
* 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
- * NOTE:
+ * a typevar is much like a typeref, except it has special logic for type equality/subtyping
*/
class TypeVar(val origin: Type, val constr0: TypeConstraint, override val typeArgs: List[Type], override val params: List[Symbol]) extends Type {
// params are needed to keep track of variance (see mapOverArgs in SubstMap)
@@ -2021,7 +2029,7 @@ A type's typeSymbol should never be inspected directly.
var constr = constr0
def instValid = constr.instValid
- /** The variable's skolemizatuon level */
+ /** The variable's skolemization level */
val level = skolemizationLevel
/**
@@ -2034,14 +2042,14 @@ A type's typeSymbol should never be inspected directly.
if(newArgs.isEmpty) this // SubstMap relies on this (though this check is redundant when called from appliedType...)
else TypeVar(origin, constr, newArgs, params) // @M TODO: interaction with undoLog??
// newArgs.length may differ from args.length (could've been empty before)
- // OBSOLETE BEHAVIOUR: imperatively update args to new args
- // this initialises a TypeVar's arguments to the arguments of the type
// 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]
- // thus, we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver)
- // OBSOLETE BECAUSE: can't update imperatively because TypeVars do get applied to different arguments over type (in asSeenFrom) -- see pos/tcpoly_infer_implicit_tuplewrapper.scala
- // CONSEQUENCE: make new TypeVar's for every application of a TV to args,
- // inference may generate several TypeVar's for a single type parameter that must be inferred,
- // one of them is in the set of tvars that need to be solved, and they all share the same constr instance
+ // we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver)
+ // TypeVars get applied to different arguments over time (in asSeenFrom)
+ // -- see pos/tcpoly_infer_implicit_tuplewrapper.scala
+ // thus: make new TypeVar's for every application of a TV to args,
+ // inference may generate several TypeVar's for a single type parameter that must be inferred,
+ // only one of them is in the set of tvars that need to be solved, but
+ // they share the same TypeConstraint instance
def setInst(tp: Type) {
@@ -2049,17 +2057,17 @@ A type's typeSymbol should never be inspected directly.
constr.inst = tp
}
- /** Can this variable be related in a constraint to type `tp'?
- * This is not the case if `tp' contains type skolems whose
- * skolemization level is higher than the level of this variable.
- */
- def isRelatable(tp: Type): Boolean =
- !tp.exists { t =>
- t.typeSymbol match {
- case ts: TypeSkolem => ts.level > level
- case _ => false
- }
- }
+ def addLoBound(tp: Type, numBound: Boolean = false) {
+ assert(tp != this) // implies there is a cycle somewhere (?)
+ //println("addLoBound: "+(safeToString, debugString(tp))) //DEBUG
+ constr.addLoBound(tp, numBound)
+ }
+
+ def addHiBound(tp: Type, numBound: Boolean = false) {
+ // assert(tp != this)
+ //println("addHiBound: "+(safeToString, debugString(tp))) //DEBUG
+ constr.addHiBound(tp, numBound)
+ }
/** Called from isSubtype0 when a TypeVar is involved in a subtyping check.
* if isLowerBound is true,
@@ -2084,8 +2092,8 @@ A type's typeSymbol should never be inspected directly.
else tp2 <:< tp1
def addBound(tp: Type) = {
- if (isLowerBound) constr.addLoBound(tp, numBound)
- else constr.addHiBound(tp, numBound)
+ if (isLowerBound) addLoBound(tp, numBound)
+ else addHiBound(tp, numBound)
// println("addedBound: "+(this, tp)) // @MDEBUG
}
@@ -2127,6 +2135,18 @@ A type's typeSymbol should never be inspected directly.
}
}
+ /** Can this variable be related in a constraint to type `tp'?
+ * This is not the case if `tp' contains type skolems whose
+ * skolemization level is higher than the level of this variable.
+ */
+ def isRelatable(tp: Type): Boolean =
+ !tp.exists { t =>
+ t.typeSymbol match {
+ case ts: TypeSkolem => ts.level > level
+ case _ => false
+ }
+ }
+
override val isHigherKinded = typeArgs.isEmpty && !params.isEmpty
override def normalize: Type =
@@ -4065,7 +4085,7 @@ A type's typeSymbol should never be inspected directly.
case ExistentialType(_, _) =>
try {
skolemizationLevel += 1
- tp1.skolemizeExistential(NoSymbol, null) <:< tp2
+ tp1.skolemizeExistential <:< tp2
} finally {
skolemizationLevel -= 1
}
@@ -4282,14 +4302,13 @@ A type's typeSymbol should never be inspected directly.
val up = if (variance != CONTRAVARIANT) upper else !upper
tvar.constr.inst = null
val bound: Type = if (up) tparam.info.bounds.hi else tparam.info.bounds.lo
- //Console.println("solveOne0 "+tvar+" "+config+" "+bound);//DEBUG
+ //Console.println("solveOne0(tv, tp, v, b)="+(tvar, tparam, variance, bound))
var cyclic = bound contains tparam
for ((tvar2, (tparam2, variance2)) <- config) {
- // Console.println("solveOne0(tp,up,lo,hi,lo=tp,hi=tp)="+(tparam.tpe, up, tparam2.info.bounds.lo, tparam2.info.bounds.hi, (tparam2.info.bounds.lo =:= tparam.tpe), (tparam2.info.bounds.hi =:= tparam.tpe))) //DEBUG
if (tparam2 != tparam &&
((bound contains tparam2) ||
- up && (tparam2.info.bounds.lo =:= tparam.tpe) || //@M TODO: should probably be .tpeHK
- !up && (tparam2.info.bounds.hi =:= tparam.tpe))) { //@M TODO: should probably be .tpeHK
+ up && (tparam2.info.bounds.lo =:= tparam.tpe) ||
+ !up && (tparam2.info.bounds.hi =:= tparam.tpe))) {
if (tvar2.constr.inst eq null) cyclic = true
solveOne(tvar2, tparam2, variance2)
}
@@ -4297,31 +4316,29 @@ A type's typeSymbol should never be inspected directly.
if (!cyclic) {
if (up) {
if (bound.typeSymbol != AnyClass)
- tvar.constr addHiBound bound.instantiateTypeParams(tparams, tvars)
+ tvar addHiBound bound.instantiateTypeParams(tparams, tvars)
for (tparam2 <- tparams)
- if (tparam2.info.bounds.lo =:= tparam.tpe) //@M TODO: should probably be .tpeHK
- tvar.constr addHiBound tparam2.tpe.instantiateTypeParams(tparams, tvars)
+ if (tparam2.info.bounds.lo =:= tparam.tpe) // declaration tp2 :> tparam implies ?tparam <: tp2
+ tvar addHiBound tparam2.tpe.instantiateTypeParams(tparams, tvars)
} else {
- if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam)
- tvar.constr addLoBound bound.instantiateTypeParams(tparams, tvars)
+ if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam) {
+ tvar addLoBound bound.instantiateTypeParams(tparams, tvars)
+ }
for (tparam2 <- tparams)
- if (tparam2.info.bounds.hi =:= tparam.tpe) //@M TODO: should probably be .tpeHK
- tvar.constr addLoBound tparam2.tpe.instantiateTypeParams(tparams, tvars)
+ if (tparam2.info.bounds.hi =:= tparam.tpe)
+ tvar addLoBound tparam2.tpe.instantiateTypeParams(tparams, tvars)
}
}
tvar.constr.inst = NoType // necessary because hibounds/lobounds may contain tvar
- // println("solveOne(useGlb, glb, lub): "+ (up, //@MDEBUG
- // if (depth != AnyDepth) glb(tvar.constr.hiBounds, depth) else glb(tvar.constr.hiBounds),
- // if (depth != AnyDepth) lub(tvar.constr.loBounds, depth) else lub(tvar.constr.loBounds)))
-
tvar setInst (
if (up) {
if (depth != AnyDepth) glb(tvar.constr.hiBounds, depth) else glb(tvar.constr.hiBounds)
} else {
if (depth != AnyDepth) lub(tvar.constr.loBounds, depth) else lub(tvar.constr.loBounds)
})
- // Console.println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))+" = "+tvar.constr.inst)//@MDEBUG
+
+ //Console.println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))+" = "+tvar.constr.inst)//@MDEBUG
}
}