diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2011-10-20 22:28:58 +0000 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2011-10-20 22:28:58 +0000 |
commit | 8704ed2fc92e3d82287317fe34126c5d4d84e10c (patch) | |
tree | 035a6d98a08e102ac6116e9048c36996d1af6a22 /src/compiler | |
parent | 98b904db879a0b987d6ae50e5d5d990285ed8c59 (diff) | |
download | scala-8704ed2fc92e3d82287317fe34126c5d4d84e10c.tar.gz scala-8704ed2fc92e3d82287317fe34126c5d4d84e10c.tar.bz2 scala-8704ed2fc92e3d82287317fe34126c5d4d84e10c.zip |
infer singleton when asking for it
a type var's constraint now also tracks whether the type var was
compared to a stable type
if it was, we probably shouldn't widen the type argument that's inferred
for this var, as the result will surely fail to type check
NOTE: must be enabled using -Xexperimental
review by extempore
Diffstat (limited to 'src/compiler')
4 files changed, 53 insertions, 31 deletions
diff --git a/src/compiler/scala/reflect/internal/Scopes.scala b/src/compiler/scala/reflect/internal/Scopes.scala index 4db2cbf0d6..3ea43c22f2 100644 --- a/src/compiler/scala/reflect/internal/Scopes.scala +++ b/src/compiler/scala/reflect/internal/Scopes.scala @@ -33,6 +33,10 @@ trait Scopes extends api.Scopes { self: SymbolTable => e } + object Scope { + def unapplySeq(decls: Scope): Some[Seq[Symbol]] = Some(decls.toList) + } + class Scope(initElems: ScopeEntry) extends Iterable[Symbol] { var elems: ScopeEntry = initElems diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 24b641ddb4..a0bd994a97 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -2338,6 +2338,20 @@ A type's typeSymbol should never be inspected directly. //private var tidCount = 0 //DEBUG + object HasTypeMember { + def apply(name: TypeName, tp: Type): Type = { + val bound = refinedType(List(WildcardType), NoSymbol) + val bsym = bound.typeSymbol.newAliasType(NoPosition, name) + bsym setInfo tp + bound.decls enter bsym + bound + } + def unapply(tp: Type): Option[(TypeName, Type)] = tp match { + case RefinedType(List(WildcardType), Scope(sym)) => Some((sym.name.toTypeName, sym.info)) + case _ => None + } + } + //@M // a TypeVar used to be a case class with only an origin and a constr // then, constr became mutable (to support UndoLog, I guess), @@ -2558,6 +2572,8 @@ A type's typeSymbol should never be inspected directly. // So the strategy used here is to test first the type, then the direct parents, and finally // to fall back on the individual base types. This warrants eventual re-examination. + // AM: I think we could use the `suspended` flag to avoid side-effecting during unification + if (suspended) // constraint accumulation is disabled checkSubtype(tp, origin) else if (constr.instValid) // type var is already set @@ -2603,11 +2619,7 @@ A type's typeSymbol should never be inspected directly. * (`T` corresponds to @param sym) */ def registerTypeSelection(sym: Symbol, tp: Type): Boolean = { - val bound = refinedType(List(WildcardType), NoSymbol) - val bsym = bound.typeSymbol.newAliasType(NoPosition, sym.name.toTypeName) - bsym setInfo tp - bound.decls enter bsym - registerBound(bound, false) + registerBound(HasTypeMember(sym.name.toTypeName, tp), false) } /** Can this variable be related in a constraint to type `tp`? @@ -3206,7 +3218,7 @@ A type's typeSymbol should never be inspected directly. /** A class expressing upper and lower bounds constraints of type variables, * as well as their instantiations. */ - class TypeConstraint(lo0: List[Type], hi0: List[Type], numlo0: Type, numhi0: Type) { + class TypeConstraint(lo0: List[Type], hi0: List[Type], numlo0: Type, numhi0: Type, avoidWidening0: Boolean = false) { def this(lo0: List[Type], hi0: List[Type]) = this(lo0, hi0, NoType, NoType) def this() = this(List(), List()) @@ -3214,9 +3226,11 @@ A type's typeSymbol should never be inspected directly. private var hibounds = hi0 private var numlo = numlo0 private var numhi = numhi0 + private var avoidWidening = avoidWidening0 def loBounds: List[Type] = if (numlo == NoType) lobounds else numlo :: lobounds def hiBounds: List[Type] = if (numhi == NoType) hibounds else numhi :: hibounds + def avoidWiden: Boolean = avoidWidening def addLoBound(tp: Type, isNumericBound: Boolean = false) { if (isNumericBound && isNumericValueType(tp)) { @@ -3228,7 +3242,16 @@ A type's typeSymbol should never be inspected directly. else lobounds ::= tp } + def checkWidening(tp: Type) { + if(tp.isStable) avoidWidening = true + else tp match { + case HasTypeMember(_, _) => avoidWidening = true + case _ => + } + } + def addHiBound(tp: Type, isNumericBound: Boolean = false) { + checkWidening(tp) if (isNumericBound && isNumericValueType(tp)) { if (numhi == NoType || isNumericSubType(tp, numhi)) numhi = tp @@ -3249,7 +3272,7 @@ A type's typeSymbol should never be inspected directly. def instValid = (inst ne null) && (inst ne NoType) def cloneInternal = { - val tc = new TypeConstraint(lobounds, hibounds, numlo, numhi) + val tc = new TypeConstraint(lobounds, hibounds, numlo, numhi, avoidWidening) tc.inst = inst tc } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 660999eb64..fedf0a9104 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -178,13 +178,8 @@ trait Implicits { private val hasMemberCache = perRunCaches.newMap[Name, Type]() def apply(name: Name): Type = hasMemberCache.getOrElseUpdate(name, memberWildcardType(name, WildcardType)) def unapply(pt: Type): Option[Name] = pt match { - case RefinedType(List(WildcardType), decls) => - decls.toList match { - case List(sym) if sym.tpe == WildcardType => Some(sym.name) - case _ => None - } - case _ => - None + case RefinedType(List(WildcardType), Scope(sym)) if sym.tpe == WildcardType => Some(sym.name) + case _ => None } } @@ -570,7 +565,7 @@ trait Implicits { // filter out failures from type inference, don't want to remove them from undetParams! // we must be conservative in leaving type params in undetparams // prototype == WildcardType: want to remove all inferred Nothings - val AdjustedTypeArgs(okParams, okArgs) = adjustTypeArgs(undetParams, targs) + val AdjustedTypeArgs(okParams, okArgs) = adjustTypeArgs(undetParams, tvars, targs) val subst: TreeTypeSubstituter = if (okParams.isEmpty) EmptyTreeTypeSubstituter else { diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index f2a0091ee1..f6fc6cedd2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -523,7 +523,7 @@ trait Infer { * @param pt ... * @return ... */ - private def exprTypeArgs(tparams: List[Symbol], restpe: Type, pt: Type, useWeaklyCompatible: Boolean = false): List[Type] = { + private def exprTypeArgs(tparams: List[Symbol], restpe: Type, pt: Type, useWeaklyCompatible: Boolean = false): (List[Type], List[TypeVar]) = { val tvars = tparams map freshVar val instResTp = restpe.instantiateTypeParams(tparams, tvars) if ( if (useWeaklyCompatible) isWeaklyCompatible(instResTp, pt) else isCompatible(instResTp, pt) ) { @@ -538,12 +538,12 @@ trait Infer { restpe } //println("try to solve "+tvars+" "+tparams) - solvedTypes(tvars, tparams, tparams map varianceInType(varianceType), - false, lubDepth(List(restpe, pt))) + (solvedTypes(tvars, tparams, tparams map varianceInType(varianceType), + false, lubDepth(List(restpe, pt))), tvars) } catch { - case ex: NoInstance => null + case ex: NoInstance => (null, null) } - } else null + } else (null, null) } /** Return inferred proto-type arguments of function, given @@ -639,11 +639,11 @@ trait Infer { * @return map from tparams to inferred arg, if inference was successful, tparams that map to None are considered left undetermined * type parameters that are inferred as `scala.Nothing` and that are not covariant in <code>restpe</code> are taken to be undetermined */ - def adjustTypeArgs(tparams: List[Symbol], targs: List[Type], restpe: Type = WildcardType): AdjustedTypeArgs.Result = { + def adjustTypeArgs(tparams: List[Symbol], tvars: List[TypeVar], targs: List[Type], restpe: Type = WildcardType): AdjustedTypeArgs.Result = { @inline def notCovariantIn(tparam: Symbol, restpe: Type) = (varianceInType(restpe)(tparam) & COVARIANT) == 0 // tparam occurred non-covariantly (in invariant or contravariant position) - (tparams, targs).zipped.map{ (tparam, targ) => + (tparams, tvars, targs).zipped.map{ (tparam, tvar, targ) => if (targ.typeSymbol == NothingClass && (restpe.isWildcard || notCovariantIn(tparam, restpe))) { tparam -> None @@ -651,7 +651,7 @@ trait Infer { tparam -> Some( if (targ.typeSymbol == RepeatedParamClass) targ.baseType(SeqClass) else if (targ.typeSymbol == JavaRepeatedParamClass) targ.baseType(ArrayClass) - else if (targ.typeSymbol.isModuleClass) targ // this infers Foo.type instead of "object Foo" (see also widenIfNecessary) + else if (targ.typeSymbol.isModuleClass || (opt.experimental && tvar.constr.avoidWiden)) targ // this infers Foo.type instead of "object Foo" (see also widenIfNecessary) else targ.widen ) } @@ -729,7 +729,7 @@ trait Infer { tvars, tparams, tparams map varianceInTypes(formals), false, lubDepth(formals) max lubDepth(argtpes) ) - val result = adjustTypeArgs(tparams, targs, restpe) + val result = adjustTypeArgs(tparams, tvars, targs, restpe) printInference( ptBlock("methTypeArgs result", @@ -861,7 +861,7 @@ trait Infer { try { val AdjustedTypeArgs.Undets(okparams, okargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt) // #2665: must use weak conformance, not regular one (follow the monomorphic case above) - (exprTypeArgs(leftUndet, restpe.instantiateTypeParams(okparams, okargs), pt, useWeaklyCompatible = true) ne null) && + (exprTypeArgs(leftUndet, restpe.instantiateTypeParams(okparams, okargs), pt, useWeaklyCompatible = true)._1 ne null) && isWithinBounds(NoPrefix, NoSymbol, okparams, okargs) } catch { case ex: NoInstance => false @@ -1176,10 +1176,10 @@ trait Infer { "lenientPt" -> lenientPt ) ) - var targs = exprTypeArgs(undetparams, tree.tpe, strictPt) - if ((targs eq null) || !(tree.tpe.subst(undetparams, targs) <:< strictPt)) { - targs = exprTypeArgs(undetparams, tree.tpe, lenientPt) - } + var targs = exprTypeArgs(undetparams, tree.tpe, strictPt)._1 + if ((targs eq null) || !(tree.tpe.subst(undetparams, targs) <:< strictPt)) + targs = exprTypeArgs(undetparams, tree.tpe, lenientPt)._1 + substExpr(tree, undetparams, targs, lenientPt) printInference("[inferArgumentInstance] finished, targs = " + targs) } @@ -1199,13 +1199,13 @@ trait Infer { "pt" -> pt ) ) - val targs = exprTypeArgs(tparams, treeTp, pt, useWeaklyCompatible) + val (targs, tvars) = exprTypeArgs(tparams, treeTp, pt, useWeaklyCompatible) if (keepNothings || (targs eq null)) { //@M: adjustTypeArgs fails if targs==null, neg/t0226 substExpr(tree, tparams, targs, pt) List() } else { - val AdjustedTypeArgs.Undets(okParams, okArgs, leftUndet) = adjustTypeArgs(tparams, targs) + val AdjustedTypeArgs.Undets(okParams, okArgs, leftUndet) = adjustTypeArgs(tparams, tvars, targs) printInference( ptBlock("inferExprInstance/AdjustedTypeArgs", "okParams" -> okParams, |