Skip to content

Commit 3d6da69

Browse files
committed
Harmonize PolyType and TypeLambda
Let them inherit the same traits and push as much functionality as possibly into the common superclass GenericType.
1 parent f16adc3 commit 3d6da69

12 files changed

+89
-84
lines changed

src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ class TypeApplications(val self: Type) extends AnyVal {
485485
// In this case we should always dealias since we cannot handle
486486
// higher-kinded applications to wildcard arguments.
487487
dealiased
488-
.derivedTypeLambda(resType = tycon.safeDealias.appliedTo(args1))
488+
.derivedGenericType(resType = tycon.safeDealias.appliedTo(args1))
489489
.appliedTo(args)
490490
case _ =>
491491
val reducer = new Reducer(dealiased, args)

src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1331,7 +1331,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
13311331
case tp1: PolyType =>
13321332
tp2 match {
13331333
case tp2: PolyType if matchingTypeParams(tp1, tp2) =>
1334-
tp1.derivedPolyType(
1334+
tp1.derivedGenericType(
13351335
mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
13361336
tp1.paramBounds, tp1.resultType & tp2.resultType.subst(tp2, tp1))
13371337
case _ =>

src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ object TypeErasure {
169169
val erase = erasureFn(isJava, semiEraseVCs, sym.isConstructor, wildcardOK = false)
170170

171171
def eraseParamBounds(tp: PolyType): Type =
172-
tp.derivedPolyType(
172+
tp.derivedGenericType(
173173
tp.paramNames, tp.paramNames map (Function.const(TypeBounds.upper(defn.ObjectType))), tp.resultType)
174174

175175
if (defn.isPolymorphicAfterErasure(sym)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
@@ -356,8 +356,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
356356
SuperType(this(thistpe), this(supertpe))
357357
case ExprType(rt) =>
358358
defn.FunctionClass(0).typeRef
359-
case tp: TypeProxy =>
360-
this(tp.underlying)
361359
case AndType(tp1, tp2) =>
362360
erasedGlb(this(tp1), this(tp2), isJava)
363361
case OrType(tp1, tp2) =>
@@ -398,6 +396,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
398396
tp
399397
case tp: WildcardType if wildcardOK =>
400398
tp
399+
case tp: TypeProxy =>
400+
this(tp.underlying)
401401
}
402402

403403
private def eraseArray(tp: RefinedType)(implicit ctx: Context) = {

src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
136136
finally seen = saved
137137
}
138138
case _ =>
139-
if (tp.isInstanceOf[MethodicType]) assert(variance != 0, tp)
140139
mapOver(tp)
141140
}
142141
}

src/dotty/tools/dotc/core/Types.scala

Lines changed: 63 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2508,24 +2508,24 @@ object Types {
25082508
}
25092509

25102510
/** A common supertrait of PolyType and TypeLambda */
2511-
trait GenericType extends BindingType with TermType {
2512-
2513-
/** The names of the type parameters */
2514-
val paramNames: List[TypeName]
2511+
abstract class GenericType(val paramNames: List[TypeName])
2512+
(paramBoundsExp: GenericType => List[TypeBounds],
2513+
resultTypeExp: GenericType => Type)
2514+
extends CachedProxyType with BindingType with TermType {
2515+
type This <: GenericType
2516+
protected[this] def companion: GenericCompanion[This]
25152517

25162518
/** The bounds of the type parameters */
2517-
val paramBounds: List[TypeBounds]
2519+
val paramBounds: List[TypeBounds] = paramBoundsExp(this)
25182520

25192521
/** The result type of a PolyType / body of a type lambda */
2520-
val resType: Type
2522+
val resType: Type = resultTypeExp(this)
25212523

25222524
/** If this is a type lambda, the variances of its parameters, otherwise Nil.*/
2523-
def variances: List[Int]
2525+
def variances: List[Int] = Nil
25242526

25252527
override def resultType(implicit ctx: Context) = resType
2526-
2527-
/** Unconditionally create a new generic type like this one with given elements */
2528-
def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): GenericType
2528+
override def underlying(implicit ctx: Context) = resType
25292529

25302530
/** Instantiate result type by substituting parameters with given arguments */
25312531
final def instantiate(argTypes: List[Type])(implicit ctx: Context): Type =
@@ -2535,9 +2535,17 @@ object Types {
25352535
def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[TypeBounds] =
25362536
paramBounds.mapConserve(_.substParams(this, argTypes).bounds)
25372537

2538-
def derivedGenericType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context) =
2538+
/** Unconditionally create a new generic type like this one with given elements */
2539+
def newLikeThis(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): This =
2540+
companion.apply(paramNames, variances)(
2541+
x => paramBounds mapConserve (_.subst(this, x).bounds),
2542+
x => resType.subst(this, x))
2543+
2544+
def derivedGenericType(paramNames: List[TypeName] = this.paramNames,
2545+
paramBounds: List[TypeBounds] = this.paramBounds,
2546+
resType: Type = this.resType)(implicit ctx: Context) =
25392547
if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (resType eq this.resType)) this
2540-
else duplicate(paramNames, paramBounds, resType)
2548+
else newLikeThis(paramNames, paramBounds, resType)
25412549

25422550
/** PolyParam references to all type parameters of this type */
25432551
lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _))
@@ -2559,14 +2567,28 @@ object Types {
25592567
other.variances == this.variances
25602568
case _ => false
25612569
}
2570+
2571+
override def computeHash = doHash(variances ::: paramNames, resType, paramBounds)
2572+
}
2573+
2574+
abstract class GenericCompanion[GT <: GenericType] {
2575+
def apply(paramNames: List[TypeName], variances: List[Int])(
2576+
paramBoundsExp: GenericType => List[TypeBounds],
2577+
resultTypeExp: GenericType => Type)(implicit ctx: Context): GT
2578+
2579+
def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context): Type =
2580+
if (tparams.isEmpty) resultType
2581+
else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))(
2582+
pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds),
2583+
pt => pt.lifted(tparams, resultType))
25622584
}
25632585

