From 8897b46fd41437c8ff1a91fad4a58ed452c3c35c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 5 Oct 2016 16:06:50 +0200 Subject: Make TypeLambdas not be ValueTypes --- src/dotty/tools/dotc/core/OrderingConstraint.scala | 2 +- src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- src/dotty/tools/dotc/core/Types.scala | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/src/dotty/tools/dotc/core/OrderingConstraint.scala b/src/dotty/tools/dotc/core/OrderingConstraint.scala index 68c7655ef..93e9878e7 100644 --- a/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -393,7 +393,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, val replacement = tp.dealias.stripTypeVar if (param == replacement) this else { - assert(replacement.isValueType) + assert(replacement.isValueTypeOrLambda) val poly = param.binder val idx = param.paramNum diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 52b248abb..b518bf9d9 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -543,7 +543,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2) case _ => false } - (tp1.symbol eq NothingClass) && tp2.isInstanceOf[ValueType] || + (tp1.symbol eq NothingClass) && tp2.isValueTypeOrLambda || (tp1.symbol eq NullClass) && isNullable(tp2) } case tp1: SingletonType => diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 0f81f8c38..ce1460980 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -96,6 +96,9 @@ object Types { /** Is this type a value type? */ final def isValueType: Boolean = this.isInstanceOf[ValueType] + /** Is the is value type or type lambda? */ + final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[TypeLambda] + /** Does this type denote a stable reference (i.e. singleton type)? */ final def isStable(implicit ctx: Context): Boolean = stripTypeVar match { case tp: TermRef => tp.termSymbol.isStable && tp.prefix.isStable @@ -2197,7 +2200,7 @@ object Types { object AndType { def apply(tp1: Type, tp2: Type)(implicit ctx: Context) = { - assert(tp1.isInstanceOf[ValueType] && tp2.isInstanceOf[ValueType], i"$tp1 & $tp2 / " + s"$tp1 & $tp2") + assert(tp1.isValueType && tp2.isValueType, i"$tp1 & $tp2 / " + s"$tp1 & $tp2") unchecked(tp1, tp2) } def unchecked(tp1: Type, tp2: Type)(implicit ctx: Context) = { -- cgit v1.2.3 From bafc0a397e28c6e46619f413c9a5648026eac303 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 5 Oct 2016 16:09:17 +0200 Subject: Harmonize PolyType and TypeLambda Let them inherit the same traits and push as much functionality as possibly into the common superclass GenericType. --- src/dotty/tools/dotc/core/TypeApplications.scala | 2 +- src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- src/dotty/tools/dotc/core/TypeErasure.scala | 6 +- src/dotty/tools/dotc/core/TypeOps.scala | 1 - src/dotty/tools/dotc/core/Types.scala | 133 ++++++++++----------- .../dotc/core/unpickleScala2/Scala2Unpickler.scala | 2 +- src/dotty/tools/dotc/transform/ElimRepeated.scala | 4 +- .../tools/dotc/transform/SuperAccessors.scala | 4 +- src/dotty/tools/dotc/typer/Applications.scala | 2 +- src/dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- src/dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- tests/pos/sams.scala | 13 ++ 12 files changed, 89 insertions(+), 84 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index f32a591a6..8a4b47efb 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -485,7 +485,7 @@ class TypeApplications(val self: Type) extends AnyVal { // In this case we should always dealias since we cannot handle // higher-kinded applications to wildcard arguments. dealiased - .derivedTypeLambda(resType = tycon.safeDealias.appliedTo(args1)) + .derivedGenericType(resType = tycon.safeDealias.appliedTo(args1)) .appliedTo(args) case _ => val reducer = new Reducer(dealiased, args) diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index b518bf9d9..4c962747a 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1344,7 +1344,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp1: PolyType => tp2 match { case tp2: PolyType if matchingTypeParams(tp1, tp2) => - tp1.derivedPolyType( + tp1.derivedGenericType( mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName), tp1.paramBounds, tp1.resultType & tp2.resultType.subst(tp2, tp1)) case _ => diff --git a/src/dotty/tools/dotc/core/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala index 1a7342a12..bd1b9b1d3 100644 --- a/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/src/dotty/tools/dotc/core/TypeErasure.scala @@ -169,7 +169,7 @@ object TypeErasure { val erase = erasureFn(isJava, semiEraseVCs, sym.isConstructor, wildcardOK = false) def eraseParamBounds(tp: PolyType): Type = - tp.derivedPolyType( + tp.derivedGenericType( tp.paramNames, tp.paramNames map (Function.const(TypeBounds.upper(defn.ObjectType))), tp.resultType) if (defn.isPolymorphicAfterErasure(sym)) eraseParamBounds(sym.info.asInstanceOf[PolyType]) @@ -356,8 +356,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean SuperType(this(thistpe), this(supertpe)) case ExprType(rt) => defn.FunctionClass(0).typeRef - case tp: TypeProxy => - this(tp.underlying) case AndType(tp1, tp2) => erasedGlb(this(tp1), this(tp2), isJava) case OrType(tp1, tp2) => @@ -398,6 +396,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean tp case tp: WildcardType if wildcardOK => tp + case tp: TypeProxy => + this(tp.underlying) } private def eraseArray(tp: RefinedType)(implicit ctx: Context) = { diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index d480a792b..92e5f9d57 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -136,7 +136,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object. finally seen = saved } case _ => - if (tp.isInstanceOf[MethodicType]) assert(variance != 0, tp) mapOver(tp) } } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index ce1460980..8548a517e 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2504,24 +2504,24 @@ object Types { } /** A common supertrait of PolyType and TypeLambda */ - trait GenericType extends BindingType with TermType { - - /** The names of the type parameters */ - val paramNames: List[TypeName] + abstract class GenericType(val paramNames: List[TypeName]) + (paramBoundsExp: GenericType => List[TypeBounds], + resultTypeExp: GenericType => Type) + extends CachedProxyType with BindingType with TermType { + type This <: GenericType + protected[this] def companion: GenericCompanion[This] /** The bounds of the type parameters */ - val paramBounds: List[TypeBounds] + val paramBounds: List[TypeBounds] = paramBoundsExp(this) /** The result type of a PolyType / body of a type lambda */ - val resType: Type + val resType: Type = resultTypeExp(this) /** If this is a type lambda, the variances of its parameters, otherwise Nil.*/ - def variances: List[Int] + def variances: List[Int] = Nil override def resultType(implicit ctx: Context) = resType - - /** Unconditionally create a new generic type like this one with given elements */ - def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): GenericType + override def underlying(implicit ctx: Context) = resType /** Instantiate result type by substituting parameters with given arguments */ final def instantiate(argTypes: List[Type])(implicit ctx: Context): Type = @@ -2531,9 +2531,17 @@ object Types { def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[TypeBounds] = paramBounds.mapConserve(_.substParams(this, argTypes).bounds) - def derivedGenericType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context) = + /** Unconditionally create a new generic type like this one with given elements */ + def newLikeThis(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): This = + companion.apply(paramNames, variances)( + x => paramBounds mapConserve (_.subst(this, x).bounds), + x => resType.subst(this, x)) + + def derivedGenericType(paramNames: List[TypeName] = this.paramNames, + paramBounds: List[TypeBounds] = this.paramBounds, + resType: Type = this.resType)(implicit ctx: Context) = if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (resType eq this.resType)) this - else duplicate(paramNames, paramBounds, resType) + else newLikeThis(paramNames, paramBounds, resType) /** PolyParam references to all type parameters of this type */ lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _)) @@ -2555,14 +2563,28 @@ object Types { other.variances == this.variances case _ => false } + + override def computeHash = doHash(variances ::: paramNames, resType, paramBounds) + } + + abstract class GenericCompanion[GT <: GenericType] { + def apply(paramNames: List[TypeName], variances: List[Int])( + paramBoundsExp: GenericType => List[TypeBounds], + resultTypeExp: GenericType => Type)(implicit ctx: Context): GT + + def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context): Type = + if (tparams.isEmpty) resultType + else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))( + pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds), + pt => pt.lifted(tparams, resultType)) } /** A type for polymorphic methods */ - class PolyType(val paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) - extends CachedGroundType with GenericType with MethodOrPoly { - val paramBounds: List[TypeBounds] = paramBoundsExp(this) - val resType: Type = resultTypeExp(this) - def variances = Nil + class PolyType(paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) + extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) with MethodOrPoly { + + type This = PolyType + def companion = PolyType protected def computeSignature(implicit ctx: Context) = resultSignature @@ -2571,14 +2593,6 @@ object Types { case _ => false } - def derivedPolyType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType = - derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[PolyType] - - def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): PolyType = - PolyType(paramNames)( - x => paramBounds mapConserve (_.subst(this, x).bounds), - x => resType.subst(this, x)) - /** Merge nested polytypes into one polytype. nested polytypes are normally not supported * but can arise as temporary data structures. */ @@ -2598,34 +2612,26 @@ object Types { } override def toString = s"PolyType($paramNames, $paramBounds, $resType)" - - override def computeHash = doHash(paramNames, resType, paramBounds) } - object PolyType { - def apply(paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): PolyType = { + object PolyType extends GenericCompanion[PolyType] { + def apply(paramNames: List[TypeName], variances: List[Int] = Nil)(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): PolyType = { unique(new PolyType(paramNames)(paramBoundsExp, resultTypeExp)) } - - def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) = - if (tparams.isEmpty) resultType - else apply(tparams map (_.name.asTypeName))( - pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds), - pt => pt.lifted(tparams, resultType)) } // ----- HK types: TypeLambda, LambdaParam, HKApply --------------------- /** A type lambda of the form `[v_0 X_0, ..., v_n X_n] => T` */ - class TypeLambda(val paramNames: List[TypeName], val variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) - extends CachedProxyType with GenericType with ValueType { - val paramBounds = paramBoundsExp(this) - val resType = resultTypeExp(this) + class TypeLambda(paramNames: List[TypeName], override val variances: List[Int])( + paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) + extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) { assert(resType.isInstanceOf[TermType], this) assert(paramNames.nonEmpty) - override def underlying(implicit ctx: Context) = resType + type This = TypeLambda + def companion = TypeLambda lazy val typeParams: List[LambdaParam] = paramNames.indices.toList.map(new LambdaParam(this, _)) @@ -2633,26 +2639,31 @@ object Types { def derivedLambdaAbstraction(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type = resType match { case resType @ TypeAlias(alias) => - resType.derivedTypeAlias(duplicate(paramNames, paramBounds, alias)) + resType.derivedTypeAlias(newLikeThis(paramNames, paramBounds, alias)) case resType @ TypeBounds(lo, hi) => resType.derivedTypeBounds( - if (lo.isRef(defn.NothingClass)) lo else duplicate(paramNames, paramBounds, lo), - duplicate(paramNames, paramBounds, hi)) + if (lo.isRef(defn.NothingClass)) lo else newLikeThis(paramNames, paramBounds, lo), + newLikeThis(paramNames, paramBounds, hi)) case _ => - derivedTypeLambda(paramNames, paramBounds, resType) + derivedGenericType(paramNames, paramBounds, resType) } - def derivedTypeLambda(paramNames: List[TypeName] = paramNames, paramBounds: List[TypeBounds] = paramBounds, resType: Type)(implicit ctx: Context): TypeLambda = - derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[TypeLambda] + override def toString = s"TypeLambda($variances, $paramNames, $paramBounds, $resType)" + } - def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): TypeLambda = - TypeLambda(paramNames, variances)( - x => paramBounds mapConserve (_.subst(this, x).bounds), - x => resType.subst(this, x)) + object TypeLambda extends GenericCompanion[TypeLambda] { + def apply(paramNames: List[TypeName], variances: List[Int])( + paramBoundsExp: GenericType => List[TypeBounds], + resultTypeExp: GenericType => Type)(implicit ctx: Context): TypeLambda = { + unique(new TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp)) + } - override def toString = s"TypeLambda($variances, $paramNames, $paramBounds, $resType)" + def unapply(tl: TypeLambda): Some[(List[LambdaParam], Type)] = + Some((tl.typeParams, tl.resType)) - override def computeHash = doHash(variances ::: paramNames, resType, paramBounds) + def any(n: Int)(implicit ctx: Context) = + apply(tpnme.syntheticLambdaParamNames(n), List.fill(n)(0))( + pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType) } /** The parameter of a type lambda */ @@ -2667,24 +2678,6 @@ object Types { def paramRef(implicit ctx: Context): Type = PolyParam(tl, n) } - object TypeLambda { - def apply(paramNames: List[TypeName], variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): TypeLambda = { - unique(new TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp)) - } - - def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) = - if (tparams.isEmpty) resultType - else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))( - pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds), - pt => pt.lifted(tparams, resultType)) - def unapply(tl: TypeLambda): Some[(List[LambdaParam], Type)] = - Some((tl.typeParams, tl.resType)) - - def any(n: Int)(implicit ctx: Context) = - apply(tpnme.syntheticLambdaParamNames(n), List.fill(n)(0))( - pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType) - } - /** A higher kinded type application `C[T_1, ..., T_n]` */ abstract case class HKApply(tycon: Type, args: List[Type]) extends CachedProxyType with ValueType { diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 70148b3e2..0003459e0 100644 --- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -84,7 +84,7 @@ object Scala2Unpickler { paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp), tp.resultType) case tp: PolyType => - tp.derivedPolyType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType)) + tp.derivedGenericType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType)) } def ensureConstructor(cls: ClassSymbol, scope: Scope)(implicit ctx: Context) = diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index 258b7f234..1450ff832 100644 --- a/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -44,7 +44,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati } else paramTypes tp.derivedMethodType(paramNames, paramTypes1, resultType1) case tp: PolyType => - tp.derivedPolyType(tp.paramNames, tp.paramBounds, elimRepeated(tp.resultType)) + tp.derivedGenericType(tp.paramNames, tp.paramBounds, elimRepeated(tp.resultType)) case tp => tp } @@ -126,7 +126,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati /** Convert type from Scala to Java varargs method */ private def toJavaVarArgs(tp: Type)(implicit ctx: Context): Type = tp match { case tp: PolyType => - tp.derivedPolyType(tp.paramNames, tp.paramBounds, toJavaVarArgs(tp.resultType)) + tp.derivedGenericType(tp.paramNames, tp.paramBounds, toJavaVarArgs(tp.resultType)) case tp: MethodType => val inits :+ last = tp.paramTypes val last1 = last.underlyingIfRepeated(isJava = true) diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index 10be6db65..79dbd9fe7 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -175,7 +175,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { val accType = { def accTypeOf(tpe: Type): Type = tpe match { case tpe: PolyType => - tpe.derivedPolyType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType)) + tpe.derivedGenericType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType)) case _ => MethodType(receiverType :: Nil)(mt => tpe.substThis(sym.owner.asClass, MethodParam(mt, 0))) } @@ -227,7 +227,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { else clazz.classInfo.selfType def accTypeOf(tpe: Type): Type = tpe match { case tpe: PolyType => - tpe.derivedPolyType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType)) + tpe.derivedGenericType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType)) case _ => MethodType(receiverType :: Nil)(mt => tpe.substThis(sym.owner.asClass, MethodParam(mt, 0))) } diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 56595a637..e2779e758 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -1019,7 +1019,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // todo: make sure implicit method types are not dependent? // but check test case in /tests/pos/depmet_implicit_chaining_zw.scala case pt: PolyType => - pt.derivedPolyType(pt.paramNames, pt.paramBounds, stripImplicit(pt.resultType)) + pt.derivedGenericType(pt.paramNames, pt.paramBounds, stripImplicit(pt.resultType)) case _ => tp } diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index dd5705fbf..4fe2ea6bf 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -363,7 +363,7 @@ object ProtoTypes { yield new TypeVar(PolyParam(pt, n), state, owningTree, ctx.owner) val added = - if (state.constraint contains pt) pt.duplicate(pt.paramNames, pt.paramBounds, pt.resultType) + if (state.constraint contains pt) pt.newLikeThis(pt.paramNames, pt.paramBounds, pt.resultType) else pt val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added) ctx.typeComparer.addToConstraint(added, tvars) diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 262d3f731..aecdcbee6 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -360,7 +360,7 @@ trait TypeAssigner { if (gapBuf.isEmpty) resultType1 else { val gaps = gapBuf.toList - pt.derivedPolyType( + pt.derivedGenericType( gaps.map(paramNames), gaps.map(idx => transform(pt.paramBounds(idx)).bounds), resultType1) diff --git a/tests/pos/sams.scala b/tests/pos/sams.scala index b7ef7dd2d..20338b95c 100644 --- a/tests/pos/sams.scala +++ b/tests/pos/sams.scala @@ -73,3 +73,16 @@ class T { def app[T, U](x: T)(f: F[T, U]): U = f(x) app(1)(x => List(x)) } + +object SI9943 { + +class Foo[T] { + def toMap[K, V](implicit ev: Foo[T] <:< Foo[(K, V)]): Foo[Map[K, V]] = null + def toMap[K](keySelector: T => K): Foo[Map[K, T]] = null +} + +object Foo { + val f: Foo[Int] = null + val m = f.toMap(_ % 2) +} +} -- cgit v1.2.3 From a9be90cc3a510afb801c5e288ef54b83302ee064 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 6 Oct 2016 16:19:10 +0200 Subject: Change type inheritance diagram to account for the fact the GenericTypes are now TypeProxies. --- src/dotty/tools/dotc/core/Types.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 8548a517e..30bffd2eb 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -61,14 +61,14 @@ object Types { * | +- ExprType * | +- AnnotatedType * | +- TypeVar + * | +- GenericType ----+- PolyType + * | +- TypeLambda * | * +- GroundType -+- AndType * +- OrType * +- MethodType -----+- ImplicitMethodType * | +- JavaMethodType * +- ClassInfo - * +- GenericType ----+- PolyType - * | +- TypeLambda * | * +- NoType * +- NoPrefix -- cgit v1.2.3 From 695afc5651da0fae0ff2cf0467820b6503dd0f6d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 8 Oct 2016 10:41:09 +0200 Subject: Don't let import symbols go stale Otherwise we can run into problems when checking imports for e.g. scala2Mode in later runs. --- src/dotty/tools/dotc/core/SymDenotations.scala | 5 ++++- src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 5a5eacd18..05501011a 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -41,7 +41,7 @@ trait SymDenotations { this: Context => } def stillValid(denot: SymDenotation): Boolean = - if (denot.is(ValidForever) || denot.isRefinementClass) true + if (denot.is(ValidForever) || denot.isRefinementClass || denot.isImport) true else { val initial = denot.initial val firstPhaseId = initial.validFor.firstPhaseId.max(ctx.typerPhase.id) @@ -590,6 +590,9 @@ object SymDenotations { originalName.isSetterName && (!isCompleted || info.firstParamTypes.nonEmpty) // to avoid being fooled by var x_= : Unit = ... + /** is this a symbol representing an import? */ + final def isImport = name == nme.IMPORT + /** is this the constructor of a class? */ final def isClassConstructor = name == nme.CONSTRUCTOR diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 4f3a8d272..b6deca52b 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -553,7 +553,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { (sym.allOverriddenSymbols exists (_ is TypeParam)) override def toText(sym: Symbol): Text = { - if (sym.name == nme.IMPORT) { + if (sym.isImport) { def importString(tree: untpd.Tree) = s"import ${tree.show}" sym.infoOrCompleter match { case info: Namer#Completer => return importString(info.original) -- cgit v1.2.3 From 5456c8b944056584ad7295d7e4d2a3b7a16362f8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 8 Oct 2016 12:51:21 +0200 Subject: Make PolyType a subtype of TypeLambda --- src/dotty/tools/dotc/core/TypeComparer.scala | 10 ----- src/dotty/tools/dotc/core/Types.scala | 65 +++++++++++++++++++--------- 2 files changed, 45 insertions(+), 30 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 4c962747a..91a3dd2b9 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -478,16 +478,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { false } compareMethod - case tp2: PolyType => - def comparePoly = tp1 match { - case tp1: PolyType => - (tp1.signature consistentParams 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. diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 30bffd2eb..08b11e1cb 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2508,8 +2508,6 @@ object Types { (paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) extends CachedProxyType with BindingType with TermType { - type This <: GenericType - protected[this] def companion: GenericCompanion[This] /** The bounds of the type parameters */ val paramBounds: List[TypeBounds] = paramBoundsExp(this) @@ -2532,10 +2530,7 @@ object Types { paramBounds.mapConserve(_.substParams(this, argTypes).bounds) /** Unconditionally create a new generic type like this one with given elements */ - def newLikeThis(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): This = - companion.apply(paramNames, variances)( - x => paramBounds mapConserve (_.subst(this, x).bounds), - x => resType.subst(this, x)) + def newLikeThis(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): GenericType def derivedGenericType(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, @@ -2580,15 +2575,12 @@ object Types { } /** A type for polymorphic methods */ - class PolyType(paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) - extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) with MethodOrPoly { + class PolyType(paramNames: List[TypeName], variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) + extends TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp) with MethodOrPoly { - type This = PolyType - def companion = PolyType + protected override def computeSignature(implicit ctx: Context) = resultSignature - protected def computeSignature(implicit ctx: Context) = resultSignature - - def isPolymorphicMethodType: Boolean = resType match { + override def isPolymorphicMethodType: Boolean = resType match { case _: MethodType => true case _ => false } @@ -2596,7 +2588,7 @@ object Types { /** Merge nested polytypes into one polytype. nested polytypes are normally not supported * but can arise as temporary data structures. */ - def flatten(implicit ctx: Context): PolyType = resType match { + override def flatten(implicit ctx: Context): PolyType = resType match { case that: PolyType => val shift = new TypeMap { def apply(t: Type) = t match { @@ -2611,12 +2603,17 @@ object Types { case _ => this } + override def newLikeThis(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType = + PolyType.apply(paramNames, variances)( + x => paramBounds mapConserve (_.subst(this, x).bounds), + x => resType.subst(this, x)) + override def toString = s"PolyType($paramNames, $paramBounds, $resType)" } object PolyType extends GenericCompanion[PolyType] { def apply(paramNames: List[TypeName], variances: List[Int] = Nil)(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): PolyType = { - unique(new PolyType(paramNames)(paramBoundsExp, resultTypeExp)) + unique(new PolyType(paramNames, paramNames.map(alwaysZero))(paramBoundsExp, resultTypeExp)) } } @@ -2625,17 +2622,26 @@ object Types { /** A type lambda of the form `[v_0 X_0, ..., v_n X_n] => T` */ class TypeLambda(paramNames: List[TypeName], override val variances: List[Int])( paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) - extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) { + extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) with MethodOrPoly { assert(resType.isInstanceOf[TermType], this) assert(paramNames.nonEmpty) - type This = TypeLambda - def companion = TypeLambda + protected def computeSignature(implicit ctx: Context) = resultSignature + + def isPolymorphicMethodType: Boolean = resType match { + case _: MethodType => true + case _ => false + } lazy val typeParams: List[LambdaParam] = paramNames.indices.toList.map(new LambdaParam(this, _)) + override def newLikeThis(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): TypeLambda = + TypeLambda.apply(paramNames, variances)( + x => paramBounds mapConserve (_.subst(this, x).bounds), + x => resType.subst(this, x)) + def derivedLambdaAbstraction(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type = resType match { case resType @ TypeAlias(alias) => @@ -2648,14 +2654,33 @@ object Types { derivedGenericType(paramNames, paramBounds, resType) } + /** Merge nested polytypes into one polytype. nested polytypes are normally not supported + * but can arise as temporary data structures. + */ + def flatten(implicit ctx: Context): TypeLambda = resType match { + case that: PolyType => + val shift = new TypeMap { + def apply(t: Type) = t match { + case PolyParam(`that`, n) => PolyParam(that, n + paramNames.length) + case t => mapOver(t) + } + } + PolyType(paramNames ++ that.paramNames)( + x => this.paramBounds.mapConserve(_.subst(this, x).bounds) ++ + that.paramBounds.mapConserve(shift(_).subst(that, x).bounds), + x => shift(that.resultType).subst(that, x).subst(this, x)) + case _ => this + } + override def toString = s"TypeLambda($variances, $paramNames, $paramBounds, $resType)" } object TypeLambda extends GenericCompanion[TypeLambda] { - def apply(paramNames: List[TypeName], variances: List[Int])( + def apply(paramNames: List[TypeName], variances: List[Int] = Nil)( paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): TypeLambda = { - unique(new TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp)) + val vs = if (variances.isEmpty) paramNames.map(alwaysZero) else variances + unique(new TypeLambda(paramNames, vs)(paramBoundsExp, resultTypeExp)) } def unapply(tl: TypeLambda): Some[(List[LambdaParam], Type)] = -- cgit v1.2.3 From 6807b4454529b70d2d8a6819c51db850d06078a1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 9 Oct 2016 22:29:59 +0200 Subject: Refactor from distribute{And,Or} to {meet,join}Info The refactored logic only applies to infos of denotations, not general types. The reactoring avoids special cases down the road then PolyTypes and MethodTypes can be used for terms as well as type(bounds). --- src/dotty/tools/dotc/core/Denotations.scala | 285 ++++++++++++++++++--------- src/dotty/tools/dotc/core/TypeComparer.scala | 87 +------- 2 files changed, 196 insertions(+), 176 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 0f95fc591..7866d6697 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -6,6 +6,7 @@ import SymDenotations.{ SymDenotation, ClassDenotation, NoDenotation, NotDefined import Contexts.{Context, ContextBase} import Names.{Name, PreName} import Names.TypeName +import StdNames._ import Symbols.NoSymbol import Symbols._ import Types._ @@ -247,6 +248,25 @@ object Denotations { else asSingleDenotation } + /** Handle merge conflict by throwing a `MergeError` exception */ + private def mergeConflict(tp1: Type, tp2: Type)(implicit ctx: Context): Type = { + def showType(tp: Type) = tp match { + case ClassInfo(_, cls, _, _, _) => cls.showLocated + case bounds: TypeBounds => i"type bounds $bounds" + case _ => tp.show + } + if (true) throw new MergeError(s"cannot merge ${showType(tp1)} with ${showType(tp2)}", tp1, tp2) + else throw new Error(s"cannot merge ${showType(tp1)} with ${showType(tp2)}") // flip condition for debugging + } + + /** Merge two lists of names. If names in corresponding positions match, keep them, + * otherwise generate new synthetic names. + */ + def mergeNames[N <: Name](names1: List[N], names2: List[N], syntheticName: Int => N): List[N] = { + for ((name1, name2, idx) <- (names1, names2, 0 until names1.length).zipped) + yield if (name1 == name2) name1 else syntheticName(idx) + }.toList + /** Form a denotation by conjoining with denotation `that`. * * NoDenotations are dropped. MultiDenotations are handled by merging @@ -277,6 +297,50 @@ object Denotations { */ def & (that: Denotation, pre: Type, safeIntersection: Boolean = false)(implicit ctx: Context): Denotation = { + /** Normally, `tp1 & tp2`. Special cases for matching methods and classes, with + * the possibility of raising a merge error. + */ + def infoMeet(tp1: Type, tp2: Type): Type = { + if (tp1 eq tp2) tp1 + else tp1 match { + case tp1: TypeBounds => + tp2 match { + case tp2: TypeBounds => if (safeIntersection) tp1 safe_& tp2 else tp1 & tp2 + case tp2: ClassInfo if tp1 contains tp2 => tp2 + case _ => mergeConflict(tp1, tp2) + } + case tp1: ClassInfo => + tp2 match { + case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix) + case tp2: TypeBounds if tp2 contains tp1 => tp1 + case _ => mergeConflict(tp1, tp2) + } + case tp1 @ MethodType(names1, formals1) if isTerm => + tp2 match { + case tp2 @ MethodType(names2, formals2) if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && + tp1.isImplicit == tp2.isImplicit => + tp1.derivedMethodType( + mergeNames(names1, names2, nme.syntheticParamName), + formals1, + infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1))) + case _ => + mergeConflict(tp1, tp2) + } + case tp1: PolyType if isTerm => + tp2 match { + case tp2: PolyType if ctx.typeComparer.matchingTypeParams(tp1, tp2) => + tp1.derivedPolyType( + mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName), + tp1.paramBounds, + infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1))) + case _: MethodicType => + mergeConflict(tp1, tp2) + } + case _ => + tp1 & tp2 + } + } + /** Try to merge denot1 and denot2 without adding a new signature. */ def mergeDenot(denot1: Denotation, denot2: SingleDenotation): Denotation = denot1 match { case denot1 @ MultiDenotation(denot11, denot12) => @@ -289,96 +353,95 @@ object Denotations { } case denot1: SingleDenotation => if (denot1 eq denot2) denot1 - else if (denot1.matches(denot2)) { - val info1 = denot1.info - val info2 = denot2.info - val sym1 = denot1.symbol - val sym2 = denot2.symbol - - val sym2Accessible = sym2.isAccessibleFrom(pre) - - /** Does `sym1` come before `sym2` in the linearization of `pre`? */ - def precedes(sym1: Symbol, sym2: Symbol) = { - def precedesIn(bcs: List[ClassSymbol]): Boolean = bcs match { - case bc :: bcs1 => (sym1 eq bc) || !(sym2 eq bc) && precedesIn(bcs1) - case Nil => true - } - (sym1 ne sym2) && - (sym1.derivesFrom(sym2) || - !sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses)) - } + else if (denot1.matches(denot2)) mergeSingleDenot(denot1, denot2) + else NoDenotation + } - /** Similar to SymDenotation#accessBoundary, but without the special cases. */ - def accessBoundary(sym: Symbol) = - if (sym.is(Private)) sym.owner - else sym.privateWithin.orElse( - if (sym.is(Protected)) sym.owner.enclosingPackageClass - else defn.RootClass - ) - - /** Establish a partial order "preference" order between symbols. - * Give preference to `sym1` over `sym2` if one of the following - * conditions holds, in decreasing order of weight: - * 1. sym1 is concrete and sym2 is abstract - * 2. The owner of sym1 comes before the owner of sym2 in the linearization - * of the type of the prefix `pre`. - * 3. The access boundary of sym2 is properly contained in the access - * boundary of sym1. For protected access, we count the enclosing - * package as access boundary. - * 4. sym1 a method but sym2 is not. - * The aim of these criteria is to give some disambiguation on access which - * - does not depend on textual order or other arbitrary choices - * - minimizes raising of doubleDef errors - */ - def preferSym(sym1: Symbol, sym2: Symbol) = - sym1.eq(sym2) || - sym1.isAsConcrete(sym2) && - (!sym2.isAsConcrete(sym1) || - precedes(sym1.owner, sym2.owner) || - accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) || - sym1.is(Method) && !sym2.is(Method)) || - sym1.info.isErroneous - - /** Sym preference provided types also override */ - def prefer(sym1: Symbol, sym2: Symbol, info1: Type, info2: Type) = - preferSym(sym1, sym2) && info1.overrides(info2) - - def handleDoubleDef = - if (preferSym(sym1, sym2)) denot1 - else if (preferSym(sym2, sym1)) denot2 - else doubleDefError(denot1, denot2, pre) - - if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2 - else { - val sym1Accessible = sym1.isAccessibleFrom(pre) - if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1 - else if (sym1Accessible && sym2.exists && !sym2Accessible) denot1 - else if (sym2Accessible && sym1.exists && !sym1Accessible) denot2 - else if (isDoubleDef(sym1, sym2)) handleDoubleDef - else { - val sym = - if (!sym1.exists) sym2 - else if (!sym2.exists) sym1 - else if (preferSym(sym2, sym1)) sym2 - else sym1 - val jointInfo = - try - if (safeIntersection) - info1 safe_& info2 - else - info1 & info2 - catch { - case ex: MergeError => - if (pre.widen.classSymbol.is(Scala2x) || ctx.scala2Mode) - info1 // follow Scala2 linearization - - // compare with way merge is performed in SymDenotation#computeMembersNamed - else - throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}", ex.tp1, ex.tp2) - } - new JointRefDenotation(sym, jointInfo, denot1.validFor & denot2.validFor) + /** Try to merge single-denotations. */ + def mergeSingleDenot(denot1: SingleDenotation, denot2: SingleDenotation): SingleDenotation = { + val info1 = denot1.info + val info2 = denot2.info + val sym1 = denot1.symbol + val sym2 = denot2.symbol + + val sym2Accessible = sym2.isAccessibleFrom(pre) + + /** Does `sym1` come before `sym2` in the linearization of `pre`? */ + def precedes(sym1: Symbol, sym2: Symbol) = { + def precedesIn(bcs: List[ClassSymbol]): Boolean = bcs match { + case bc :: bcs1 => (sym1 eq bc) || !(sym2 eq bc) && precedesIn(bcs1) + case Nil => true + } + (sym1 ne sym2) && + (sym1.derivesFrom(sym2) || + !sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses)) + } + + /** Similar to SymDenotation#accessBoundary, but without the special cases. */ + def accessBoundary(sym: Symbol) = + if (sym.is(Private)) sym.owner + else sym.privateWithin.orElse( + if (sym.is(Protected)) sym.owner.enclosingPackageClass + else defn.RootClass) + + /** Establish a partial order "preference" order between symbols. + * Give preference to `sym1` over `sym2` if one of the following + * conditions holds, in decreasing order of weight: + * 1. sym1 is concrete and sym2 is abstract + * 2. The owner of sym1 comes before the owner of sym2 in the linearization + * of the type of the prefix `pre`. + * 3. The access boundary of sym2 is properly contained in the access + * boundary of sym1. For protected access, we count the enclosing + * package as access boundary. + * 4. sym1 a method but sym2 is not. + * The aim of these criteria is to give some disambiguation on access which + * - does not depend on textual order or other arbitrary choices + * - minimizes raising of doubleDef errors + */ + def preferSym(sym1: Symbol, sym2: Symbol) = + sym1.eq(sym2) || + sym1.isAsConcrete(sym2) && + (!sym2.isAsConcrete(sym1) || + precedes(sym1.owner, sym2.owner) || + accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) || + sym1.is(Method) && !sym2.is(Method)) || + sym1.info.isErroneous + + /** Sym preference provided types also override */ + def prefer(sym1: Symbol, sym2: Symbol, info1: Type, info2: Type) = + preferSym(sym1, sym2) && info1.overrides(info2) + + def handleDoubleDef = + if (preferSym(sym1, sym2)) denot1 + else if (preferSym(sym2, sym1)) denot2 + else doubleDefError(denot1, denot2, pre) + + if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2 + else { + val sym1Accessible = sym1.isAccessibleFrom(pre) + if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1 + else if (sym1Accessible && sym2.exists && !sym2Accessible) denot1 + else if (sym2Accessible && sym1.exists && !sym1Accessible) denot2 + else if (isDoubleDef(sym1, sym2)) handleDoubleDef + else { + val sym = + if (!sym1.exists) sym2 + else if (!sym2.exists) sym1 + else if (preferSym(sym2, sym1)) sym2 + else sym1 + val jointInfo = + try infoMeet(info1, info2) + catch { + case ex: MergeError => + if (pre.widen.classSymbol.is(Scala2x) || ctx.scala2Mode) + info1 // follow Scala2 linearization - + // compare with way merge is performed in SymDenotation#computeMembersNamed + else + throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}", ex.tp1, ex.tp2) } - } - } else NoDenotation + new JointRefDenotation(sym, jointInfo, denot1.validFor & denot2.validFor) + } + } } if (this eq that) this @@ -399,6 +462,46 @@ object Denotations { */ def | (that: Denotation, pre: Type)(implicit ctx: Context): Denotation = { + /** Normally, `tp1 | tp2`. Special cases for matching methods and classes, with + * the possibility of raising a merge error. + */ + def infoJoin(tp1: Type, tp2: Type): Type = tp1 match { + case tp1: TypeBounds => + tp2 match { + case tp2: TypeBounds => tp1 | tp2 + case tp2: ClassInfo if tp1 contains tp2 => tp1 + case _ => mergeConflict(tp1, tp2) + } + case tp1: ClassInfo => + tp2 match { + case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix | tp2.prefix) + case tp2: TypeBounds if tp2 contains tp1 => tp2 + case _ => mergeConflict(tp1, tp2) + } + case tp1 @ MethodType(names1, formals1) => + tp2 match { + case tp2 @ MethodType(names2, formals2) + if ctx.typeComparer.matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && + tp1.isImplicit == tp2.isImplicit => + tp1.derivedMethodType( + mergeNames(names1, names2, nme.syntheticParamName), + formals1, tp1.resultType | tp2.resultType.subst(tp2, tp1)) + case _ => + mergeConflict(tp1, tp2) + } + case tp1: PolyType => + tp2 match { + case tp2: PolyType if ctx.typeComparer.matchingTypeParams(tp1, tp2) => + tp1.derivedPolyType( + mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName), + tp1.paramBounds, tp1.resultType | tp2.resultType.subst(tp2, tp1)) + case _ => + mergeConflict(tp1, tp2) + } + case _ => + tp1 | tp2 + } + def unionDenot(denot1: SingleDenotation, denot2: SingleDenotation): Denotation = if (denot1.matches(denot2)) { val sym1 = denot1.symbol @@ -428,7 +531,8 @@ object Denotations { } lubSym(sym1.allOverriddenSymbols, NoSymbol) } - new JointRefDenotation(jointSym, info1 | info2, denot1.validFor & denot2.validFor) + new JointRefDenotation( + jointSym, infoJoin(info1, info2), denot1.validFor & denot2.validFor) } } else NoDenotation @@ -1134,5 +1238,4 @@ object Denotations { util.Stats.record("not defined here") override def getMessage() = msg } -} - +} \ No newline at end of file diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 91a3dd2b9..7f60f0231 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1022,7 +1022,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } /** Are `syms1` and `syms2` parameter lists with pairwise equivalent types? */ - private def matchingParams(formals1: List[Type], formals2: List[Type], isJava1: Boolean, isJava2: Boolean): Boolean = formals1 match { + def matchingParams(formals1: List[Type], formals2: List[Type], isJava1: Boolean, isJava2: Boolean): Boolean = formals1 match { case formal1 :: rest1 => formals2 match { case formal2 :: rest2 => @@ -1040,7 +1040,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { /** Do generic types `poly1` and `poly2` have type parameters that * have the same bounds (after renaming one set to the other)? */ - private def matchingTypeParams(poly1: GenericType, poly2: GenericType): Boolean = + def matchingTypeParams(poly1: PolyType, poly2: PolyType): Boolean = (poly1.paramBounds corresponds poly2.paramBounds)((b1, b2) => isSameType(b1, b2.subst(poly2, poly1))) @@ -1308,38 +1308,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } case tp1: RecType => tp1.rebind(distributeAnd(tp1.parent, tp2)) - case tp1: TypeBounds => - tp2 match { - case tp2: TypeBounds => tp1 & tp2 - case tp2: ClassInfo if tp1 contains tp2 => tp2 - case _ => mergeConflict(tp1, tp2) - } - case tp1: ClassInfo => - tp2 match { - case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix) - case tp2: TypeBounds if tp2 contains tp1 => tp1 - case _ => mergeConflict(tp1, tp2) - } - case tp1 @ MethodType(names1, formals1) => - tp2 match { - case tp2 @ MethodType(names2, formals2) - if matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && - tp1.isImplicit == tp2.isImplicit => - tp1.derivedMethodType( - mergeNames(names1, names2, nme.syntheticParamName), - formals1, tp1.resultType & tp2.resultType.subst(tp2, tp1)) - case _ => - mergeConflict(tp1, tp2) - } - case tp1: PolyType => - tp2 match { - case tp2: PolyType if matchingTypeParams(tp1, tp2) => - tp1.derivedGenericType( - mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName), - tp1.paramBounds, tp1.resultType & tp2.resultType.subst(tp2, tp1)) - case _ => - mergeConflict(tp1, tp2) - } case ExprType(rt1) => tp2 match { case ExprType(rt2) => @@ -1364,38 +1332,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { * The rhs is a proper supertype of the lhs. */ private def distributeOr(tp1: Type, tp2: Type): Type = tp1 match { - case tp1: TypeBounds => - tp2 match { - case tp2: TypeBounds => tp1 | tp2 - case tp2: ClassInfo if tp1 contains tp2 => tp1 - case _ => mergeConflict(tp1, tp2) - } - case tp1: ClassInfo => - tp2 match { - case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix | tp2.prefix) - case tp2: TypeBounds if tp2 contains tp1 => tp2 - case _ => mergeConflict(tp1, tp2) - } - case tp1 @ MethodType(names1, formals1) => - tp2 match { - case tp2 @ MethodType(names2, formals2) - if matchingParams(formals1, formals2, tp1.isJava, tp2.isJava) && - tp1.isImplicit == tp2.isImplicit => - tp1.derivedMethodType( - mergeNames(names1, names2, nme.syntheticParamName), - formals1, tp1.resultType | tp2.resultType.subst(tp2, tp1)) - case _ => - mergeConflict(tp1, tp2) - } - case tp1: GenericType => - tp2 match { - case tp2: GenericType if matchingTypeParams(tp1, tp2) => - tp1.derivedGenericType( - mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName), - tp1.paramBounds, tp1.resultType | tp2.resultType.subst(tp2, tp1)) - case _ => - mergeConflict(tp1, tp2) - } case ExprType(rt1) => ExprType(rt1 | tp2.widenExpr) case tp1: TypeVar if tp1.isInstantiated => @@ -1406,25 +1342,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { NoType } - /** Handle merge conflict by throwing a `MergeError` exception */ - private def mergeConflict(tp1: Type, tp2: Type): Type = { - def showType(tp: Type) = tp match { - case ClassInfo(_, cls, _, _, _) => cls.showLocated - case bounds: TypeBounds => i"type bounds $bounds" - case _ => tp.show - } - if (true) throw new MergeError(s"cannot merge ${showType(tp1)} with ${showType(tp2)}", tp1, tp2) - else throw new Error(s"cannot merge ${showType(tp1)} with ${showType(tp2)}") // flip condition for debugging - } - - /** Merge two lists of names. If names in corresponding positions match, keep them, - * otherwise generate new synthetic names. - */ - private def mergeNames[N <: Name](names1: List[N], names2: List[N], syntheticName: Int => N): List[N] = { - for ((name1, name2, idx) <- (names1, names2, 0 until names1.length).zipped) - yield if (name1 == name2) name1 else syntheticName(idx) - }.toList - /** Show type, handling type types better than the default */ private def showType(tp: Type)(implicit ctx: Context) = tp match { case ClassInfo(_, cls, _, _, _) => cls.showLocated -- cgit v1.2.3 From df2187e51e7a38a6ca8260ab4a415a7cd5efdcfc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 9 Oct 2016 22:47:26 +0200 Subject: Merge GenericType, TypeLambda and PolyType --- .../src/dotty/tools/dottydoc/model/factories.scala | 2 +- .../tools/backend/jvm/CollectEntryPoints.scala | 2 +- src/dotty/tools/dotc/ast/Trees.scala | 18 +- src/dotty/tools/dotc/ast/untpd.scala | 2 +- src/dotty/tools/dotc/core/Constraint.scala | 10 +- src/dotty/tools/dotc/core/ConstraintHandling.scala | 10 +- src/dotty/tools/dotc/core/Definitions.scala | 6 +- src/dotty/tools/dotc/core/OrderingConstraint.scala | 44 ++--- src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- src/dotty/tools/dotc/core/TypeApplications.scala | 20 +- src/dotty/tools/dotc/core/TypeComparer.scala | 15 +- src/dotty/tools/dotc/core/TypeErasure.scala | 18 +- src/dotty/tools/dotc/core/TyperState.scala | 2 +- src/dotty/tools/dotc/core/Types.scala | 219 ++++++++------------- src/dotty/tools/dotc/core/tasty/TreePickler.scala | 5 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 4 +- .../dotc/core/unpickleScala2/Scala2Unpickler.scala | 2 +- src/dotty/tools/dotc/parsing/Parsers.scala | 2 +- src/dotty/tools/dotc/printing/PlainPrinter.scala | 16 +- src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 +- src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +- src/dotty/tools/dotc/transform/ElimRepeated.scala | 4 +- .../dotc/transform/FullParameterization.scala | 4 +- .../tools/dotc/transform/SuperAccessors.scala | 4 +- src/dotty/tools/dotc/typer/Applications.scala | 2 +- src/dotty/tools/dotc/typer/Checking.scala | 4 +- src/dotty/tools/dotc/typer/Implicits.scala | 2 +- src/dotty/tools/dotc/typer/Inliner.scala | 2 +- src/dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- src/dotty/tools/dotc/typer/TypeAssigner.scala | 6 +- src/dotty/tools/dotc/typer/Typer.scala | 10 +- src/dotty/tools/dotc/typer/Variances.scala | 2 +- 32 files changed, 185 insertions(+), 260 deletions(-) (limited to 'src/dotty/tools/dotc/core') diff --git a/dottydoc/src/dotty/tools/dottydoc/model/factories.scala b/dottydoc/src/dotty/tools/dottydoc/model/factories.scala index b19b836ee..f95474ef1 100644 --- a/dottydoc/src/dotty/tools/dottydoc/model/factories.scala +++ b/dottydoc/src/dotty/tools/dottydoc/model/factories.scala @@ -43,7 +43,7 @@ object factories { } def expandTpe(t: Type, params: List[Reference] = Nil): Reference = t match { - case tl: TypeLambda => + case tl: PolyType => //FIXME: should be handled correctly // example, in `Option`: // diff --git a/src/dotty/tools/backend/jvm/CollectEntryPoints.scala b/src/dotty/tools/backend/jvm/CollectEntryPoints.scala index 3ed232bc7..2ee1b6011 100644 --- a/src/dotty/tools/backend/jvm/CollectEntryPoints.scala +++ b/src/dotty/tools/backend/jvm/CollectEntryPoints.scala @@ -107,7 +107,7 @@ object CollectEntryPoints{ else (possibles exists(x=> isJavaMainMethod(x.symbol))) || { possibles exists { m => toDenot(m.symbol).info match { - case t:PolyType => + case t: PolyType => fail("main methods cannot be generic.") case t@MethodType(paramNames, paramTypes) => if (t.resultType :: paramTypes exists (_.typeSymbol.isAbstractType)) diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index ed3690795..1fb3557db 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -562,9 +562,9 @@ object Trees { } /** [typeparams] -> tpt */ - case class TypeLambdaTree[-T >: Untyped] private[ast] (tparams: List[TypeDef[T]], body: Tree[T]) + case class PolyTypeTree[-T >: Untyped] private[ast] (tparams: List[TypeDef[T]], body: Tree[T]) extends TypTree[T] { - type ThisTree[-T >: Untyped] = TypeLambdaTree[T] + type ThisTree[-T >: Untyped] = PolyTypeTree[T] } /** => T */ @@ -820,7 +820,7 @@ object Trees { type OrTypeTree = Trees.OrTypeTree[T] type RefinedTypeTree = Trees.RefinedTypeTree[T] type AppliedTypeTree = Trees.AppliedTypeTree[T] - type TypeLambdaTree = Trees.TypeLambdaTree[T] + type PolyTypeTree = Trees.PolyTypeTree[T] type ByNameTypeTree = Trees.ByNameTypeTree[T] type TypeBoundsTree = Trees.TypeBoundsTree[T] type Bind = Trees.Bind[T] @@ -984,9 +984,9 @@ object Trees { case tree: AppliedTypeTree if (tpt eq tree.tpt) && (args eq tree.args) => tree case _ => finalize(tree, untpd.AppliedTypeTree(tpt, args)) } - def TypeLambdaTree(tree: Tree)(tparams: List[TypeDef], body: Tree): TypeLambdaTree = tree match { - case tree: TypeLambdaTree if (tparams eq tree.tparams) && (body eq tree.body) => tree - case _ => finalize(tree, untpd.TypeLambdaTree(tparams, body)) + def PolyTypeTree(tree: Tree)(tparams: List[TypeDef], body: Tree): PolyTypeTree = tree match { + case tree: PolyTypeTree if (tparams eq tree.tparams) && (body eq tree.body) => tree + case _ => finalize(tree, untpd.PolyTypeTree(tparams, body)) } def ByNameTypeTree(tree: Tree)(result: Tree): ByNameTypeTree = tree match { case tree: ByNameTypeTree if result eq tree.result => tree @@ -1118,8 +1118,8 @@ object Trees { cpy.RefinedTypeTree(tree)(transform(tpt), transformSub(refinements)) case AppliedTypeTree(tpt, args) => cpy.AppliedTypeTree(tree)(transform(tpt), transform(args)) - case TypeLambdaTree(tparams, body) => - cpy.TypeLambdaTree(tree)(transformSub(tparams), transform(body)) + case PolyTypeTree(tparams, body) => + cpy.PolyTypeTree(tree)(transformSub(tparams), transform(body)) case ByNameTypeTree(result) => cpy.ByNameTypeTree(tree)(transform(result)) case TypeBoundsTree(lo, hi) => @@ -1222,7 +1222,7 @@ object Trees { this(this(x, tpt), refinements) case AppliedTypeTree(tpt, args) => this(this(x, tpt), args) - case TypeLambdaTree(tparams, body) => + case PolyTypeTree(tparams, body) => implicit val ctx: Context = localCtx this(this(x, tparams), body) case ByNameTypeTree(result) => diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index cc7cefbac..852c3a346 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -212,7 +212,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def OrTypeTree(left: Tree, right: Tree): OrTypeTree = new OrTypeTree(left, right) def RefinedTypeTree(tpt: Tree, refinements: List[Tree]): RefinedTypeTree = new RefinedTypeTree(tpt, refinements) def AppliedTypeTree(tpt: Tree, args: List[Tree]): AppliedTypeTree = new AppliedTypeTree(tpt, args) - def TypeLambdaTree(tparams: List[TypeDef], body: Tree): TypeLambdaTree = new TypeLambdaTree(tparams, body) + def PolyTypeTree(tparams: List[TypeDef], body: Tree): PolyTypeTree = new PolyTypeTree(tparams, body) def ByNameTypeTree(result: Tree): ByNameTypeTree = new ByNameTypeTree(result) def TypeBoundsTree(lo: Tree, hi: Tree): TypeBoundsTree = new TypeBoundsTree(lo, hi) def Bind(name: Name, body: Tree): Bind = new Bind(name, body) diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala index 91e70b7b5..c99b748b7 100644 --- a/src/dotty/tools/dotc/core/Constraint.scala +++ b/src/dotty/tools/dotc/core/Constraint.scala @@ -23,7 +23,7 @@ abstract class Constraint extends Showable { type This <: Constraint /** Does the constraint's domain contain the type parameters of `pt`? */ - def contains(pt: GenericType): Boolean + def contains(pt: PolyType): Boolean /** Does the constraint's domain contain the type parameter `param`? */ def contains(param: PolyParam): Boolean @@ -79,7 +79,7 @@ abstract class Constraint extends Showable { * satisfiability but will solved to give instances of * type variables. */ - def add(poly: GenericType, tvars: List[TypeVar])(implicit ctx: Context): This + def add(poly: PolyType, tvars: List[TypeVar])(implicit ctx: Context): This /** A new constraint which is derived from this constraint by updating * the entry for parameter `param` to `tp`. @@ -121,13 +121,13 @@ abstract class Constraint extends Showable { * all type parameters of the entry are associated with type variables * which have their `inst` fields set. */ - def isRemovable(pt: GenericType): Boolean + def isRemovable(pt: PolyType): Boolean /** A new constraint with all entries coming from `pt` removed. */ - def remove(pt: GenericType)(implicit ctx: Context): This + def remove(pt: PolyType)(implicit ctx: Context): This /** The polytypes constrained by this constraint */ - def domainPolys: List[GenericType] + def domainPolys: List[PolyType] /** The polytype parameters constrained by this constraint */ def domainParams: List[PolyParam] diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala index 84f531385..3835d553c 100644 --- a/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -44,10 +44,10 @@ trait ConstraintHandling { try op finally alwaysFluid = saved } - /** We are currently comparing lambdas. Used as a flag for + /** We are currently comparing polytypes. Used as a flag for * optimization: when `false`, no need to do an expensive `pruneLambdaParams` */ - protected var comparingLambdas = false + protected var comparedPolyTypes: Set[PolyType] = Set.empty private def addOneBound(param: PolyParam, bound: Type, isUpper: Boolean): Boolean = !constraint.contains(param) || { @@ -316,12 +316,12 @@ trait ConstraintHandling { * missing. */ def pruneLambdaParams(tp: Type) = - if (comparingLambdas && param.binder.isInstanceOf[PolyType]) { + if (comparedPolyTypes.nonEmpty) { val approx = new ApproximatingTypeMap { def apply(t: Type): Type = t match { - case t @ PolyParam(tl: TypeLambda, n) => + case t @ PolyParam(pt: PolyType, n) if comparedPolyTypes contains pt => val effectiveVariance = if (fromBelow) -variance else variance - val bounds = tl.paramBounds(n) + val bounds = pt.paramBounds(n) if (effectiveVariance > 0) bounds.lo else if (effectiveVariance < 0) bounds.hi else NoType diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index b1c2bc535..50746c61d 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -92,17 +92,17 @@ class Definitions { } private def newPolyMethod(cls: ClassSymbol, name: TermName, typeParamCount: Int, - resultTypeFn: GenericType => Type, flags: FlagSet = EmptyFlags) = { + resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = { val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount) val tparamBounds = tparamNames map (_ => TypeBounds.empty) val ptype = PolyType(tparamNames)(_ => tparamBounds, resultTypeFn) newMethod(cls, name, ptype, flags) } - private def newT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: GenericType => Type, flags: FlagSet) = + private def newT1ParameterlessMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) = newPolyMethod(cls, name, 1, resultTypeFn, flags) - private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: GenericType => Type, flags: FlagSet) = + private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) = newPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags) private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[TypeRef] = { diff --git a/src/dotty/tools/dotc/core/OrderingConstraint.scala b/src/dotty/tools/dotc/core/OrderingConstraint.scala index 93e9878e7..72c7a8e51 100644 --- a/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -14,7 +14,7 @@ import annotation.tailrec object OrderingConstraint { - type ArrayValuedMap[T] = SimpleMap[GenericType, Array[T]] + type ArrayValuedMap[T] = SimpleMap[PolyType, Array[T]] /** The type of `OrderingConstraint#boundsMap` */ type ParamBounds = ArrayValuedMap[Type] @@ -32,11 +32,11 @@ object OrderingConstraint { /** A lens for updating a single entry array in one of the three constraint maps */ abstract class ConstraintLens[T <: AnyRef: ClassTag] { - def entries(c: OrderingConstraint, poly: GenericType): Array[T] - def updateEntries(c: OrderingConstraint, poly: GenericType, entries: Array[T])(implicit ctx: Context): OrderingConstraint + def entries(c: OrderingConstraint, poly: PolyType): Array[T] + def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[T])(implicit ctx: Context): OrderingConstraint def initial: T - def apply(c: OrderingConstraint, poly: GenericType, idx: Int) = { + def apply(c: OrderingConstraint, poly: PolyType, idx: Int) = { val es = entries(c, poly) if (es == null) initial else es(idx) } @@ -47,7 +47,7 @@ object OrderingConstraint { * parts of `current` which are not shared by `prev`. */ def update(prev: OrderingConstraint, current: OrderingConstraint, - poly: GenericType, idx: Int, entry: T)(implicit ctx: Context): OrderingConstraint = { + poly: PolyType, idx: Int, entry: T)(implicit ctx: Context): OrderingConstraint = { var es = entries(current, poly) if (es != null && (es(idx) eq entry)) current else { @@ -72,7 +72,7 @@ object OrderingConstraint { update(prev, current, param.binder, param.paramNum, entry) def map(prev: OrderingConstraint, current: OrderingConstraint, - poly: GenericType, idx: Int, f: T => T)(implicit ctx: Context): OrderingConstraint = + poly: PolyType, idx: Int, f: T => T)(implicit ctx: Context): OrderingConstraint = update(prev, current, poly, idx, f(apply(current, poly, idx))) def map(prev: OrderingConstraint, current: OrderingConstraint, @@ -81,25 +81,25 @@ object OrderingConstraint { } val boundsLens = new ConstraintLens[Type] { - def entries(c: OrderingConstraint, poly: GenericType): Array[Type] = + def entries(c: OrderingConstraint, poly: PolyType): Array[Type] = c.boundsMap(poly) - def updateEntries(c: OrderingConstraint, poly: GenericType, entries: Array[Type])(implicit ctx: Context): OrderingConstraint = + def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[Type])(implicit ctx: Context): OrderingConstraint = newConstraint(c.boundsMap.updated(poly, entries), c.lowerMap, c.upperMap) def initial = NoType } val lowerLens = new ConstraintLens[List[PolyParam]] { - def entries(c: OrderingConstraint, poly: GenericType): Array[List[PolyParam]] = + def entries(c: OrderingConstraint, poly: PolyType): Array[List[PolyParam]] = c.lowerMap(poly) - def updateEntries(c: OrderingConstraint, poly: GenericType, entries: Array[List[PolyParam]])(implicit ctx: Context): OrderingConstraint = + def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[List[PolyParam]])(implicit ctx: Context): OrderingConstraint = newConstraint(c.boundsMap, c.lowerMap.updated(poly, entries), c.upperMap) def initial = Nil } val upperLens = new ConstraintLens[List[PolyParam]] { - def entries(c: OrderingConstraint, poly: GenericType): Array[List[PolyParam]] = + def entries(c: OrderingConstraint, poly: PolyType): Array[List[PolyParam]] = c.upperMap(poly) - def updateEntries(c: OrderingConstraint, poly: GenericType, entries: Array[List[PolyParam]])(implicit ctx: Context): OrderingConstraint = + def updateEntries(c: OrderingConstraint, poly: PolyType, entries: Array[List[PolyParam]])(implicit ctx: Context): OrderingConstraint = newConstraint(c.boundsMap, c.lowerMap, c.upperMap.updated(poly, entries)) def initial = Nil } @@ -149,7 +149,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, // ----------- Contains tests -------------------------------------------------- - def contains(pt: GenericType): Boolean = boundsMap(pt) != null + def contains(pt: PolyType): Boolean = boundsMap(pt) != null def contains(param: PolyParam): Boolean = { val entries = boundsMap(param.binder) @@ -280,7 +280,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, stripParams(tp, paramBuf, isUpper) .orElse(if (isUpper) defn.AnyType else defn.NothingType) - def add(poly: GenericType, tvars: List[TypeVar])(implicit ctx: Context): This = { + def add(poly: PolyType, tvars: List[TypeVar])(implicit ctx: Context): This = { assert(!contains(poly)) val nparams = poly.paramNames.length val entries1 = new Array[Type](nparams * 2) @@ -293,7 +293,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, * Update all bounds to be normalized and update ordering to account for * dependent parameters. */ - private def init(poly: GenericType)(implicit ctx: Context): This = { + private def init(poly: PolyType)(implicit ctx: Context): This = { var current = this val loBuf, hiBuf = new mutable.ListBuffer[PolyParam] var i = 0 @@ -400,7 +400,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, def removeParam(ps: List[PolyParam]) = ps.filterNot(p => p.binder.eq(poly) && p.paramNum == idx) - def replaceParam(tp: Type, atPoly: GenericType, atIdx: Int): Type = tp match { + def replaceParam(tp: Type, atPoly: PolyType, atIdx: Int): Type = tp match { case bounds @ TypeBounds(lo, hi) => def recombine(andor: AndOrType, op: (Type, Boolean) => Type, isUpper: Boolean): Type = { @@ -440,9 +440,9 @@ class OrderingConstraint(private val boundsMap: ParamBounds, } } - def remove(pt: GenericType)(implicit ctx: Context): This = { + def remove(pt: PolyType)(implicit ctx: Context): This = { def removeFromOrdering(po: ParamOrdering) = { - def removeFromBoundss(key: GenericType, bndss: Array[List[PolyParam]]): Array[List[PolyParam]] = { + def removeFromBoundss(key: PolyType, bndss: Array[List[PolyParam]]): Array[List[PolyParam]] = { val bndss1 = bndss.map(_.filterConserve(_.binder ne pt)) if (bndss.corresponds(bndss1)(_ eq _)) bndss else bndss1 } @@ -451,7 +451,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, newConstraint(boundsMap.remove(pt), removeFromOrdering(lowerMap), removeFromOrdering(upperMap)) } - def isRemovable(pt: GenericType): Boolean = { + def isRemovable(pt: PolyType): Boolean = { val entries = boundsMap(pt) @tailrec def allRemovable(last: Int): Boolean = if (last < 0) true @@ -464,7 +464,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, // ---------- Exploration -------------------------------------------------------- - def domainPolys: List[GenericType] = boundsMap.keys + def domainPolys: List[PolyType] = boundsMap.keys def domainParams: List[PolyParam] = for { @@ -481,7 +481,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, true } - def foreachParam(p: (GenericType, Int) => Unit): Unit = + def foreachParam(p: (PolyType, Int) => Unit): Unit = boundsMap.foreachBinding { (poly, entries) => 0.until(poly.paramNames.length).foreach(p(poly, _)) } @@ -541,7 +541,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, override def checkClosed()(implicit ctx: Context): Unit = { def isFreePolyParam(tp: Type) = tp match { - case PolyParam(binder: GenericType, _) => !contains(binder) + case PolyParam(binder: PolyType, _) => !contains(binder) case _ => false } def checkClosedType(tp: Type, where: String) = diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 05501011a..a98d6732a 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1150,7 +1150,7 @@ object SymDenotations { case tp: NamedType => hasSkolems(tp.prefix) case tp: RefinedType => hasSkolems(tp.parent) || hasSkolems(tp.refinedInfo) case tp: RecType => hasSkolems(tp.parent) - case tp: GenericType => tp.paramBounds.exists(hasSkolems) || hasSkolems(tp.resType) + case tp: PolyType => tp.paramBounds.exists(hasSkolems) || hasSkolems(tp.resType) case tp: MethodType => tp.paramTypes.exists(hasSkolems) || hasSkolems(tp.resType) case tp: ExprType => hasSkolems(tp.resType) case tp: HKApply => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems) diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 8a4b47efb..8aaf77032 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -72,7 +72,7 @@ object TypeApplications { } def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] = tp match { - case tp @ TypeLambda(tparams, AppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn) + case tp @ PolyType(tparams, AppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn) case _ => None } } @@ -159,7 +159,7 @@ object TypeApplications { * result type. Using this mode, we can guarantee that `appliedTo` will never * produce a higher-kinded application with a type lambda as type constructor. */ - class Reducer(tycon: TypeLambda, args: List[Type])(implicit ctx: Context) extends TypeMap { + class Reducer(tycon: PolyType, args: List[Type])(implicit ctx: Context) extends TypeMap { private var available = (0 until args.length).toSet var allReplaced = true def hasWildcardArg(p: PolyParam) = @@ -212,7 +212,7 @@ class TypeApplications(val self: Type) extends AnyVal { self match { case self: ClassInfo => self.cls.typeParams - case self: TypeLambda => + case self: PolyType => self.typeParams case self: TypeRef => val tsym = self.symbol @@ -311,7 +311,7 @@ class TypeApplications(val self: Type) extends AnyVal { def isHK(implicit ctx: Context): Boolean = self.dealias match { case self: TypeRef => self.info.isHK case self: RefinedType => false - case self: TypeLambda => true + case self: PolyType => true case self: SingletonType => false case self: TypeVar => // Using `origin` instead of `underlying`, as is done for typeParams, @@ -339,7 +339,7 @@ class TypeApplications(val self: Type) extends AnyVal { */ def LambdaAbstract(tparams: List[TypeParamInfo])(implicit ctx: Context): Type = { def expand(tp: Type) = - TypeLambda( + PolyType( tpnme.syntheticLambdaParamNames(tparams.length), tparams.map(_.paramVariance))( tl => tparams.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds), tl => tl.lifted(tparams, tp)) @@ -421,10 +421,10 @@ class TypeApplications(val self: Type) extends AnyVal { if (hkParams.isEmpty) self else { def adaptArg(arg: Type): Type = arg match { - case arg @ TypeLambda(tparams, body) if + case arg @ PolyType(tparams, body) if !tparams.corresponds(hkParams)(_.paramVariance == _.paramVariance) && tparams.corresponds(hkParams)(varianceConforms) => - TypeLambda(tparams.map(_.paramName), hkParams.map(_.paramVariance))( + PolyType(tparams.map(_.paramName), hkParams.map(_.paramVariance))( tl => arg.paramBounds.map(_.subst(arg, tl).bounds), tl => arg.resultType.subst(arg, tl) ) @@ -466,7 +466,7 @@ class TypeApplications(val self: Type) extends AnyVal { val dealiased = stripped.safeDealias if (args.isEmpty || ctx.erasedTypes) self else dealiased match { - case dealiased: TypeLambda => + case dealiased: PolyType => def tryReduce = if (!args.exists(_.isInstanceOf[TypeBounds])) { val followAlias = Config.simplifyApplications && { @@ -485,7 +485,7 @@ class TypeApplications(val self: Type) extends AnyVal { // In this case we should always dealias since we cannot handle // higher-kinded applications to wildcard arguments. dealiased - .derivedGenericType(resType = tycon.safeDealias.appliedTo(args1)) + .derivedPolyType(resType = tycon.safeDealias.appliedTo(args1)) .appliedTo(args) case _ => val reducer = new Reducer(dealiased, args) @@ -494,8 +494,6 @@ class TypeApplications(val self: Type) extends AnyVal { else HKApply(dealiased, args) } tryReduce - case dealiased: PolyType => - dealiased.instantiate(args) case dealiased: AndOrType => dealiased.derivedAndOrType(dealiased.tp1.appliedTo(args), dealiased.tp2.appliedTo(args)) case dealiased: TypeAlias => diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 7f60f0231..b495f00d0 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -412,9 +412,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { compareRec case tp2 @ HKApply(tycon2, args2) => compareHkApply2(tp1, tp2, tycon2, args2) - case tp2 @ TypeLambda(tparams2, body2) => + case tp2 @ PolyType(tparams2, body2) => def compareHkLambda: Boolean = tp1.stripTypeVar match { - case tp1 @ TypeLambda(tparams1, body1) => + case tp1 @ PolyType(tparams1, body1) => /* Don't compare bounds of lambdas under language:Scala2, or t2994 will fail * The issue is that, logically, bounds should compare contravariantly, * but that would invalidate a pattern exploited in t2994: @@ -432,13 +432,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { ctx.scala2Mode || tparams1.corresponds(tparams2)((tparam1, tparam2) => isSubType(tparam2.paramBounds.subst(tp2, tp1), tparam1.paramBounds)) - val saved = comparingLambdas - comparingLambdas = true + val saved = comparedPolyTypes + comparedPolyTypes += tp1 + comparedPolyTypes += tp2 try variancesConform(tparams1, tparams2) && boundsOK && isSubType(body1, body2.subst(tp2, tp1)) - finally comparingLambdas = saved + finally comparedPolyTypes = saved case _ => if (!tp1.isHK) { tp2 match { @@ -650,7 +651,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val tparams1 = tparams1a.drop(lengthDiff) variancesConform(tparams1, tparams) && { if (lengthDiff > 0) - tycon1b = TypeLambda(tparams1.map(_.paramName), tparams1.map(_.paramVariance))( + tycon1b = PolyType(tparams1.map(_.paramName), tparams1.map(_.paramVariance))( tl => tparams1.map(tparam => tl.lifted(tparams, tparam.paramBounds).bounds), tl => tycon1a.appliedTo(args1.take(lengthDiff) ++ tparams1.indices.toList.map(PolyParam(tl, _)))) @@ -1264,7 +1265,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { else if (tparams2.isEmpty) original(tp1.appliedTo(tp1.typeParams.map(_.paramBoundsAsSeenFrom(tp1))), tp2) else - TypeLambda( + PolyType( paramNames = tpnme.syntheticLambdaParamNames(tparams1.length), variances = (tparams1, tparams2).zipped.map((tparam1, tparam2) => (tparam1.paramVariance + tparam2.paramVariance) / 2))( diff --git a/src/dotty/tools/dotc/core/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala index bd1b9b1d3..fd5fcb921 100644 --- a/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/src/dotty/tools/dotc/core/TypeErasure.scala @@ -169,7 +169,7 @@ object TypeErasure { val erase = erasureFn(isJava, semiEraseVCs, sym.isConstructor, wildcardOK = false) def eraseParamBounds(tp: PolyType): Type = - tp.derivedGenericType( + tp.derivedPolyType( tp.paramNames, tp.paramNames map (Function.const(TypeBounds.upper(defn.ObjectType))), tp.resultType) if (defn.isPolymorphicAfterErasure(sym)) eraseParamBounds(sym.info.asInstanceOf[PolyType]) @@ -370,11 +370,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean case rt => tp.derivedMethodType(tp.paramNames, formals, rt) } - case tp: PolyType => - this(tp.resultType) match { - case rt: MethodType => rt - case rt => MethodType(Nil, Nil, rt) - } case tp @ ClassInfo(pre, cls, classParents, decls, _) => if (cls is Package) tp else { @@ -409,9 +404,9 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean else JavaArrayType(arrayErasure(elemtp)) } - /** The erasure of a symbol's info. This is different from `apply` in the way `ExprType`s are - * treated. `eraseInfo` maps them them to nullary method types, whereas `apply` maps them - * to `Function0`. + /** The erasure of a symbol's info. This is different from `apply` in the way `ExprType`s and + * `PolyType`s are treated. `eraseInfo` maps them them to method types, whereas `apply` maps them + * to the underlying type. */ def eraseInfo(tp: Type, sym: Symbol)(implicit ctx: Context) = tp match { case ExprType(rt) => @@ -421,6 +416,11 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean // forwarders to mixin methods. // See doc comment for ElimByName for speculation how we could improve this. else MethodType(Nil, Nil, eraseResult(rt)) + case tp: PolyType => + this(tp.resultType) match { + case rt: MethodType => rt + case rt => MethodType(Nil, Nil, rt) + } case tp => this(tp) } diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala index 7e332b412..5c476c1cb 100644 --- a/src/dotty/tools/dotc/core/TyperState.scala +++ b/src/dotty/tools/dotc/core/TyperState.scala @@ -152,7 +152,7 @@ extends TyperState(r) { } override def gc()(implicit ctx: Context): Unit = { - val toCollect = new mutable.ListBuffer[GenericType] + val toCollect = new mutable.ListBuffer[PolyType] constraint foreachTypeVar { tvar => if (!tvar.inst.exists) { val inst = instType(tvar) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 08b11e1cb..d242843e5 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -61,8 +61,7 @@ object Types { * | +- ExprType * | +- AnnotatedType * | +- TypeVar - * | +- GenericType ----+- PolyType - * | +- TypeLambda + * | +- PolyType * | * +- GroundType -+- AndType * +- OrType @@ -97,7 +96,7 @@ object Types { final def isValueType: Boolean = this.isInstanceOf[ValueType] /** Is the is value type or type lambda? */ - final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[TypeLambda] + final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[PolyType] /** Does this type denote a stable reference (i.e. singleton type)? */ final def isStable(implicit ctx: Context): Boolean = stripTypeVar match { @@ -522,7 +521,7 @@ object Types { } def goApply(tp: HKApply) = tp.tycon match { - case tl: TypeLambda => + case tl: PolyType => go(tl.resType).mapInfo(info => tl.derivedLambdaAbstraction(tl.paramNames, tl.paramBounds, info).appliedTo(tp.args)) case _ => @@ -1087,7 +1086,7 @@ object Types { /** The parameter types in the first parameter section of a generic type or MethodType, Empty list for others */ final def firstParamTypes(implicit ctx: Context): List[Type] = this match { case mt: MethodType => mt.paramTypes - case pt: GenericType => pt.resultType.firstParamTypes + case pt: PolyType => pt.resultType.firstParamTypes case _ => Nil } @@ -2263,7 +2262,7 @@ object Types { // and therefore two different poly types would never be equal. /** A trait that mixes in functionality for signature caching */ - trait MethodicType extends Type { + trait MethodicType extends TermType { private[this] var mySignature: Signature = _ private[this] var mySignatureRunId: Int = NoRunId @@ -2503,11 +2502,10 @@ object Types { } } - /** A common supertrait of PolyType and TypeLambda */ - abstract class GenericType(val paramNames: List[TypeName]) - (paramBoundsExp: GenericType => List[TypeBounds], - resultTypeExp: GenericType => Type) - extends CachedProxyType with BindingType with TermType { + /** A type lambda of the form `[v_0 X_0, ..., v_n X_n] => T` */ + class PolyType(val paramNames: List[TypeName], val variances: List[Int])( + paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type) + extends CachedProxyType with BindingType with MethodOrPoly { /** The bounds of the type parameters */ val paramBounds: List[TypeBounds] = paramBoundsExp(this) @@ -2515,115 +2513,6 @@ object Types { /** The result type of a PolyType / body of a type lambda */ val resType: Type = resultTypeExp(this) - /** If this is a type lambda, the variances of its parameters, otherwise Nil.*/ - def variances: List[Int] = Nil - - override def resultType(implicit ctx: Context) = resType - override def underlying(implicit ctx: Context) = resType - - /** Instantiate result type by substituting parameters with given arguments */ - final def instantiate(argTypes: List[Type])(implicit ctx: Context): Type = - resultType.substParams(this, argTypes) - - /** Instantiate parameter bounds by substituting parameters with given arguments */ - def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[TypeBounds] = - paramBounds.mapConserve(_.substParams(this, argTypes).bounds) - - /** Unconditionally create a new generic type like this one with given elements */ - def newLikeThis(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): GenericType - - def derivedGenericType(paramNames: List[TypeName] = this.paramNames, - paramBounds: List[TypeBounds] = this.paramBounds, - resType: Type = this.resType)(implicit ctx: Context) = - if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (resType eq this.resType)) this - else newLikeThis(paramNames, paramBounds, resType) - - /** PolyParam references to all type parameters of this type */ - lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _)) - - /** The type `[tparams := paramRefs] tp`, where `tparams` can be - * either a list of type parameter symbols or a list of lambda parameters - */ - def lifted(tparams: List[TypeParamInfo], tp: Type)(implicit ctx: Context): Type = - tparams match { - case LambdaParam(poly, _) :: _ => tp.subst(poly, this) - case tparams: List[Symbol @unchecked] => tp.subst(tparams, paramRefs) - } - - override def equals(other: Any) = other match { - case other: GenericType => - other.paramNames == this.paramNames && - other.paramBounds == this.paramBounds && - other.resType == this.resType && - other.variances == this.variances - case _ => false - } - - override def computeHash = doHash(variances ::: paramNames, resType, paramBounds) - } - - abstract class GenericCompanion[GT <: GenericType] { - def apply(paramNames: List[TypeName], variances: List[Int])( - paramBoundsExp: GenericType => List[TypeBounds], - resultTypeExp: GenericType => Type)(implicit ctx: Context): GT - - def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context): Type = - if (tparams.isEmpty) resultType - else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))( - pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds), - pt => pt.lifted(tparams, resultType)) - } - - /** A type for polymorphic methods */ - class PolyType(paramNames: List[TypeName], variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) - extends TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp) with MethodOrPoly { - - protected override def computeSignature(implicit ctx: Context) = resultSignature - - override def isPolymorphicMethodType: Boolean = resType match { - case _: MethodType => true - case _ => false - } - - /** Merge nested polytypes into one polytype. nested polytypes are normally not supported - * but can arise as temporary data structures. - */ - override def flatten(implicit ctx: Context): PolyType = resType match { - case that: PolyType => - val shift = new TypeMap { - def apply(t: Type) = t match { - case PolyParam(`that`, n) => PolyParam(that, n + paramNames.length) - case t => mapOver(t) - } - } - PolyType(paramNames ++ that.paramNames)( - x => this.paramBounds.mapConserve(_.subst(this, x).bounds) ++ - that.paramBounds.mapConserve(shift(_).subst(that, x).bounds), - x => shift(that.resultType).subst(that, x).subst(this, x)) - case _ => this - } - - override def newLikeThis(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType = - PolyType.apply(paramNames, variances)( - x => paramBounds mapConserve (_.subst(this, x).bounds), - x => resType.subst(this, x)) - - override def toString = s"PolyType($paramNames, $paramBounds, $resType)" - } - - object PolyType extends GenericCompanion[PolyType] { - def apply(paramNames: List[TypeName], variances: List[Int] = Nil)(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): PolyType = { - unique(new PolyType(paramNames, paramNames.map(alwaysZero))(paramBoundsExp, resultTypeExp)) - } - } - - // ----- HK types: TypeLambda, LambdaParam, HKApply --------------------- - - /** A type lambda of the form `[v_0 X_0, ..., v_n X_n] => T` */ - class TypeLambda(paramNames: List[TypeName], override val variances: List[Int])( - paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type) - extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) with MethodOrPoly { - assert(resType.isInstanceOf[TermType], this) assert(paramNames.nonEmpty) @@ -2634,14 +2523,34 @@ object Types { case _ => false } + /** PolyParam references to all type parameters of this type */ + lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _)) + lazy val typeParams: List[LambdaParam] = paramNames.indices.toList.map(new LambdaParam(this, _)) - override def newLikeThis(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): TypeLambda = - TypeLambda.apply(paramNames, variances)( + override def resultType(implicit ctx: Context) = resType + override def underlying(implicit ctx: Context) = resType + + /** Instantiate result type by substituting parameters with given arguments */ + final def instantiate(argTypes: List[Type])(implicit ctx: Context): Type = + resultType.substParams(this, argTypes) + + /** Instantiate parameter bounds by substituting parameters with given arguments */ + final def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[TypeBounds] = + paramBounds.mapConserve(_.substParams(this, argTypes).bounds) + + def newLikeThis(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType = + PolyType.apply(paramNames, variances)( x => paramBounds mapConserve (_.subst(this, x).bounds), x => resType.subst(this, x)) + def derivedPolyType(paramNames: List[TypeName] = this.paramNames, + paramBounds: List[TypeBounds] = this.paramBounds, + resType: Type = this.resType)(implicit ctx: Context) = + if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (resType eq this.resType)) this + else newLikeThis(paramNames, paramBounds, resType) + def derivedLambdaAbstraction(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type = resType match { case resType @ TypeAlias(alias) => @@ -2651,13 +2560,13 @@ object Types { if (lo.isRef(defn.NothingClass)) lo else newLikeThis(paramNames, paramBounds, lo), newLikeThis(paramNames, paramBounds, hi)) case _ => - derivedGenericType(paramNames, paramBounds, resType) + derivedPolyType(paramNames, paramBounds, resType) } /** Merge nested polytypes into one polytype. nested polytypes are normally not supported * but can arise as temporary data structures. */ - def flatten(implicit ctx: Context): TypeLambda = resType match { + def flatten(implicit ctx: Context): PolyType = resType match { case that: PolyType => val shift = new TypeMap { def apply(t: Type) = t match { @@ -2672,18 +2581,44 @@ object Types { case _ => this } - override def toString = s"TypeLambda($variances, $paramNames, $paramBounds, $resType)" + /** The type `[tparams := paramRefs] tp`, where `tparams` can be + * either a list of type parameter symbols or a list of lambda parameters + */ + def lifted(tparams: List[TypeParamInfo], tp: Type)(implicit ctx: Context): Type = + tparams match { + case LambdaParam(poly, _) :: _ => tp.subst(poly, this) + case tparams: List[Symbol @unchecked] => tp.subst(tparams, paramRefs) + } + + override def equals(other: Any) = other match { + case other: PolyType => + other.paramNames == this.paramNames && + other.paramBounds == this.paramBounds && + other.resType == this.resType && + other.variances == this.variances + case _ => false + } + + override def toString = s"PolyType($variances, $paramNames, $paramBounds, $resType)" + + override def computeHash = doHash(variances ::: paramNames, resType, paramBounds) } - object TypeLambda extends GenericCompanion[TypeLambda] { + object PolyType { def apply(paramNames: List[TypeName], variances: List[Int] = Nil)( - paramBoundsExp: GenericType => List[TypeBounds], - resultTypeExp: GenericType => Type)(implicit ctx: Context): TypeLambda = { + paramBoundsExp: PolyType => List[TypeBounds], + resultTypeExp: PolyType => Type)(implicit ctx: Context): PolyType = { val vs = if (variances.isEmpty) paramNames.map(alwaysZero) else variances - unique(new TypeLambda(paramNames, vs)(paramBoundsExp, resultTypeExp)) + unique(new PolyType(paramNames, vs)(paramBoundsExp, resultTypeExp)) } - def unapply(tl: TypeLambda): Some[(List[LambdaParam], Type)] = + def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context): Type = + if (tparams.isEmpty) resultType + else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))( + pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds), + pt => pt.lifted(tparams, resultType)) + + def unapply(tl: PolyType): Some[(List[LambdaParam], Type)] = Some((tl.typeParams, tl.resType)) def any(n: Int)(implicit ctx: Context) = @@ -2691,8 +2626,10 @@ object Types { pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType) } + // ----- HK types: LambdaParam, HKApply --------------------- + /** The parameter of a type lambda */ - case class LambdaParam(tl: TypeLambda, n: Int) extends TypeParamInfo { + case class LambdaParam(tl: PolyType, n: Int) extends TypeParamInfo { def isTypeParam(implicit ctx: Context) = true def paramName(implicit ctx: Context): TypeName = tl.paramNames(n) def paramBounds(implicit ctx: Context): TypeBounds = tl.paramBounds(n) @@ -2715,7 +2652,7 @@ object Types { override def superType(implicit ctx: Context): Type = { if (ctx.period != validSuper) { cachedSuper = tycon match { - case tp: TypeLambda => defn.AnyType + case tp: PolyType => defn.AnyType case tp: TypeVar if !tp.inst.exists => // supertype not stable, since underlying might change return tp.underlying.applyIfParameterized(args) @@ -2741,7 +2678,7 @@ object Types { def typeParams(implicit ctx: Context): List[TypeParamInfo] = { val tparams = tycon.typeParams - if (tparams.isEmpty) TypeLambda.any(args.length).typeParams else tparams + if (tparams.isEmpty) PolyType.any(args.length).typeParams else tparams } def derivedAppliedType(tycon: Type, args: List[Type])(implicit ctx: Context): Type = @@ -2754,7 +2691,7 @@ object Types { def check(tycon: Type): Unit = tycon.stripTypeVar match { case tycon: TypeRef if !tycon.symbol.isClass => case _: PolyParam | ErrorType | _: WildcardType => - case _: TypeLambda => + case _: PolyType => assert(args.exists(_.isInstanceOf[TypeBounds]), s"unreduced type apply: $this") case tycon: AnnotatedType => check(tycon.underlying) @@ -2820,8 +2757,8 @@ object Types { } /** TODO Some docs would be nice here! */ - case class PolyParam(binder: GenericType, paramNum: Int) extends ParamType { - type BT = GenericType + case class PolyParam(binder: PolyType, paramNum: Int) extends ParamType { + type BT = PolyType def copyBoundType(bt: BT) = PolyParam(bt, paramNum) /** Looking only at the structure of `bound`, is one of the following true? @@ -3427,8 +3364,8 @@ object Types { tp.derivedMethodType(tp.paramNames, formals, restpe) protected def derivedExprType(tp: ExprType, restpe: Type): Type = tp.derivedExprType(restpe) - protected def derivedGenericType(tp: GenericType, pbounds: List[TypeBounds], restpe: Type): Type = - tp.derivedGenericType(tp.paramNames, pbounds, restpe) + protected def derivedPolyType(tp: PolyType, pbounds: List[TypeBounds], restpe: Type): Type = + tp.derivedPolyType(tp.paramNames, pbounds, restpe) /** Map this function over given type */ def mapOver(tp: Type): Type = { @@ -3470,12 +3407,12 @@ object Types { case tp: ExprType => derivedExprType(tp, this(tp.resultType)) - case tp: GenericType => + case tp: PolyType => def mapOverPoly = { variance = -variance val bounds1 = tp.paramBounds.mapConserve(this).asInstanceOf[List[TypeBounds]] variance = -variance - derivedGenericType(tp, bounds1, this(tp.resultType)) + derivedPolyType(tp, bounds1, this(tp.resultType)) } mapOverPoly @@ -3688,7 +3625,7 @@ object Types { case ExprType(restpe) => this(x, restpe) - case tp: GenericType => + case tp: PolyType => variance = -variance val y = foldOver(x, tp.paramBounds) variance = -variance diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala index b6f52c0ec..8889e8a5c 100644 --- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -251,7 +251,7 @@ class TreePickler(pickler: TastyPickler) { case tpe: ExprType => writeByte(BYNAMEtype) pickleType(tpe.underlying) - case tpe: TypeLambda => + case tpe: PolyType => writeByte(LAMBDAtype) val paramNames = tpe.typeParams.map(tparam => varianceToPrefix(tparam.paramVariance) +: tparam.paramName) @@ -259,9 +259,6 @@ class TreePickler(pickler: TastyPickler) { case tpe: MethodType if richTypes => writeByte(METHODtype) pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramTypes) - case tpe: PolyType if richTypes => - writeByte(POLYtype) - pickleMethodic(tpe.resultType, tpe.paramNames, tpe.paramBounds) case tpe: PolyParam => if (!pickleParamType(tpe)) // TODO figure out why this case arises in e.g. pickling AbstractFileReader. diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 09f2c0d1f..f67159808 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -270,7 +270,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val (rawNames, paramReader) = readNamesSkipParams val (variances, paramNames) = rawNames .map(name => (prefixToVariance(name.head), name.tail.toTypeName)).unzip - val result = TypeLambda(paramNames, variances)( + val result = PolyType(paramNames, variances)( pt => registeringType(pt, paramReader.readParamTypes[TypeBounds](end)), pt => readType()) goto(end) @@ -290,7 +290,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle result case PARAMtype => readTypeRef() match { - case binder: GenericType => PolyParam(binder, readNat()) + case binder: PolyType => PolyParam(binder, readNat()) case binder: MethodType => MethodParam(binder, readNat()) } case CLASSconst => diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 0003459e0..70148b3e2 100644 --- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -84,7 +84,7 @@ object Scala2Unpickler { paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp), tp.resultType) case tp: PolyType => - tp.derivedGenericType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType)) + tp.derivedPolyType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType)) } def ensureConstructor(cls: ClassSymbol, scope: Scope)(implicit ctx: Context) = diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index f22556f27..ab4e38638 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -702,7 +702,7 @@ object Parsers { val start = in.offset val tparams = typeParamClause(ParamOwner.TypeParam) if (isIdent && in.name.toString == "->") - atPos(start, in.skipToken())(TypeLambdaTree(tparams, typ())) + atPos(start, in.skipToken())(PolyTypeTree(tparams, typ())) else { syntaxErrorOrIncomplete(expectedMessage("`->'")); typ() } } else infixType() diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index a92095d9b..564ef21ef 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -114,7 +114,7 @@ class PlainPrinter(_ctx: Context) extends Printer { case _ => toTextGlobal(arg) } - /** The text for a TypeLambda + /** The text for a PolyType * * [v_1 p_1: B_1, ..., v_n p_n: B_n] -> T * @@ -124,7 +124,7 @@ class PlainPrinter(_ctx: Context) extends Printer { * @param argBoundss = B_1, ..., B_n * @param body = T */ - protected def typeLambdaText(paramNames: List[String], variances: List[Int], argBoundss: List[TypeBounds], body: Type): Text = { + protected def polyTypeText(paramNames: List[String], variances: List[Int], argBoundss: List[TypeBounds], body: Type): Text = { def lambdaParamText(variance: Int, name: String, bounds: TypeBounds): Text = varianceString(variance) ~ name ~ toText(bounds) changePrec(GlobalPrec) { @@ -185,16 +185,8 @@ class PlainPrinter(_ctx: Context) extends Printer { } case tp: ExprType => changePrec(GlobalPrec) { "=> " ~ toText(tp.resultType) } - case tp: TypeLambda => - typeLambdaText(tp.paramNames.map(_.toString), tp.variances, tp.paramBounds, tp.resultType) case tp: PolyType => - def paramText(name: TypeName, bounds: TypeBounds): Text = - polyParamNameString(name) ~ polyHash(tp) ~ toText(bounds) - changePrec(GlobalPrec) { - "[" ~ - Text((tp.paramNames, tp.paramBounds).zipped map paramText, ", ") ~ - "]" ~ toText(tp.resultType) - } + polyTypeText(tp.paramNames.map(_.toString), tp.variances, tp.paramBounds, tp.resultType) case tp: PolyParam => polyParamNameString(tp) ~ polyHash(tp.binder) case AnnotatedType(tpe, annot) => @@ -229,7 +221,7 @@ class PlainPrinter(_ctx: Context) extends Printer { protected def simpleNameString(sym: Symbol): String = nameString(sym.name) /** If -uniqid is set, the hashcode of the polytype, after a # */ - protected def polyHash(pt: GenericType): Text = + protected def polyHash(pt: PolyType): Text = if (ctx.settings.uniqid.value) "#" + pt.hashCode else "" /** If -uniqid is set, the unique id of symbol, after a # */ diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index b6deca52b..bcd12bc86 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -368,7 +368,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { toTextLocal(tpt) ~ " " ~ blockText(refines) case AppliedTypeTree(tpt, args) => toTextLocal(tpt) ~ "[" ~ Text(args map argText, ", ") ~ "]" - case TypeLambdaTree(tparams, body) => + case PolyTypeTree(tparams, body) => changePrec(GlobalPrec) { tparamsText(tparams) ~ " -> " ~ toText(body) } diff --git a/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/src/dotty/tools/dotc/sbt/ExtractAPI.scala index a7b18b6d6..bc8528c05 100644 --- a/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -363,7 +363,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder val apiTycon = simpleType(tycon) val apiArgs = args.map(processArg) new api.Parameterized(apiTycon, apiArgs.toArray) - case TypeLambda(tparams, res) => + case PolyType(tparams, res) => val apiTparams = tparams.map(apiTypeParameter) val apiRes = apiType(res) new api.Polymorphic(apiRes, apiTparams.toArray) diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index 1450ff832..258b7f234 100644 --- a/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -44,7 +44,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati } else paramTypes tp.derivedMethodType(paramNames, paramTypes1, resultType1) case tp: PolyType => - tp.derivedGenericType(tp.paramNames, tp.paramBounds, elimRepeated(tp.resultType)) + tp.derivedPolyType(tp.paramNames, tp.paramBounds, elimRepeated(tp.resultType)) case tp => tp } @@ -126,7 +126,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati /** Convert type from Scala to Java varargs method */ private def toJavaVarArgs(tp: Type)(implicit ctx: Context): Type = tp match { case tp: PolyType => - tp.derivedGenericType(tp.paramNames, tp.paramBounds, toJavaVarArgs(tp.resultType)) + tp.derivedPolyType(tp.paramNames, tp.paramBounds, toJavaVarArgs(tp.resultType)) case tp: MethodType => val inits :+ last = tp.paramTypes val last1 = last.underlyingIfRepeated(isJava = true) diff --git a/src/dotty/tools/dotc/transform/FullParameterization.scala b/src/dotty/tools/dotc/transform/FullParameterization.scala index d2052d8cb..6c69c735b 100644 --- a/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -111,13 +111,13 @@ trait FullParameterization { } /** Replace class type parameters by the added type parameters of the polytype `pt` */ - def mapClassParams(tp: Type, pt: GenericType): Type = { + def mapClassParams(tp: Type, pt: PolyType): Type = { val classParamsRange = (mtparamCount until mtparamCount + ctparams.length).toList tp.substDealias(ctparams, classParamsRange map (PolyParam(pt, _))) } /** The bounds for the added type parameters of the polytype `pt` */ - def mappedClassBounds(pt: GenericType): List[TypeBounds] = + def mappedClassBounds(pt: PolyType): List[TypeBounds] = ctparams.map(tparam => mapClassParams(tparam.info, pt).bounds) info match { diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index 79dbd9fe7..10be6db65 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -175,7 +175,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { val accType = { def accTypeOf(tpe: Type): Type = tpe match { case tpe: PolyType => - tpe.derivedGenericType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType)) + tpe.derivedPolyType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType)) case _ => MethodType(receiverType :: Nil)(mt => tpe.substThis(sym.owner.asClass, MethodParam(mt, 0))) } @@ -227,7 +227,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { else clazz.classInfo.selfType def accTypeOf(tpe: Type): Type = tpe match { case tpe: PolyType => - tpe.derivedGenericType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType)) + tpe.derivedPolyType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType)) case _ => MethodType(receiverType :: Nil)(mt => tpe.substThis(sym.owner.asClass, MethodParam(mt, 0))) } diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index e2779e758..56595a637 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -1019,7 +1019,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // todo: make sure implicit method types are not dependent? // but check test case in /tests/pos/depmet_implicit_chaining_zw.scala case pt: PolyType => - pt.derivedGenericType(pt.paramNames, pt.paramBounds, stripImplicit(pt.resultType)) + pt.derivedPolyType(pt.paramNames, pt.paramBounds, stripImplicit(pt.resultType)) case _ => tp } diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 3461facc1..7899174f5 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -52,7 +52,7 @@ object Checking { * Note: This does not check the bounds of AppliedTypeTrees. These * are handled by method checkBounds in FirstTransform */ - def checkBounds(args: List[tpd.Tree], poly: GenericType)(implicit ctx: Context): Unit = + def checkBounds(args: List[tpd.Tree], poly: PolyType)(implicit ctx: Context): Unit = checkBounds(args, poly.paramBounds, _.substParams(poly, _)) /** If type is a higher-kinded application with wildcard arguments, @@ -63,7 +63,7 @@ object Checking { def checkWildcardHKApply(tp: Type, pos: Position)(implicit ctx: Context): Unit = tp match { case tp @ HKApply(tycon, args) if args.exists(_.isInstanceOf[TypeBounds]) => tycon match { - case tycon: TypeLambda => + case tycon: PolyType => ctx.errorOrMigrationWarning( ex"unreducible application of higher-kinded type $tycon to wildcard arguments", pos) diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 6e3fe7630..d6cf7fb2b 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -302,7 +302,7 @@ trait ImplicitRunInfo { self: RunInfo => case _ => arg } (apply(tp.tycon) /: tp.args)((tc, arg) => AndType.make(tc, applyArg(arg))) - case tp: TypeLambda => + case tp: PolyType => apply(tp.resType) case _ => mapOver(tp) diff --git a/src/dotty/tools/dotc/typer/Inliner.scala b/src/dotty/tools/dotc/typer/Inliner.scala index d1c160a23..55008c0c5 100644 --- a/src/dotty/tools/dotc/typer/Inliner.scala +++ b/src/dotty/tools/dotc/typer/Inliner.scala @@ -108,7 +108,7 @@ object Inliner { // Add qualifier type as leading method argument to argument `tp` def addQualType(tp: Type): Type = tp match { - case tp: PolyType => tp.derivedGenericType(tp.paramNames, tp.paramBounds, addQualType(tp.resultType)) + case tp: PolyType => tp.derivedPolyType(tp.paramNames, tp.paramBounds, addQualType(tp.resultType)) case tp: ExprType => addQualType(tp.resultType) case tp => MethodType(qualType :: Nil, tp) } diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index 4fe2ea6bf..d451d6abd 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -316,7 +316,7 @@ object ProtoTypes { override def isMatchedBy(tp: Type)(implicit ctx: Context) = { def isInstantiatable(tp: Type) = tp.widen match { - case tp: GenericType => tp.paramNames.length == targs.length + case tp: PolyType => tp.paramNames.length == targs.length case _ => false } isInstantiatable(tp) || tp.member(nme.apply).hasAltWith(d => isInstantiatable(d.info)) diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index aecdcbee6..696ecfedb 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -360,7 +360,7 @@ trait TypeAssigner { if (gapBuf.isEmpty) resultType1 else { val gaps = gapBuf.toList - pt.derivedGenericType( + pt.derivedPolyType( gaps.map(paramNames), gaps.map(idx => transform(pt.paramBounds(idx)).bounds), resultType1) @@ -455,8 +455,8 @@ trait TypeAssigner { tree.withType(ownType) } - def assignType(tree: untpd.TypeLambdaTree, tparamDefs: List[TypeDef], body: Tree)(implicit ctx: Context) = - tree.withType(TypeLambda.fromSymbols(tparamDefs.map(_.symbol), body.tpe)) + def assignType(tree: untpd.PolyTypeTree, tparamDefs: List[TypeDef], body: Tree)(implicit ctx: Context) = + tree.withType(PolyType.fromSymbols(tparamDefs.map(_.symbol), body.tpe)) def assignType(tree: untpd.ByNameTypeTree, result: Tree)(implicit ctx: Context) = tree.withType(ExprType(result.tpe)) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index e423082d5..6be119319 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1061,12 +1061,12 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } - def typedTypeLambdaTree(tree: untpd.TypeLambdaTree)(implicit ctx: Context): Tree = track("typedTypeLambdaTree") { - val TypeLambdaTree(tparams, body) = tree + def typedPolyTypeTree(tree: untpd.PolyTypeTree)(implicit ctx: Context): Tree = track("typedPolyTypeTree") { + val PolyTypeTree(tparams, body) = tree index(tparams) val tparams1 = tparams.mapconserve(typed(_).asInstanceOf[TypeDef]) val body1 = typedType(tree.body) - assignType(cpy.TypeLambdaTree(tree)(tparams1, body1), tparams1, body1) + assignType(cpy.PolyTypeTree(tree)(tparams1, body1), tparams1, body1) } def typedByNameTypeTree(tree: untpd.ByNameTypeTree)(implicit ctx: Context): ByNameTypeTree = track("typedByNameTypeTree") { @@ -1469,7 +1469,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case tree: untpd.OrTypeTree => typedOrTypeTree(tree) case tree: untpd.RefinedTypeTree => typedRefinedTypeTree(tree) case tree: untpd.AppliedTypeTree => typedAppliedTypeTree(tree) - case tree: untpd.TypeLambdaTree => typedTypeLambdaTree(tree)(localContext(tree, NoSymbol).setNewScope) + case tree: untpd.PolyTypeTree => typedPolyTypeTree(tree)(localContext(tree, NoSymbol).setNewScope) case tree: untpd.ByNameTypeTree => typedByNameTypeTree(tree) case tree: untpd.TypeBoundsTree => typedTypeBoundsTree(tree) case tree: untpd.Alternative => typedAlternative(tree, pt) @@ -1921,7 +1921,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case _ => adaptOverloaded(ref) } - case poly: PolyType => + case poly: PolyType if !(ctx.mode is Mode.Type) => if (pt.isInstanceOf[PolyProto]) tree else { var typeArgs = tree match { diff --git a/src/dotty/tools/dotc/typer/Variances.scala b/src/dotty/tools/dotc/typer/Variances.scala index a8abe5e30..92bd9fd74 100644 --- a/src/dotty/tools/dotc/typer/Variances.scala +++ b/src/dotty/tools/dotc/typer/Variances.scala @@ -94,7 +94,7 @@ object Variances { v } varianceInArgs(varianceInType(tycon)(tparam), args, tycon.typeParams) - case tp: GenericType => + case tp: PolyType => flip(varianceInTypes(tp.paramBounds)(tparam)) & varianceInType(tp.resultType)(tparam) case AnnotatedType(tp, annot) => varianceInType(tp)(tparam) & varianceInAnnot(annot)(tparam) -- cgit v1.2.3