Skip to content

Commit 92b891f

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 4ab0c68 commit 92b891f

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
@@ -2482,24 +2482,24 @@ object Types {
24822482
}
24832483

24842484
/** A common supertrait of PolyType and TypeLambda */
2485-
trait GenericType extends BindingType with TermType {
2486-
2487-
/** The names of the type parameters */
2488-
val paramNames: List[TypeName]
2485+
abstract class GenericType(val paramNames: List[TypeName])
2486+
(paramBoundsExp: GenericType => List[TypeBounds],
2487+
resultTypeExp: GenericType => Type)
2488+
extends CachedProxyType with BindingType with TermType {
2489+
type This <: GenericType
2490+
protected[this] def companion: GenericCompanion[This]
24892491

24902492
/** The bounds of the type parameters */
2491-
val paramBounds: List[TypeBounds]
2493+
val paramBounds: List[TypeBounds] = paramBoundsExp(this)
24922494

24932495
/** The result type of a PolyType / body of a type lambda */
2494-
val resType: Type
2496+
val resType: Type = resultTypeExp(this)
24952497

24962498
/** If this is a type lambda, the variances of its parameters, otherwise Nil.*/
2497-
def variances: List[Int]
2499+
def variances: List[Int] = Nil
24982500

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

25042504
/** Instantiate result type by substituting parameters with given arguments */
25052505
final def instantiate(argTypes: List[Type])(implicit ctx: Context): Type =
@@ -2509,9 +2509,17 @@ object Types {
25092509
def instantiateBounds(argTypes: List[Type])(implicit ctx: Context): List[TypeBounds] =
25102510
paramBounds.mapConserve(_.substParams(this, argTypes).bounds)
25112511

2512-
def derivedGenericType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context) =
2512+
/** Unconditionally create a new generic type like this one with given elements */
2513+
def newLikeThis(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): This =
2514+
companion.apply(paramNames, variances)(
2515+
x => paramBounds mapConserve (_.subst(this, x).bounds),
2516+
x => resType.subst(this, x))
2517+
2518+
def derivedGenericType(paramNames: List[TypeName] = this.paramNames,
2519+
paramBounds: List[TypeBounds] = this.paramBounds,
2520+
resType: Type = this.resType)(implicit ctx: Context) =
25132521
if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (resType eq this.resType)) this
2514-
else duplicate(paramNames, paramBounds, resType)
2522+
else newLikeThis(paramNames, paramBounds, resType)
25152523

25162524
/** PolyParam references to all type parameters of this type */
25172525
lazy val paramRefs: List[PolyParam] = paramNames.indices.toList.map(PolyParam(this, _))
@@ -2533,14 +2541,28 @@ object Types {
25332541
other.variances == this.variances
25342542
case _ => false
25352543
}
2544+
2545+
override def computeHash = doHash(variances ::: paramNames, resType, paramBounds)
2546+
}
2547+
2548+
abstract class GenericCompanion[GT <: GenericType] {
2549+
def apply(paramNames: List[TypeName], variances: List[Int])(
2550+
paramBoundsExp: GenericType => List[TypeBounds],
2551+
resultTypeExp: GenericType => Type)(implicit ctx: Context): GT
2552+
2553+
def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context): Type =
2554+
if (tparams.isEmpty) resultType
2555+
else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))(
2556+
pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds),
2557+
pt => pt.lifted(tparams, resultType))
25362558
}
25372559

