Skip to content

Commit c5d58c7

Browse files
oderskysmarter
authored andcommitted
Harmonize PolyType and TypeLambda
Let them inherit the same traits and push as much functionality as possibly into the common superclass GenericType.
1 parent 3f7307d commit c5d58c7

File tree

12 files changed

+89
-84
lines changed

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
@@ -1019,7 +1019,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
10191019
// todo: make sure implicit method types are not dependent?
10201020
// but check test case in /tests/pos/depmet_implicit_chaining_zw.scala
10211021
case pt: PolyType =>
1022-
pt.derivedPolyType(pt.paramNames, pt.paramBounds, stripImplicit(pt.resultType))
1022+
pt.derivedGenericType(pt.paramNames, pt.paramBounds, stripImplicit(pt.resultType))
10231023
case _ =>
10241024
tp
10251025
}

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
@@ -360,7 +360,7 @@ trait TypeAssigner {
360360
if (gapBuf.isEmpty) resultType1
361361
else {
362362
val gaps = gapBuf.toList
363-
pt.derivedPolyType(
363+
pt.derivedGenericType(
364364
gaps.map(paramNames),
365365
gaps.map(idx => transform(pt.paramBounds(idx)).bounds),
366366
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)