25642586
/** A type for polymorphic methods */
2565-
class PolyType(val paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
2566-
extends CachedGroundType with GenericType with MethodOrPoly {
2567-
val paramBounds: List[TypeBounds] = paramBoundsExp(this)
2568-
val resType: Type = resultTypeExp(this)
2569-
def variances = Nil
2587+
class PolyType(paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
2588+
extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) with MethodOrPoly {
2589+
2590+
type This = PolyType
2591+
def companion = PolyType
25702592

25712593
protected def computeSignature(implicit ctx: Context) = resultSignature
25722594

@@ -2575,14 +2597,6 @@ object Types {
25752597
case _ => false
25762598
}
25772599

2578-
def derivedPolyType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType =
2579-
derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[PolyType]
2580-
2581-
def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): PolyType =
2582-
PolyType(paramNames)(
2583-
x => paramBounds mapConserve (_.subst(this, x).bounds),
2584-
x => resType.subst(this, x))
2585-
25862600
/** Merge nested polytypes into one polytype. nested polytypes are normally not supported
25872601
* but can arise as temporary data structures.
25882602
*/
@@ -2602,61 +2616,58 @@ object Types {
26022616
}
26032617

26042618
override def toString = s"PolyType($paramNames, $paramBounds, $resType)"
2605-
2606-
override def computeHash = doHash(paramNames, resType, paramBounds)
26072619
}
26082620

2609-
object PolyType {
2610-
def apply(paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): PolyType = {
2621+
object PolyType extends GenericCompanion[PolyType] {
2622+
def apply(paramNames: List[TypeName], variances: List[Int] = Nil)(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): PolyType = {
26112623
unique(new PolyType(paramNames)(paramBoundsExp, resultTypeExp))
26122624
}
2613-
2614-
def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) =
2615-
if (tparams.isEmpty) resultType
2616-
else apply(tparams map (_.name.asTypeName))(
2617-
pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds),
2618-
pt => pt.lifted(tparams, resultType))
26192625
}
26202626

26212627
// ----- HK types: TypeLambda, LambdaParam, HKApply ---------------------
26222628

26232629
/** A type lambda of the form `[v_0 X_0, ..., v_n X_n] => T` */
2624-
class TypeLambda(val paramNames: List[TypeName], val variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
2625-
extends CachedProxyType with GenericType with ValueType {
2626-
val paramBounds = paramBoundsExp(this)
2627-
val resType = resultTypeExp(this)
2630+
class TypeLambda(paramNames: List[TypeName], override val variances: List[Int])(
2631+
paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
2632+
extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) {
26282633

26292634
assert(resType.isInstanceOf[TermType], this)
26302635
assert(paramNames.nonEmpty)
26312636

2632-
override def underlying(implicit ctx: Context) = resType
2637+
type This = TypeLambda
2638+
def companion = TypeLambda
26332639

26342640
lazy val typeParams: List[LambdaParam] =
26352641
paramNames.indices.toList.map(new LambdaParam(this, _))
26362642

26372643
def derivedLambdaAbstraction(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type =
26382644
resType match {
26392645
case resType @ TypeAlias(alias) =>
2640-
resType.derivedTypeAlias(duplicate(paramNames, paramBounds, alias))
2646+
resType.derivedTypeAlias(newLikeThis(paramNames, paramBounds, alias))
26412647
case resType @ TypeBounds(lo, hi) =>
26422648
resType.derivedTypeBounds(
2643-
if (lo.isRef(defn.NothingClass)) lo else duplicate(paramNames, paramBounds, lo),
2644-
duplicate(paramNames, paramBounds, hi))
2649+
if (lo.isRef(defn.NothingClass)) lo else newLikeThis(paramNames, paramBounds, lo),
2650+
newLikeThis(paramNames, paramBounds, hi))
26452651
case _ =>
2646-
derivedTypeLambda(paramNames, paramBounds, resType)
2652+
derivedGenericType(paramNames, paramBounds, resType)
26472653
}
26482654

2649-
def derivedTypeLambda(paramNames: List[TypeName] = paramNames, paramBounds: List[TypeBounds] = paramBounds, resType: Type)(implicit ctx: Context): TypeLambda =
2650-
derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[TypeLambda]
2655+
override def toString = s"TypeLambda($variances, $paramNames, $paramBounds, $resType)"
2656+
}
26512657

2652-
def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): TypeLambda =
2653-
TypeLambda(paramNames, variances)(
2654-
x => paramBounds mapConserve (_.subst(this, x).bounds),
2655-
x => resType.subst(this, x))
2658+
object TypeLambda extends GenericCompanion[TypeLambda] {
2659+
def apply(paramNames: List[TypeName], variances: List[Int])(
2660+
paramBoundsExp: GenericType => List[TypeBounds],
2661+
resultTypeExp: GenericType => Type)(implicit ctx: Context): TypeLambda = {
2662+
unique(new TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp))
2663+
}
26562664

2657-
override def toString = s"TypeLambda($variances, $paramNames, $paramBounds, $resType)"
2665+
def unapply(tl: TypeLambda): Some[(List[LambdaParam], Type)] =
2666+
Some((tl.typeParams, tl.resType))
26582667

2659-
override def computeHash = doHash(variances ::: paramNames, resType, paramBounds)
2668+
def any(n: Int)(implicit ctx: Context) =
2669+
apply(tpnme.syntheticLambdaParamNames(n), List.fill(n)(0))(
2670+
pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType)
26602671
}
26612672

26622673
/** The parameter of a type lambda */
@@ -2671,24 +2682,6 @@ object Types {
26712682
def paramRef(implicit ctx: Context): Type = PolyParam(tl, n)
26722683
}
26732684

2674-
object TypeLambda {
2675-
def apply(paramNames: List[TypeName], variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): TypeLambda = {
2676-
unique(new TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp))
2677-
}
2678-
2679-
def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) =
2680-
if (tparams.isEmpty) resultType
2681-
else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))(
2682-
pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds),
2683-
pt => pt.lifted(tparams, resultType))
2684-
def unapply(tl: TypeLambda): Some[(List[LambdaParam], Type)] =
2685-
Some((tl.typeParams, tl.resType))
2686-
2687-
def any(n: Int)(implicit ctx: Context) =
2688-
apply(tpnme.syntheticLambdaParamNames(n), List.fill(n)(0))(
2689-
pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType)
2690-
}
2691-
26922685
/** A higher kinded type application `C[T_1, ..., T_n]` */
26932686
abstract case class HKApply(tycon: Type, args: List[Type])
26942687
extends CachedProxyType with ValueType {

src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ object Scala2Unpickler {
8484
paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp),
8585
tp.resultType)
8686
case tp: PolyType =>
87-
tp.derivedPolyType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType))
87+
tp.derivedGenericType(tp.paramNames, tp.paramBounds, arrayToRepeated(tp.resultType))
8888
}
8989

