From 54acd26dcf377e2eb2a474399894e10cfd4322f5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 26 Sep 2013 12:03:10 +0200 Subject: Added isRef method to determine whether a type is a typeref that refers to a symbol. The alternative (tpe eq sym.typeConstructor) does not work because types are not unique. The alternative (tpe.typeSymbol == sym) does not work because other types than TypeRefs have typeSymbols. --- src/dotty/tools/dotc/ast/TreeInfo.scala | 2 +- src/dotty/tools/dotc/core/TypeComparer.scala | 21 +++++++------ src/dotty/tools/dotc/core/Types.scala | 36 +++++++++++++++------- .../tools/dotc/core/pickling/ClassfileParser.scala | 2 +- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 4 +-- src/dotty/tools/dotc/core/transform/Erasure.scala | 4 +-- src/dotty/tools/dotc/typer/Applications.scala | 2 +- src/dotty/tools/dotc/typer/EtaExpansion.scala | 3 +- src/dotty/tools/dotc/typer/Inferencing.scala | 2 +- src/dotty/tools/dotc/typer/Typer.scala | 6 ++-- 10 files changed, 48 insertions(+), 34 deletions(-) (limited to 'src/dotty/tools/dotc') diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index adc268943..665fbec89 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -157,7 +157,7 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => /** Is tpt a by-name parameter type of the form => T? */ def isByNameParamType(tpt: Tree)(implicit ctx: Context) = tpt match { - case tpt: TypeTree => tpt.typeOpt.typeSymbol == defn.ByNameParamClass + case tpt: TypeTree => tpt.typeOpt isRef defn.ByNameParamClass case AppliedTypeTree(Select(_, tpnme.BYNAME_PARAM_CLASS), _) => true case _ => false } diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index f723dca48..588756db4 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -220,8 +220,8 @@ class TypeComparer(initctx: Context) extends DotClass { case tp2: RefinedType => isSubType(tp1, tp2.parent) && ( tp2.refinedName == nme.WILDCARD - || (tp1.typeSymbol eq NothingClass) - || (tp1.typeSymbol eq NullClass) + || (tp1 isRef NothingClass) + || (tp1 isRef NullClass) || tp1.member(tp2.refinedName).hasAltWith(alt => isSubType(alt.info, tp2.refinedInfo))) case AndType(tp21, tp22) => @@ -258,8 +258,8 @@ class TypeComparer(initctx: Context) extends DotClass { case TypeBounds(lo2, hi2) => tp1 match { case TypeBounds(lo1, hi1) => - ((lo2.typeSymbol eq NothingClass) || isSubType(lo2, lo1)) && - ((hi2.typeSymbol eq AnyClass) || isSubType(hi1, hi2)) + ((lo2 isRef NothingClass) || isSubType(lo2, lo1)) && + ((hi2 isRef AnyClass) || isSubType(hi1, hi2)) case tp1: ClassInfo => val tt = tp1.typeConstructor // was typeTemplate isSubType(lo2, tt) && isSubType(tt, hi2) @@ -386,8 +386,9 @@ class TypeComparer(initctx: Context) extends DotClass { formals2 match { case formal2 :: rest2 => (isSameType(formal1, formal2) - || isJava1 && formal2.typeSymbol == ObjectClass && formal1.typeSymbol == AnyClass - || isJava2 && formal1.typeSymbol == ObjectClass && formal2.typeSymbol == AnyClass) && matchingParams(rest1, rest2, isJava1, isJava2) + || isJava1 && (formal2 isRef ObjectClass) && (formal1 isRef AnyClass) + || isJava2 && (formal1 isRef ObjectClass) && (formal2 isRef AnyClass)) && + matchingParams(rest1, rest2, isJava1, isJava2) case nil => false } @@ -402,8 +403,8 @@ class TypeComparer(initctx: Context) extends DotClass { def glb(tp1: Type, tp2: Type): Type = if (tp1 eq tp2) tp1 - else if (!tp1.exists || (tp1.typeSymbol eq AnyClass) || (tp2.typeSymbol eq NothingClass)) tp2 - else if (!tp2.exists || (tp2.typeSymbol eq AnyClass) || (tp1.typeSymbol eq NothingClass)) tp1 + else if (!tp1.exists || (tp1 isRef AnyClass) || (tp2 isRef NothingClass)) tp2 + else if (!tp2.exists || (tp2 isRef AnyClass) || (tp1 isRef NothingClass)) tp1 else tp2 match { // normalize to disjunctive normal form if possible. case OrType(tp21, tp22) => tp1 & tp21 | tp1 & tp22 @@ -442,8 +443,8 @@ class TypeComparer(initctx: Context) extends DotClass { def lub(tp1: Type, tp2: Type): Type = if (tp1 eq tp2) tp1 - else if (!tp1.exists || (tp1.typeSymbol eq AnyClass) || (tp2.typeSymbol eq NothingClass)) tp1 - else if (!tp2.exists || (tp2.typeSymbol eq AnyClass) || (tp1.typeSymbol eq NothingClass)) tp2 + else if (!tp1.exists || (tp1 isRef AnyClass) || (tp2 isRef NothingClass)) tp1 + else if (!tp2.exists || (tp2 isRef AnyClass) || (tp1 isRef NothingClass)) tp2 else { val t1 = mergeIfSuper(tp1, tp2) if (t1.exists) t1 diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index ddb42916e..3e419359b 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -53,7 +53,6 @@ object Types { * | | +--- ConstantType * | | +--- MethodParam * | | +--- RefinedThis - * | | +--- NoPrefix * | +- PolyParam * | +- RefinedType * | +- TypeBounds @@ -69,6 +68,7 @@ object Types { * +- ClassInfo * | * +- NoType + * +- NoPrefix * +- ErrorType * +- WildcardType */ @@ -92,16 +92,30 @@ object Types { case _ => false } - /** Is this type an instance of the given class `cls`? */ - final def isClassType(cls: Symbol)(implicit ctx: Context): Boolean = - dealias.typeSymbol == cls + /** Is this type a (possibly aliased and/or partially applied) type reference + * to the given type symbol? + * @sym The symbol to compare to. It must be a class symbol or abstract type. + * It makes no sense for it to be an alias type because isRef would always + * return false in that case. + */ + def isRef(sym: Symbol)(implicit ctx: Context): Boolean = stripTypeVar match { + case this1: TypeRef => + val thissym = this1.symbol + if (thissym.isAliasType) this1.info.bounds.hi.isRef(sym) + else thissym eq sym + case this1: RefinedType => + // make sure all refinements are type arguments + this1.parent.isRef(sym) && this.typeArgs.nonEmpty + case _ => + false + } /** Is this type an instance of a non-bottom subclass of the given class `cls`? */ - final def derivesFrom(cls: Symbol)(implicit ctx: Context): Boolean = + final def derivesFrom(cls: Symbol)(implicit defctx: Context): Boolean = classSymbol.derivesFrom(cls) /** Is this an array type? */ - final def isArray(implicit ctx: Context): Boolean = isClassType(defn.ArrayClass) + final def isArray(implicit ctx: Context): Boolean = isRef(defn.ArrayClass) /** A type T is a legal prefix in a type selection T#A if * T is stable or T contains no uninstantiated type variables. @@ -568,7 +582,7 @@ object Types { /** Map references to Object to references to Any; needed for Java interop */ final def objToAny(implicit ctx: Context) = - if (isClassType(defn.ObjectClass) && !ctx.phase.erasedTypes) defn.AnyType else this + if ((this isRef defn.ObjectClass) && !ctx.phase.erasedTypes) defn.AnyType else this /** If this is repeated parameter type, its underlying type, * else the type itself. @@ -837,8 +851,8 @@ object Types { final def argType(tparam: Symbol)(implicit ctx: Context): Type = this match { case TypeBounds(lo, hi) => val v = tparam.variance - if (v > 0 && lo.isClassType(defn.NothingClass)) hi - else if (v < 0 && hi.isClassType(defn.AnyClass)) lo + if (v > 0 && (lo isRef defn.NothingClass)) hi + else if (v < 0 && (hi isRef defn.AnyClass)) lo else if (v == 0 && (lo eq hi)) lo else NoType case _ => @@ -1867,9 +1881,9 @@ object Types { if ((prefix eq cls.owner.thisType) || !cls.owner.isClass) tp else tp.substThis(cls.owner.asClass, prefix) - private var tyconCache: Type = null + private var tyconCache: TypeRef = null - def typeConstructor(implicit ctx: Context): Type = { + def typeConstructor(implicit ctx: Context): TypeRef = { def clsDenot = if (prefix eq cls.owner.thisType) cls.denot else cls.denot.copySymDenotation(info = this) if (tyconCache == null) tyconCache = diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index fc3fb49ec..f640c3d67 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -248,7 +248,7 @@ class ClassfileParser( val tp = sig2type(tparams, skiptvs) // sig2type seems to return AnyClass regardless of the situation: // we don't want Any as a LOWER bound. - if (tp.typeSymbol == defn.AnyClass) TypeBounds.empty + if (tp isRef defn.AnyClass) TypeBounds.empty else TypeBounds.lower(tp) case '*' => TypeBounds.empty } diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 109987dcf..4570d0654 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -71,7 +71,7 @@ object UnPickler { assert(lastArg.isArray) val elemtp0 :: Nil = lastArg.baseTypeArgs(defn.ArrayClass) val elemtp = elemtp0 match { - case AndType(t1, t2) if t1.typeSymbol.isAbstractType && t2.isClassType(defn.ObjectClass) => + case AndType(t1, t2) if t1.typeSymbol.isAbstractType && (t2 isRef defn.ObjectClass) => t1 // drop intersection with Object for abstract types in varargs. UnCurry can handle them. case _ => elemtp0 @@ -538,7 +538,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: */ def elimExistentials(boundSyms: List[Symbol], tp: Type): Type = { def removeSingleton(tp: Type): Type = - if (tp.isClassType(defn.SingletonClass)) defn.AnyType else tp + if (tp isRef defn.SingletonClass) defn.AnyType else tp def elim(tp: Type): Type = tp match { case tp @ RefinedType(parent, name) => val parent1 = elim(tp.parent) diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala index 6bb07e699..201dd107f 100644 --- a/src/dotty/tools/dotc/core/transform/Erasure.scala +++ b/src/dotty/tools/dotc/core/transform/Erasure.scala @@ -131,10 +131,10 @@ object Erasure { } def resultErasure(tp: Type)(implicit ctx: Context) = - if (tp.isClassType(defn.UnitClass)) tp else erasure(tp) + if (tp isRef defn.UnitClass) tp else erasure(tp) def removeLaterObjects(trs: List[TypeRef])(implicit ctx: Context): List[TypeRef] = trs match { - case tr :: trs1 => tr :: trs1.filterNot(_.isClassType(defn.ObjectClass)) + case tr :: trs1 => tr :: trs1.filterNot(_ isRef defn.ObjectClass) case nil => nil } } diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index f81fcf3cd..bf49091ec 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -556,7 +556,7 @@ trait Applications extends Compatibility { self: Typer => if (tp derivesFrom defn.ProductClass) productSelectors else if (tp derivesFrom defn.SeqClass) seqSelector :: Nil - else if (tp.typeSymbol == defn.BooleanClass) Nil + else if (tp isRef defn.BooleanClass) Nil else if (extractorMemberType(nme.isDefined).exists && extractorMemberType(nme.get).exists) recur(extractorMemberType(nme.get)) else { diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala index 6a2b2060e..155574c81 100644 --- a/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -31,11 +31,10 @@ object EtaExpansion { def liftArgs(defs: mutable.ListBuffer[Tree], methType: Type, args: List[Tree])(implicit ctx: Context) = { def toPrefix(name: Name) = if (name contains '$') "" else name.toString - def isByName(tp: Type) = tp.typeSymbol == defn.ByNameParamClass val paramInfos = methType match { case MethodType(paramNames, paramTypes) => (paramNames, paramTypes).zipped map ((name, tp) => - (toPrefix(name), isByName(tp))) + (toPrefix(name), tp isRef defn.ByNameParamClass)) case _ => args map Function.const(("", false)) } diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index 7a8b94571..2137981e7 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -28,7 +28,7 @@ object Inferencing { */ def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean = ( (tp <:< pt) - || pt.typeSymbol == defn.ByNameParamClass && (tp <:< pt.typeArgs.head) + || (pt isRef defn.ByNameParamClass) && (tp <:< pt.typeArgs.head) || viewExists(tp, pt)) } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 69b79a474..0c33aa026 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -387,7 +387,7 @@ class Typer extends Namer with Applications with Implicits { def typedPair(tree: untpd.Pair, pt: Type)(implicit ctx: Context) = { val (leftProto, rightProto) = pt.typeArgs match { - case l :: r :: Nil if pt.typeSymbol == defn.PairClass => (l, r) + case l :: r :: Nil if pt isRef defn.PairClass => (l, r) case _ => (WildcardType, WildcardType) } val left1 = typed(tree.left, leftProto) @@ -468,7 +468,7 @@ class Typer extends Namer with Applications with Implicits { else { val params = args.asInstanceOf[List[ValDef]] val protoFormals: List[Type] = pt match { - case _ if pt.typeSymbol == defn.FunctionClass(params.length) => + case _ if pt isRef defn.FunctionClass(params.length) => pt.typeArgs take params.length case SAMType(meth) => val MethodType(_, paramTypes) = meth.info @@ -1028,7 +1028,7 @@ class Typer extends Namer with Applications with Implicits { val folded = ConstFold(tree, pt) if (folded ne EmptyTree) return folded // drop type if prototype is Unit - if (pt.typeSymbol == defn.UnitClass) + if (pt isRef defn.UnitClass) return tpd.Block(tree :: Nil, Literal(Constant())) // convert function literal to SAM closure tree match { -- cgit v1.2.3