diff options
-rw-r--r-- | src/dotty/tools/dotc/ast/CheckTrees.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/untpd.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeApplications.scala | 80 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/UnPickler.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 6 |
11 files changed, 88 insertions, 33 deletions
diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala index 6152a2880..ad3764450 100644 --- a/src/dotty/tools/dotc/ast/CheckTrees.scala +++ b/src/dotty/tools/dotc/ast/CheckTrees.scala @@ -135,7 +135,7 @@ object CheckTrees { check(finalizer.isTerm) check(handler.isTerm) check(handler.tpe derivesFrom defn.FunctionClass(1)) - check(handler.tpe.baseTypeArgs(defn.FunctionClass(1)).head <:< defn.ThrowableType) + check(handler.tpe.baseArgInfos(defn.FunctionClass(1)).head <:< defn.ThrowableType) case Throw(expr) => check(expr.isValue) check(expr.tpe.derivesFrom(defn.ThrowableClass)) @@ -210,9 +210,9 @@ object CheckTrees { check(args.isEmpty) else { check(rtp isRef defn.OptionClass) - val normArgs = rtp.typeArgs match { + val normArgs = rtp.argTypesHi match { case optionArg :: Nil => - optionArg.typeArgs match { + optionArg.argTypesHi match { case Nil => optionArg :: Nil case tupleArgs if defn.isTupleType(optionArg) => diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 8b9e0c12e..03c0f83a9 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -336,7 +336,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** new C(args) */ def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = { - val targs = tp.typeArgs + val targs = tp.argTypes Apply( Select( New(tp withoutArgs targs), diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index 4aff9da5d..fc2b07b02 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -124,7 +124,7 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] { case TypedSplice(AppliedTypeTree(tycon, targs)) => (TypedSplice(tycon), targs map TypedSplice) case TypedSplice(tpt1: Tree) => - val argTypes = tpt1.tpe.typeArgs + val argTypes = tpt1.tpe.argTypes val tycon = tpt1.tpe.withoutArgs(argTypes) def wrap(tpe: Type) = TypeTree(tpe) withPos tpt.pos (wrap(tycon), argTypes map wrap) diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 0ee0ea1e2..ef16a970d 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -286,7 +286,7 @@ class Definitions { def unapply(ft: Type): Option[(List[Type], Type)] = { // Dotty deviation: Type annotation needed because inferred type // is Some[(List[Type], Type)] | None, which is not a legal unapply type. val tsym = ft.typeSymbol - lazy val targs = ft.typeArgs + lazy val targs = ft.argInfos if ((FunctionClasses contains tsym) && (targs.length - 1 <= MaxFunctionArity) && (FunctionClass(targs.length - 1) == tsym)) Some((targs.init, targs.last)) // Dotty deviation: no auto-tupling @@ -317,7 +317,7 @@ class Definitions { lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule) def isTupleType(tp: Type) = { - val arity = tp.dealias.typeArgs.length + val arity = tp.dealias.argInfos.length arity <= MaxTupleArity && (tp isRef TupleClass(arity)) } @@ -329,7 +329,7 @@ class Definitions { 0 <= arity && arity <= MaxFunctionArity && (tp isRef FunctionClass(arity)) } - def functionArity(tp: Type) = tp.dealias.typeArgs.length - 1 + def functionArity(tp: Type) = tp.dealias.argInfos.length - 1 // ----- Higher kinds machinery ------------------------------------------ diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index e854e672f..b4c30d902 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -12,6 +12,29 @@ import Flags._ import util.Positions.Position import collection.mutable +object TypeApplications { + + /** Assert type is not a TypeBounds instance and return it unchanged */ + val noBounds = (tp: Type) => tp match { + case tp: TypeBounds => throw new AssertionError("no TypeBounds allowed") + case _ => tp + } + + /** If `tp` is a TypeBounds instance return its lower bound else return `tp` */ + val boundsToLo = (tp: Type) => tp match { + case tp: TypeBounds => tp.lo + case _ => tp + } + + /** If `tp` is a TypeBounds instance return its upper bound else return `tp` */ + val boundsToHi = (tp: Type) => tp match { + case tp: TypeBounds => tp.hi + case _ => tp + } +} + +import TypeApplications._ + /** A decorator that provides methods for modeling type application */ class TypeApplications(val self: Type) extends AnyVal { @@ -135,24 +158,43 @@ class TypeApplications(val self: Type) extends AnyVal { else TypeAlias(self, v) } - /** The type arguments of the base type instance wrt `base` of this type */ - final def baseTypeArgs(base: Symbol)(implicit ctx: Context): List[Type] = + /** The type arguments of this type's base type instance wrt.`base`. + * Existential types in arguments are returned as TypeBounds instances. + */ + final def baseArgInfos(base: Symbol)(implicit ctx: Context): List[Type] = if (self derivesFrom base) - base.typeParams map (param => self.member(param.name).info.argType(param)) + base.typeParams map (param => self.member(param.name).info.argInfo(param)) else Nil + /** The type arguments of this type's base type instance wrt.`base`. + * Existential types in arguments are disallowed. + */ + final def baseArgTypes(base: Symbol)(implicit ctx: Context): List[Type] = baseArgInfos(base) mapConserve noBounds + + /** The type arguments of this type's base type instance wrt.`base`. + * Existential types in arguments are approximanted by their lower bound. + */ + final def baseArgTypesLo(base: Symbol)(implicit ctx: Context): List[Type] = baseArgInfos(base) mapConserve boundsToLo + + /** The type arguments of this type's base type instance wrt.`base`. + * Existential types in arguments are approximanted by their upper bound. + */ + final def baseArgTypesHi(base: Symbol)(implicit ctx: Context): List[Type] = baseArgInfos(base) mapConserve boundsToHi + /** The first type argument of the base type instance wrt `base` of this type */ - final def firstBaseTypeArg(base: Symbol)(implicit ctx: Context): Type = base.typeParams match { + final def firstBaseArgInfo(base: Symbol)(implicit ctx: Context): Type = base.typeParams match { case param :: _ if self derivesFrom base => - self.member(param.name).info.argType(param) + self.member(param.name).info.argInfo(param) case _ => NoType } - /** The base type including all type arguments of this type */ + /** The base type including all type arguments of this type. + * Existential types in arguments are returned as TypeBounds instances. + */ final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = - self.baseTypeRef(base).appliedTo(baseTypeArgs(base)) + self.baseTypeRef(base).appliedTo(baseArgInfos(base)) /** Translate a type of the form From[T] to To[T], keep other types as they are. * `from` and `to` must be static classes, both with one type parameter, and the same variance. @@ -163,9 +205,10 @@ class TypeApplications(val self: Type) extends AnyVal { else self /** If this is an encoding of a (partially) applied type, return its arguments, - * otherwise return Nil + * otherwise return Nil. + * Existential types in arguments are returned as TypeBounds instances. */ - final def typeArgs(implicit ctx: Context): List[Type] = { + final def argInfos(implicit ctx: Context): List[Type] = { var tparams: List[TypeSymbol] = null def recur(tp: Type, refineCount: Int): mutable.ListBuffer[Type] = tp.stripTypeVar match { case tp @ RefinedType(tycon, name) => @@ -175,7 +218,7 @@ class TypeApplications(val self: Type) extends AnyVal { if (tparams == null) tparams = tycon.typeParams if (buf.size < tparams.length) { val tparam = tparams(buf.size) - if (name == tparam.name) buf += tp.refinedInfo.argType(tparam) + if (name == tparam.name) buf += tp.refinedInfo.argInfo(tparam) else null } else null } @@ -187,6 +230,15 @@ class TypeApplications(val self: Type) extends AnyVal { if (buf == null) Nil else buf.toList } + /** Argument types where existential types in arguments are disallowed */ + def argTypes(implicit ctx: Context) = argInfos mapConserve noBounds + + /** Argument types where existential types in arguments are approximated by their lower bound */ + def argTypesLo(implicit ctx: Context) = argInfos mapConserve boundsToLo + + /** Argument types where existential types in arguments are approximated by their upper bound */ + def argTypesHi(implicit ctx: Context) = argInfos mapConserve boundsToHi + /** The core type without any type arguments. * @param `typeArgs` must be the type arguments of this type. */ @@ -201,7 +253,7 @@ class TypeApplications(val self: Type) extends AnyVal { /** If this is the image of a type argument to type parameter `tparam`, * recover the type argument, otherwise NoType. */ - final def argType(tparam: Symbol)(implicit ctx: Context): Type = self match { + final def argInfo(tparam: Symbol)(implicit ctx: Context): Type = self match { case TypeBounds(lo, hi) => if (lo eq hi) hi else { @@ -216,7 +268,7 @@ class TypeApplications(val self: Type) extends AnyVal { /** The element type of a sequence or array */ def elemType(implicit ctx: Context): Type = - firstBaseTypeArg(defn.SeqClass) orElse firstBaseTypeArg(defn.ArrayClass) + firstBaseArgInfo(defn.SeqClass) orElse firstBaseArgInfo(defn.ArrayClass) /** If this type is of the normalized form Array[...[Array[T]...] * return the number of Array wrappers and T. @@ -225,7 +277,7 @@ class TypeApplications(val self: Type) extends AnyVal { final def splitArray(implicit ctx: Context): (Int, Type) = { def recur(n: Int, tp: Type): (Int, Type) = tp.stripTypeVar match { case RefinedType(tycon, _) if tycon isRef defn.ArrayClass => - tp.typeArgs match { + tp.argInfos match { case arg :: Nil => recur(n + 1, arg) case _ => (n, tp) } @@ -274,7 +326,7 @@ class TypeApplications(val self: Type) extends AnyVal { val correspondingParamName: Map[Symbol, TypeName] = { for { - (tparam, targ: TypeRef) <- cls.typeParams zip typeArgs + (tparam, targ: TypeRef) <- cls.typeParams zip argInfos if boundSyms contains targ.symbol } yield targ.symbol -> tparam.name }.toMap diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 0af6ebf97..d46a8387f 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -616,7 +616,7 @@ class TypeComparer(initctx: Context) extends DotClass { */ def isSubTypeHK(tp1: Type, tp2: Type): Boolean = { val tparams = tp1.typeParams - val hkArgs = tp2.typeArgs + val hkArgs = tp2.argInfos (hkArgs.length == tparams.length) && { val base = tp1.narrow (tparams, hkArgs).zipped.forall { (tparam, hkArg) => @@ -752,7 +752,7 @@ class TypeComparer(initctx: Context) extends DotClass { /** The least upper bound of two types * @note We do not admit singleton types in or-types as lubs. */ - def lub(tp1: Type, tp2: Type): Type = + def lub(tp1: Type, tp2: Type): Type = /*>|>*/ ctx.traceIndented(s"lub(${tp1.show}, ${tp2.show})", typr, show = true) /*<|<*/ { if (tp1 eq tp2) tp1 else if (!tp1.exists) tp1 else if (!tp2.exists) tp2 @@ -772,6 +772,7 @@ class TypeComparer(initctx: Context) extends DotClass { } } } + } /** The least upper bound of a list of types */ final def lub(tps: List[Type]): Type = diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index bc8d7dfd2..4d26a6735 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -96,7 +96,7 @@ object Types { else thissym eq sym case this1: RefinedType => // make sure all refinements are type arguments - this1.parent.isRef(sym) && this.typeArgs.nonEmpty + this1.parent.isRef(sym) && this.argInfos.nonEmpty case _ => false } diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index c48e71052..c69f60758 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -76,7 +76,7 @@ object UnPickler { case tp @ MethodType(paramNames, paramTypes) => val lastArg = paramTypes.last assert(lastArg isRef defn.ArrayClass) - val elemtp0 :: Nil = lastArg.baseTypeArgs(defn.ArrayClass) + val elemtp0 :: Nil = lastArg.baseArgInfos(defn.ArrayClass) val elemtp = elemtp0 match { 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. diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 6fad6738e..cb0780ae3 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -96,7 +96,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } tp match { case tp: RefinedType => - val args = tp.typeArgs + val args = tp.argInfos if (args.nonEmpty) { val tycon = tp.unrefine val cls = tycon.typeSymbol diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 4b43aa8b7..4d7bc8976 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -24,6 +24,7 @@ import EtaExpansion._ import collection.mutable import reflect.ClassTag import config.Printers._ +import TypeApplications._ import language.implicitConversions object Applications { @@ -266,7 +267,7 @@ trait Applications extends Compatibility { self: Typer => case arg :: Nil if isVarArg(arg) => addTyped(arg, formal) case _ => - val elemFormal = formal.typeArgs.head + val elemFormal = formal.argTypesLo.head args foreach (addTyped(_, elemFormal)) makeVarArg(args.length, elemFormal) } @@ -609,7 +610,7 @@ trait Applications extends Compatibility { self: Typer => if (extractorMemberType(unapplyResult, nme.isDefined) isRef defn.BooleanClass) { if (getTp.exists) if (unapply.symbol.name == nme.unapplySeq) { - val seqArg = getTp.firstBaseTypeArg(defn.SeqClass) + val seqArg = boundsToHi(getTp.firstBaseArgInfo(defn.SeqClass)) if (seqArg.exists) return args map Function.const(seqArg) } else return getSelectors(getTp) @@ -683,6 +684,7 @@ trait Applications extends Compatibility { self: Typer => } var argTypes = unapplyArgs(unapplyApp.tpe) + for (argType <- argTypes) assert(!argType.isInstanceOf[TypeBounds], unapplyApp.tpe.show) val bunchedArgs = argTypes match { case argType :: Nil if argType.isRepeatedParam => untpd.SeqLiteral(args) :: Nil case _ => args @@ -770,7 +772,7 @@ trait Applications extends Compatibility { self: Typer => val tparams = ctx.newTypeParams(alt1.symbol.owner, tp1.paramNames, EmptyFlags, bounds) isAsSpecific(alt1, tp1.instantiate(tparams map (_.typeRef)), alt2, tp2) case tp1: MethodType => - def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.typeArgs.head else tp + def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.argTypesHi.head else tp isApplicable(alt2, tp1.paramTypes map repeatedToSingle, WildcardType) || tp1.paramTypes.isEmpty && tp2.isInstanceOf[MethodOrPoly] case _ => diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 400a1407a..96fe73e7d 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -438,7 +438,7 @@ class Typer extends Namer with Applications with Implicits { } def typedPair(tree: untpd.Pair, pt: Type)(implicit ctx: Context) = track("typedPair") { - val (leftProto, rightProto) = pt.typeArgs match { + val (leftProto, rightProto) = pt.argTypesLo match { case l :: r :: Nil if pt isRef defn.PairClass => (l, r) case _ => (WildcardType, WildcardType) } @@ -561,7 +561,7 @@ class Typer extends Namer with Applications with Implicits { val params = args.asInstanceOf[List[untpd.ValDef]] val (protoFormals, protoResult): (List[Type], Type) = pt match { case _ if defn.isFunctionType(pt) => - (pt.dealias.typeArgs.init, pt.dealias.typeArgs.last) + (pt.dealias.argInfos.init, pt.dealias.argInfos.last) case SAMType(meth) => val mt @ MethodType(_, paramTypes) = meth.info (paramTypes, mt.resultType) @@ -750,7 +750,7 @@ class Typer extends Namer with Applications with Implicits { val expr1 = typed(tree.expr, pt) val handler1 = typed(tree.handler, defn.FunctionType(defn.ThrowableType :: Nil, pt)) val finalizer1 = typed(tree.finalizer, defn.UnitType) - val handlerTypeArgs = handler1.tpe.baseTypeArgs(defn.FunctionClass(1)) + val handlerTypeArgs = handler1.tpe.baseArgTypesHi(defn.FunctionClass(1)) val ownType = if (handlerTypeArgs.nonEmpty) expr1.tpe | handlerTypeArgs(1) else expr1.tpe cpy.Try(tree, expr1, handler1, finalizer1) withType ownType } |