9090
def ensureConstructor(cls: ClassSymbol, scope: Scope)(implicit ctx: Context) =

src/dotty/tools/dotc/transform/ElimRepeated.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati
4444
} else paramTypes
4545
tp.derivedMethodType(paramNames, paramTypes1, resultType1)
4646
case tp: PolyType =>
47-
tp.derivedPolyType(tp.paramNames, tp.paramBounds, elimRepeated(tp.resultType))
47+
tp.derivedGenericType(tp.paramNames, tp.paramBounds, elimRepeated(tp.resultType))
4848
case tp =>
4949
tp
5050
}
@@ -126,7 +126,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati
126126
/** Convert type from Scala to Java varargs method */
127127
private def toJavaVarArgs(tp: Type)(implicit ctx: Context): Type = tp match {
128128
case tp: PolyType =>
129-
tp.derivedPolyType(tp.paramNames, tp.paramBounds, toJavaVarArgs(tp.resultType))
129+
tp.derivedGenericType(tp.paramNames, tp.paramBounds, toJavaVarArgs(tp.resultType))
130130
case tp: MethodType =>
131131
val inits :+ last = tp.paramTypes
132132
val last1 = last.underlyingIfRepeated(isJava = true)

src/dotty/tools/dotc/transform/SuperAccessors.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) {
175175
val accType = {
176176
def accTypeOf(tpe: Type): Type = tpe match {
177177
case tpe: PolyType =>
178-
tpe.derivedPolyType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType))
178+
tpe.derivedGenericType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType))
179179
case _ =>
180180
MethodType(receiverType :: Nil)(mt => tpe.substThis(sym.owner.asClass, MethodParam(mt, 0)))
181181
}
@@ -227,7 +227,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) {
227227
else clazz.classInfo.selfType
228228
def accTypeOf(tpe: Type): Type = tpe match {
229229
case tpe: PolyType =>
230-
tpe.derivedPolyType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType))
230+
tpe.derivedGenericType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType))
231231
case _ =>
232232
MethodType(receiverType :: Nil)(mt => tpe.substThis(sym.owner.asClass, MethodParam(mt, 0)))
233233
}