25382560
/** A type for polymorphic methods */
2539-
class PolyType(val paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
2540-
extends CachedGroundType with GenericType with MethodOrPoly {
2541-
val paramBounds: List[TypeBounds] = paramBoundsExp(this)
2542-
val resType: Type = resultTypeExp(this)
2543-
def variances = Nil
2561+
class PolyType(paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
2562+
extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) with MethodOrPoly {
2563+
2564+
type This = PolyType
2565+
def companion = PolyType
25442566

25452567
protected def computeSignature(implicit ctx: Context) = resultSignature
25462568

@@ -2549,70 +2571,59 @@ object Types {
25492571
case _ => false
25502572
}
25512573

2552-
def derivedPolyType(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): PolyType =
2553-
derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[PolyType]
2554-
2555-
def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): PolyType =
2556-
PolyType(paramNames)(
2557-
x => paramBounds mapConserve (_.subst(this, x).bounds),
2558-
x => resType.subst(this, x))
2559-
25602574
override def toString = s"PolyType($paramNames, $paramBounds, $resType)"
2561-
2562-
override def computeHash = doHash(paramNames, resType, paramBounds)
25632575
}
25642576

2565-
object PolyType {
2566-
def apply(paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): PolyType = {
2577+
object PolyType extends GenericCompanion[PolyType] {
2578+
def apply(paramNames: List[TypeName], variances: List[Int] = Nil)(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): PolyType = {
25672579
unique(new PolyType(paramNames)(paramBoundsExp, resultTypeExp))
25682580
}
2569-
2570-
def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) =
2571-
if (tparams.isEmpty) resultType
2572-
else apply(tparams map (_.name.asTypeName))(
2573-
pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds),
2574-
pt => pt.lifted(tparams, resultType))
25752581
}
25762582

25772583
// ----- HK types: TypeLambda, LambdaParam, HKApply ---------------------
25782584

25792585
/** A type lambda of the form `[v_0 X_0, ..., v_n X_n] => T` */
2580-
class TypeLambda(val paramNames: List[TypeName], val variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
2581-
extends CachedProxyType with GenericType with ValueType {
2582-
val paramBounds = paramBoundsExp(this)
2583-
val resType = resultTypeExp(this)
2586+
class TypeLambda(paramNames: List[TypeName], override val variances: List[Int])(
2587+
paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
2588+
extends GenericType(paramNames)(paramBoundsExp, resultTypeExp) {
25842589

25852590
assert(resType.isInstanceOf[TermType], this)
25862591
assert(paramNames.nonEmpty)
25872592

2588-
override def underlying(implicit ctx: Context) = resType
2593+
type This = TypeLambda
2594+
def companion = TypeLambda
25892595

25902596
lazy val typeParams: List[LambdaParam] =
25912597
paramNames.indices.toList.map(new LambdaParam(this, _))
25922598

25932599
def derivedLambdaAbstraction(paramNames: List[TypeName], paramBounds: List[TypeBounds], resType: Type)(implicit ctx: Context): Type =
25942600
resType match {
25952601
case resType @ TypeAlias(alias) =>
2596-
resType.derivedTypeAlias(duplicate(paramNames, paramBounds, alias))
2602+
resType.derivedTypeAlias(newLikeThis(paramNames, paramBounds, alias))
25972603
case resType @ TypeBounds(lo, hi) =>
25982604
resType.derivedTypeBounds(
2599-
if (lo.isRef(defn.NothingClass)) lo else duplicate(paramNames, paramBounds, lo),
2600-
duplicate(paramNames, paramBounds, hi))
2605+
if (lo.isRef(defn.NothingClass)) lo else newLikeThis(paramNames, paramBounds, lo),
2606+
newLikeThis(paramNames, paramBounds, hi))
26012607
case _ =>
2602-
derivedTypeLambda(paramNames, paramBounds, resType)
2608+
derivedGenericType(paramNames, paramBounds, resType)
26032609
}
26042610

2605-
def derivedTypeLambda(paramNames: List[TypeName] = paramNames, paramBounds: List[TypeBounds] = paramBounds, resType: Type)(implicit ctx: Context): TypeLambda =
2606-
derivedGenericType(paramNames, paramBounds, resType).asInstanceOf[TypeLambda]
2611+
override def toString = s"TypeLambda($variances, $paramNames, $paramBounds, $resType)"
2612+
}
26072613

2608-
def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, resType: Type)(implicit ctx: Context): TypeLambda =
2609-
TypeLambda(paramNames, variances)(
2610-
x => paramBounds mapConserve (_.subst(this, x).bounds),
2611-
x => resType.subst(this, x))
2614+
object TypeLambda extends GenericCompanion[TypeLambda] {
2615+
def apply(paramNames: List[TypeName], variances: List[Int])(
2616+
paramBoundsExp: GenericType => List[TypeBounds],
2617+
resultTypeExp: GenericType => Type)(implicit ctx: Context): TypeLambda = {
2618+
unique(new TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp))
2619+
}
26122620

2613-
override def toString = s"TypeLambda($variances, $paramNames, $paramBounds, $resType)"
2621+
def unapply(tl: TypeLambda): Some[(List[LambdaParam], Type)] =
2622+
Some((tl.typeParams, tl.resType))
26142623

2615-
override def computeHash = doHash(variances ::: paramNames, resType, paramBounds)
2624+
def any(n: Int)(implicit ctx: Context) =
2625+
apply(tpnme.syntheticLambdaParamNames(n), List.fill(n)(0))(
2626+
pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType)
26162627
}
26172628

26182629
/** The parameter of a type lambda */
@@ -2627,24 +2638,6 @@ object Types {
26272638
def paramRef(implicit ctx: Context): Type = PolyParam(tl, n)
26282639
}
26292640

2630-
object TypeLambda {
2631-
def apply(paramNames: List[TypeName], variances: List[Int])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)(implicit ctx: Context): TypeLambda = {
2632-
unique(new TypeLambda(paramNames, variances)(paramBoundsExp, resultTypeExp))
2633-
}
2634-
2635-
def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) =
2636-
if (tparams.isEmpty) resultType
2637-
else apply(tparams map (_.name.asTypeName), tparams.map(_.variance))(
2638-
pt => tparams.map(tparam => pt.lifted(tparams, tparam.info).bounds),
2639-
pt => pt.lifted(tparams, resultType))
2640-
def unapply(tl: TypeLambda): Some[(List[LambdaParam], Type)] =
2641-
Some((tl.typeParams, tl.resType))
2642-
2643-
def any(n: Int)(implicit ctx: Context) =
2644-
apply(tpnme.syntheticLambdaParamNames(n), List.fill(n)(0))(
2645-
pt => List.fill(n)(TypeBounds.empty), pt => defn.AnyType)
2646-
}
2647-
26482641
/** A higher kinded type application `C[T_1, ..., T_n]` */
26492642
abstract case class HKApply(tycon: Type, args: List[Type])
26502643
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
@@ -355,7 +355,7 @@ trait TypeAssigner {
355355
if (gapBuf.isEmpty) resultType1
356356
else {
357357
val gaps = gapBuf.toList
358-
pt.derivedPolyType(
358+
pt.derivedGenericType(
359359
gaps.map(paramNames),
360360
gaps.map(idx => transform(pt.paramBounds(idx)).bounds),
361361
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)