diff options
author | Martin Odersky <odersky@gmail.com> | 2014-02-03 22:40:54 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-02-03 22:41:03 +0100 |
commit | 4e34962fba727975c071d6288913d89b4692a08f (patch) | |
tree | e3ffccfe4f3c047149b32da1635ae749f8eecd4c /src | |
parent | 2a760aa7cee00829fe7b1649cad1efa5ddf8e259 (diff) | |
download | dotty-4e34962fba727975c071d6288913d89b4692a08f.tar.gz dotty-4e34962fba727975c071d6288913d89b4692a08f.tar.bz2 dotty-4e34962fba727975c071d6288913d89b4692a08f.zip |
Commenting out unused alternative isSubType implementation.
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 564 |
1 files changed, 283 insertions, 281 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 9e6982847..46caf3116 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -264,287 +264,6 @@ class TypeComparer(initctx: Context) extends DotClass { } } -/* Alternative implementation of isSubType, currently put on hold. Did not work - * out. Keep around for a while longer in case we want to mine it for ideas. - */ - - def compare(tp1: Type, tp2: Type): Boolean = ctx.debugTraceIndented(s"$tp1 <:< $tp2") { - tp2 match { - case tp2: ProtoType => - isMatchedByProto(tp2, tp1) - case tp2: TypeVar => - isSubType(tp1, tp2.underlying) - case tp2: WildcardType => - def compareWildcard = tp2.optBounds match { - case TypeBounds(_, hi2) => isSubType(tp1, hi2) - case NoType => true - } - compareWildcard - case tp2: AnnotatedType => - isSubType(tp1, tp2.tpe) // todo: refine? - case ErrorType => - true - case AndType(left2, right2) => - isSubType(tp1, left2) && isSubType(tp1, right2) - case _ => - compare1(tp1, tp2) - } - } - - def compare1(tp1: Type, tp2: Type): Boolean = { - tp1 match { - case tref1: TypeRef => - val sym1 = tref1.symbol - tref1.info match { - case TypeBounds(lo1, hi1) => - if (lo1 eq hi1) return compare(hi1, tp2) - else if (sym1 is GADTFlexType) - return isSubType(hi1, tp2) || - trySetType(tref1, TypeBounds(lo1, hi1 & tp2)) - case _ => - if ((sym1 eq NothingClass) && tp2.isInstanceOf[ValueType]) return true - if ((sym1 eq NullClass) && tp2.dealias.typeSymbol.isNullableClass) return true - } - case param1: PolyParam if isConstrained(param1) => - def comparePoly = ( - param1 == tp2 - || isSubTypeWhenFrozen(bounds(param1).hi, tp2) - || { if ((tp2 isRef defn.NothingClass) && ctx.typerState.isGlobalCommittable) - ctx.log(s"!!! instantiating to Nothing: $tp1") - addConstraint(param1, tp2, fromBelow = false) - } - ) - return comparePoly - case tp1 @ ThisType(cls) if cls is ModuleClass => - tp2 match { - case tp2: TermRef => - return tp2.symbol.moduleClass == cls && cls.owner.thisType <:< tp2.prefix - case _ => - } - case tp1: TypeVar => - return compare(tp1.underlying, tp2) - case tp1: WildcardType => - def compareWildcard = tp1.optBounds match { - case TypeBounds(lo1, _) => isSubType(lo1, tp2) // todo: use short-circuiting to current method more often? - case NoType => true - } - return compareWildcard - case tp1: AnnotatedType => - return isSubType(tp1.tpe, tp2) - case ErrorType => - return true - case OrType(left1, right1) => - return isSubType(left1, tp2) && isSubType(right1, tp2) - case _ => - } - rightIsSuper(tp1, tp2) - } - - def rightIsSuper(tp1: Type, tp2: Type): Boolean = tp2 match { - case tp2: NamedType => - def compareNamed: Boolean = { - val sym2 = tp2.symbol - val pre2 = tp2.prefix - tp1 match { - case tp1: NamedType => - val sym1 = tp1.symbol - val pre1 = tp1.prefix - if (sym1 == sym2) { - if ( ctx.erasedTypes - || sym1.isStaticOwner - || isSubType(pre1, pre2) - || pre1.isInstanceOf[ThisType] && pre2.isInstanceOf[ThisType]) return true - } else if (tp1.name == tp2.name && isSubType(pre1, pre2)) return true - case _ => - } - if (sym2.isClass) { - val base = tp1.baseType(sym2) - if (base.exists && (base ne tp1)) isSubType(base, tp2) - else - (sym2 == defn.SingletonClass) && tp1.isStable || - (defn.hkTraits contains sym2) && isSubTypeHK(tp1.widen, tp2) || - leftIsSub2(tp1, tp2) - } - else tp2.info match { - case TypeBounds(lo2, hi2) => - if (lo2 eq hi2) - isSubType(tp1.dealias, hi2.dealias) - else if (sym2 is GADTFlexType) - isSubType(tp1, lo2) || trySetType(tp2, TypeBounds(lo2 | tp1, hi2)) - else { - (frozenConstraint || !isCappable(tp1)) && isSubType(tp1, lo2) || - leftIsSub(tp1, tp2) - } - case _ => - leftIsSub(tp1, tp2) - } - } - compareNamed - - case tp2 @ RefinedType(parent2, name2) => - def matchRefinements(tp1: Type, tp2: Type, seen: Set[Name]): Type = tp1 match { - case tp1 @ RefinedType(parent1, name1) if !(seen contains name1) => - tp2 match { - case tp2 @ RefinedType(parent2, name2) if nameMatches(name1, name2, tp1, tp2) => - if (isSubType(tp1.refinedInfo, tp2.refinedInfo)) - matchRefinements(parent1, parent2, seen + name1) - else NoType - case _ => tp2 - } - case _ => tp2 - } - def compareRefined: Boolean = tp1.widen match { - case tp1 @ RefinedType(parent1, name1) if nameMatches(name1, name2, tp1, tp2) => - // optimized case; all info on tp1.name2 is in refinement tp1.refinedInfo. - isSubType(tp1.refinedInfo, tp2.refinedInfo) && { - val ancestor2 = matchRefinements(parent1, parent2, Set.empty + name1) - ancestor2.exists && isSubType(tp1, ancestor2) - } - case _ => - def hasMatchingMember(name: Name): Boolean = traceIndented(s"hasMatchingMember($name) ${tp1.member(name)}") ( - tp1.member(name).hasAltWith(alt => isSubType(alt.info, tp2.refinedInfo)) - || - { // special case for situations like: - // foo <: C { type T = foo.T } - tp2.refinedInfo match { - case TypeBounds(lo, hi) if lo eq hi => - val ref = tp1 select name - isSubType(ref, lo) && isSubType(hi, ref) - case _ => false - } - } - || - name.isHkParamName && { - val idx = name.hkParamIndex - val tparams = tp1.typeParams - idx < tparams.length && hasMatchingMember(tparams(idx).name) - } - ) - isSubType(tp1, parent2) && ( - name2 == nme.WILDCARD - || hasMatchingMember(name2) - || leftIsSub2(tp1, tp2)) - } - compareRefined - - case param2: PolyParam => - def comparePoly = - param2 == tp1 || { - if (isConstrained(param2)) - isSubTypeWhenFrozen(tp1, bounds(param2).lo) || - addConstraint(param2, tp1.widen, fromBelow = true) - else - (ctx.mode is Mode.TypevarsMissContext) || - isNonBottomSubType(tp1, bounds(param2).lo) || - leftIsSub(tp1, tp2) - } - comparePoly - - case ThisType(cls) if (cls is ModuleClass) => - def compareThis: Boolean = { - tp1 match { - case tp1: TermRef => - if (tp1.symbol.moduleClass == cls) - return tp1.prefix <:< cls.owner.thisType - case _ => - } - leftIsSub(tp1, tp2) - } - compareThis - - case tp2: BoundType => - tp1 == tp2 || leftIsSub(tp1, tp2) - case OrType(tp21, tp22) => - isSubType(tp1, tp21) || isSubType(tp1, tp22) - - case tp2 @ MethodType(_, formals2) => - def compareMethod = tp1 match { - case tp1 @ MethodType(_, formals1) => - tp1.signature == tp2.signature && - (if (Config.newMatch) subsumeParams(formals1, formals2, tp1.isJava, tp2.isJava) - else matchingParams(formals1, formals2, tp1.isJava, tp2.isJava)) && - tp1.isImplicit == tp2.isImplicit && // needed? - isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) - case _ => - false - } - compareMethod - - case tp2: PolyType => - def comparePoly = tp1 match { - case tp1: PolyType => - (tp1.signature sameParams tp2.signature) && - matchingTypeParams(tp1, tp2) && - isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) - case _ => - false - } - comparePoly - - case tp2 @ ExprType(restpe2) => - def compareExpr = tp1 match { - // We allow ()T to be a subtype of => T. - // We need some subtype relationship between them so that e.g. - // def toString and def toString() don't clash when seen - // as members of the same type. And it seems most logical to take - // ()T <:< => T, since everything one can do with a => T one can - // also do with a ()T by automatic () insertion. - case tp1 @ MethodType(Nil, _) => isSubType(tp1.resultType, restpe2) - case _ => isSubType(tp1.widenExpr, restpe2) - } - compareExpr - - case tp2 @ TypeBounds(lo2, hi2) => - def compareBounds = tp1 match { - case tp1 @ TypeBounds(lo1, hi1) => - val v = tp1.variance + tp2.variance - ((v > 0) || (lo2 isRef NothingClass) || isSubType(lo2, lo1)) && - ((v < 0) || (hi2 isRef AnyClass) || isSubType(hi1, hi2)) - case tp1: ClassInfo => - val tt = tp1.typeRef - isSubType(lo2, tt) && isSubType(tt, hi2) - case _ => - false - } - compareBounds - - case ClassInfo(pre2, cls2, _, _, _) => - def compareClassInfo = tp1 match { - case ClassInfo(pre1, cls1, _, _, _) => - (cls1 eq cls2) && isSubType(pre2, pre1) - case _ => - false - } - compareClassInfo - - case _ => - leftIsSub(tp1, tp2) - } - - def leftIsSub(tp1: Type, tp2: Type): Boolean = tp1 match { - case tp1: TypeRef => - tp1.info match { - case TypeBounds(lo1, hi1) => isSubType(hi1, tp2) - case _ => false - } - case tp1: SingletonType => - isSubType(tp1.underlying.widenExpr, tp2) - case tp1: RefinedType => - isSubType(tp1.parent, tp2) - case _ => - leftIsSub2(tp1, tp2) - } - - def leftIsSub2(tp1: Type, tp2: Type): Boolean = tp1 match { - case param1: PolyParam => - assert(!isConstrained(param1)) - (ctx.mode is Mode.TypevarsMissContext) || isSubType(bounds(param1).hi, tp2) - case AndType(tp11, tp12) => - isSubType(tp11, tp2) || isSubType(tp12, tp2) - case _ => - false - } - def firstTry(tp1: Type, tp2: Type): Boolean = { tp2 match { case tp2: NamedType => @@ -1421,3 +1140,286 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) { override def toString = "Subtype trace:" + { try b.toString finally b.clear() } } + +/* Alternative implementation of isSubType, currently put on hold. Did not work + * out. Keep around for a while longer in case we want to mine it for ideas. + + + def compare(tp1: Type, tp2: Type): Boolean = ctx.debugTraceIndented(s"$tp1 <:< $tp2") { + tp2 match { + case tp2: ProtoType => + isMatchedByProto(tp2, tp1) + case tp2: TypeVar => + isSubType(tp1, tp2.underlying) + case tp2: WildcardType => + def compareWildcard = tp2.optBounds match { + case TypeBounds(_, hi2) => isSubType(tp1, hi2) + case NoType => true + } + compareWildcard + case tp2: AnnotatedType => + isSubType(tp1, tp2.tpe) // todo: refine? + case ErrorType => + true + case AndType(left2, right2) => + isSubType(tp1, left2) && isSubType(tp1, right2) + case _ => + compare1(tp1, tp2) + } + } + + def compare1(tp1: Type, tp2: Type): Boolean = { + tp1 match { + case tref1: TypeRef => + val sym1 = tref1.symbol + tref1.info match { + case TypeBounds(lo1, hi1) => + if (lo1 eq hi1) return compare(hi1, tp2) + else if (sym1 is GADTFlexType) + return isSubType(hi1, tp2) || + trySetType(tref1, TypeBounds(lo1, hi1 & tp2)) + case _ => + if ((sym1 eq NothingClass) && tp2.isInstanceOf[ValueType]) return true + if ((sym1 eq NullClass) && tp2.dealias.typeSymbol.isNullableClass) return true + } + case param1: PolyParam if isConstrained(param1) => + def comparePoly = ( + param1 == tp2 + || isSubTypeWhenFrozen(bounds(param1).hi, tp2) + || { if ((tp2 isRef defn.NothingClass) && ctx.typerState.isGlobalCommittable) + ctx.log(s"!!! instantiating to Nothing: $tp1") + addConstraint(param1, tp2, fromBelow = false) + } + ) + return comparePoly + case tp1 @ ThisType(cls) if cls is ModuleClass => + tp2 match { + case tp2: TermRef => + return tp2.symbol.moduleClass == cls && cls.owner.thisType <:< tp2.prefix + case _ => + } + case tp1: TypeVar => + return compare(tp1.underlying, tp2) + case tp1: WildcardType => + def compareWildcard = tp1.optBounds match { + case TypeBounds(lo1, _) => isSubType(lo1, tp2) // todo: use short-circuiting to current method more often? + case NoType => true + } + return compareWildcard + case tp1: AnnotatedType => + return isSubType(tp1.tpe, tp2) + case ErrorType => + return true + case OrType(left1, right1) => + return isSubType(left1, tp2) && isSubType(right1, tp2) + case _ => + } + rightIsSuper(tp1, tp2) + } + + def rightIsSuper(tp1: Type, tp2: Type): Boolean = tp2 match { + case tp2: NamedType => + def compareNamed: Boolean = { + val sym2 = tp2.symbol + val pre2 = tp2.prefix + tp1 match { + case tp1: NamedType => + val sym1 = tp1.symbol + val pre1 = tp1.prefix + if (sym1 == sym2) { + if ( ctx.erasedTypes + || sym1.isStaticOwner + || isSubType(pre1, pre2) + || pre1.isInstanceOf[ThisType] && pre2.isInstanceOf[ThisType]) return true + } else if (tp1.name == tp2.name && isSubType(pre1, pre2)) return true + case _ => + } + if (sym2.isClass) { + val base = tp1.baseType(sym2) + if (base.exists && (base ne tp1)) isSubType(base, tp2) + else + (sym2 == defn.SingletonClass) && tp1.isStable || + (defn.hkTraits contains sym2) && isSubTypeHK(tp1.widen, tp2) || + leftIsSub2(tp1, tp2) + } + else tp2.info match { + case TypeBounds(lo2, hi2) => + if (lo2 eq hi2) + isSubType(tp1.dealias, hi2.dealias) + else if (sym2 is GADTFlexType) + isSubType(tp1, lo2) || trySetType(tp2, TypeBounds(lo2 | tp1, hi2)) + else { + (frozenConstraint || !isCappable(tp1)) && isSubType(tp1, lo2) || + leftIsSub(tp1, tp2) + } + case _ => + leftIsSub(tp1, tp2) + } + } + compareNamed + + case tp2 @ RefinedType(parent2, name2) => + def matchRefinements(tp1: Type, tp2: Type, seen: Set[Name]): Type = tp1 match { + case tp1 @ RefinedType(parent1, name1) if !(seen contains name1) => + tp2 match { + case tp2 @ RefinedType(parent2, name2) if nameMatches(name1, name2, tp1, tp2) => + if (isSubType(tp1.refinedInfo, tp2.refinedInfo)) + matchRefinements(parent1, parent2, seen + name1) + else NoType + case _ => tp2 + } + case _ => tp2 + } + def compareRefined: Boolean = tp1.widen match { + case tp1 @ RefinedType(parent1, name1) if nameMatches(name1, name2, tp1, tp2) => + // optimized case; all info on tp1.name2 is in refinement tp1.refinedInfo. + isSubType(tp1.refinedInfo, tp2.refinedInfo) && { + val ancestor2 = matchRefinements(parent1, parent2, Set.empty + name1) + ancestor2.exists && isSubType(tp1, ancestor2) + } + case _ => + def hasMatchingMember(name: Name): Boolean = traceIndented(s"hasMatchingMember($name) ${tp1.member(name)}") ( + tp1.member(name).hasAltWith(alt => isSubType(alt.info, tp2.refinedInfo)) + || + { // special case for situations like: + // foo <: C { type T = foo.T } + tp2.refinedInfo match { + case TypeBounds(lo, hi) if lo eq hi => + val ref = tp1 select name + isSubType(ref, lo) && isSubType(hi, ref) + case _ => false + } + } + || + name.isHkParamName && { + val idx = name.hkParamIndex + val tparams = tp1.typeParams + idx < tparams.length && hasMatchingMember(tparams(idx).name) + } + ) + isSubType(tp1, parent2) && ( + name2 == nme.WILDCARD + || hasMatchingMember(name2) + || leftIsSub2(tp1, tp2)) + } + compareRefined + + case param2: PolyParam => + def comparePoly = + param2 == tp1 || { + if (isConstrained(param2)) + isSubTypeWhenFrozen(tp1, bounds(param2).lo) || + addConstraint(param2, tp1.widen, fromBelow = true) + else + (ctx.mode is Mode.TypevarsMissContext) || + isNonBottomSubType(tp1, bounds(param2).lo) || + leftIsSub(tp1, tp2) + } + comparePoly + + case ThisType(cls) if (cls is ModuleClass) => + def compareThis: Boolean = { + tp1 match { + case tp1: TermRef => + if (tp1.symbol.moduleClass == cls) + return tp1.prefix <:< cls.owner.thisType + case _ => + } + leftIsSub(tp1, tp2) + } + compareThis + + case tp2: BoundType => + tp1 == tp2 || leftIsSub(tp1, tp2) + case OrType(tp21, tp22) => + isSubType(tp1, tp21) || isSubType(tp1, tp22) + + case tp2 @ MethodType(_, formals2) => + def compareMethod = tp1 match { + case tp1 @ MethodType(_, formals1) => + tp1.signature == tp2.signature && + (if (Config.newMatch) subsumeParams(formals1, formals2, tp1.isJava, tp2.isJava) + else matchingParams(formals1, formals2, tp1.isJava, tp2.isJava)) && + tp1.isImplicit == tp2.isImplicit && // needed? + isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) + case _ => + false + } + compareMethod + + case tp2: PolyType => + def comparePoly = tp1 match { + case tp1: PolyType => + (tp1.signature sameParams tp2.signature) && + matchingTypeParams(tp1, tp2) && + isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) + case _ => + false + } + comparePoly + + case tp2 @ ExprType(restpe2) => + def compareExpr = tp1 match { + // We allow ()T to be a subtype of => T. + // We need some subtype relationship between them so that e.g. + // def toString and def toString() don't clash when seen + // as members of the same type. And it seems most logical to take + // ()T <:< => T, since everything one can do with a => T one can + // also do with a ()T by automatic () insertion. + case tp1 @ MethodType(Nil, _) => isSubType(tp1.resultType, restpe2) + case _ => isSubType(tp1.widenExpr, restpe2) + } + compareExpr + + case tp2 @ TypeBounds(lo2, hi2) => + def compareBounds = tp1 match { + case tp1 @ TypeBounds(lo1, hi1) => + val v = tp1.variance + tp2.variance + ((v > 0) || (lo2 isRef NothingClass) || isSubType(lo2, lo1)) && + ((v < 0) || (hi2 isRef AnyClass) || isSubType(hi1, hi2)) + case tp1: ClassInfo => + val tt = tp1.typeRef + isSubType(lo2, tt) && isSubType(tt, hi2) + case _ => + false + } + compareBounds + + case ClassInfo(pre2, cls2, _, _, _) => + def compareClassInfo = tp1 match { + case ClassInfo(pre1, cls1, _, _, _) => + (cls1 eq cls2) && isSubType(pre2, pre1) + case _ => + false + } + compareClassInfo + + case _ => + leftIsSub(tp1, tp2) + } + + def leftIsSub(tp1: Type, tp2: Type): Boolean = tp1 match { + case tp1: TypeRef => + tp1.info match { + case TypeBounds(lo1, hi1) => isSubType(hi1, tp2) + case _ => false + } + case tp1: SingletonType => + isSubType(tp1.underlying.widenExpr, tp2) + case tp1: RefinedType => + isSubType(tp1.parent, tp2) + case _ => + leftIsSub2(tp1, tp2) + } + + def leftIsSub2(tp1: Type, tp2: Type): Boolean = tp1 match { + case param1: PolyParam => + assert(!isConstrained(param1)) + (ctx.mode is Mode.TypevarsMissContext) || isSubType(bounds(param1).hi, tp2) + case AndType(tp11, tp12) => + isSubType(tp11, tp2) || isSubType(tp12, tp2) + case _ => + false + } + +*/ |