src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
10181018
// todo: make sure implicit method types are not dependent?
10191019
// but check test case in /tests/pos/depmet_implicit_chaining_zw.scala
10201020
case pt: PolyType =>
1021-
pt.derivedPolyType(pt.paramNames, pt.paramBounds, stripImplicit(pt.resultType))
1021+
pt.derivedGenericType(pt.paramNames, pt.paramBounds, stripImplicit(pt.resultType))
10221022
case _ =>
10231023
tp
10241024
}

src/dotty/tools/dotc/typer/ProtoTypes.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ object ProtoTypes {
358358
yield new TypeVar(PolyParam(pt, n), state, owningTree, ctx.owner)
359359

360360
val added =
361-
if (state.constraint contains pt) pt.duplicate(pt.paramNames, pt.paramBounds, pt.resultType)
361+
if (state.constraint contains pt) pt.newLikeThis(pt.paramNames, pt.paramBounds, pt.resultType)
362362
else pt
363363
val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added)
364364
ctx.typeComparer.addToConstraint(added, tvars)

src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ trait TypeAssigner {
358358
if (gapBuf.isEmpty) resultType1
359359
else {
360360
val gaps = gapBuf.toList
361-
pt.derivedPolyType(
361+
pt.derivedGenericType(
362362
gaps.map(paramNames),
363363
gaps.map(idx => transform(pt.paramBounds(idx)).bounds),
364364
resultType1)

tests/pos/sams.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,16 @@ class T {
7373
def app[T, U](x: T)(f: F[T, U]): U = f(x)
7474
app(1)(x => List(x))
7575
}
76+
77+
object SI9943 {
78+
79+
class Foo[T] {
80+
def toMap[K, V](implicit ev: Foo[T] <:< Foo[(K, V)]): Foo[Map[K, V]] = null
81+
def toMap[K](keySelector: T => K): Foo[Map[K, T]] = null
82+
}
83+
84+
object Foo {
85+
val f: Foo[Int] = null
86+
val m = f.toMap(_ % 2)
87+
}
88+
}

0 commit comments

Comments
 (0)