Skip to content

Commit 97afadf

Browse files
authored
Admit parametric aliases of classes in parent typing (#18849)
When typing parent types as constructors with implicitly added `()` arguments, also admit alias types that become classes after eta-collapsing. Fixes #18623
2 parents f91e5d8 + 257a10c commit 97afadf

File tree

10 files changed

+54
-14
lines changed

10 files changed

+54
-14
lines changed

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ object TypeApplications {
3636

3737
def apply(tycon: Type)(using Context): Type =
3838
assert(tycon.typeParams.nonEmpty, tycon)
39-
tycon.EtaExpand(tycon.typeParamSymbols)
39+
tycon.etaExpand(tycon.typeParamSymbols)
4040

4141
/** Test that the parameter bounds in a hk type lambda `[X1,...,Xn] => C[X1, ..., Xn]`
4242
* contain the bounds of the type parameters of `C`. This is necessary to be able to
@@ -71,7 +71,7 @@ object TypeApplications {
7171
*/
7272
def EtaExpandIfHK(tparams: List[TypeParamInfo], args: List[Type])(using Context): List[Type] =
7373
if (tparams.isEmpty) args
74-
else args.zipWithConserve(tparams)((arg, tparam) => arg.EtaExpandIfHK(tparam.paramInfoOrCompleter))
74+
else args.zipWithConserve(tparams)((arg, tparam) => arg.etaExpandIfHK(tparam.paramInfoOrCompleter))
7575

7676
/** A type map that tries to reduce (part of) the result type of the type lambda `tycon`
7777
* with the given `args`(some of which are wildcard arguments represented by type bounds).
@@ -245,7 +245,7 @@ class TypeApplications(val self: Type) extends AnyVal {
245245
def topType(using Context): Type =
246246
if self.hasSimpleKind then
247247
defn.AnyType
248-
else EtaExpand(self.typeParams) match
248+
else etaExpand(self.typeParams) match
249249
case tp: HKTypeLambda =>
250250
tp.derivedLambdaType(resType = tp.resultType.topType)
251251
case _ =>
@@ -302,7 +302,7 @@ class TypeApplications(val self: Type) extends AnyVal {
302302
/** Convert a type constructor `TC` which has type parameters `X1, ..., Xn`
303303
* to `[X1, ..., Xn] -> TC[X1, ..., Xn]`.
304304
*/
305-
def EtaExpand(tparams: List[TypeParamInfo])(using Context): Type =
305+
def etaExpand(tparams: List[TypeParamInfo])(using Context): Type =
306306
HKTypeLambda.fromParams(tparams, self.appliedTo(tparams.map(_.paramRef)))
307307
//.ensuring(res => res.EtaReduce =:= self, s"res = $res, core = ${res.EtaReduce}, self = $self, hc = ${res.hashCode}")
308308

@@ -311,7 +311,7 @@ class TypeApplications(val self: Type) extends AnyVal {
311311
if (isLambdaSub) self else EtaExpansion(self)
312312

313313
/** Eta expand if `self` is a (non-lambda) class reference and `bound` is a higher-kinded type */
314-
def EtaExpandIfHK(bound: Type)(using Context): Type = {
314+
def etaExpandIfHK(bound: Type)(using Context): Type = {
315315
val hkParams = bound.hkTypeParams
316316
if (hkParams.isEmpty) self
317317
else self match {
@@ -321,6 +321,11 @@ class TypeApplications(val self: Type) extends AnyVal {
321321
}
322322
}
323323

324+
/** Maps [Ts] => C[Ts] to C */
325+
def etaCollapse(using Context): Type = self match
326+
case EtaExpansion(classType) => classType
327+
case _ => self
328+
324329
/** The type representing
325330
*
326331
* T[U1, ..., Un]

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
746746
case _ =>
747747
val tparams1 = tp1.typeParams
748748
if (tparams1.nonEmpty)
749-
return recur(tp1.EtaExpand(tparams1), tp2) || fourthTry
749+
return recur(tp1.etaExpand(tparams1), tp2) || fourthTry
750750
tp2 match {
751751
case EtaExpansion(tycon2: TypeRef) if tycon2.symbol.isClass && tycon2.symbol.is(JavaDefined) =>
752752
recur(tp1, tycon2) || fourthTry

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
832832
}
833833
else if args.nonEmpty then
834834
tycon.safeAppliedTo(EtaExpandIfHK(sym.typeParams, args.map(translateTempPoly)))
835-
else if (sym.typeParams.nonEmpty) tycon.EtaExpand(sym.typeParams)
835+
else if (sym.typeParams.nonEmpty) tycon.etaExpand(sym.typeParams)
836836
else tycon
837837
case TYPEBOUNDStpe =>
838838
val lo = readTypeRef()

compiler/src/dotty/tools/dotc/typer/Deriving.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ trait Deriving {
165165
// case (a) ... see description above
166166
val derivedParams = clsParams.dropRight(instanceArity)
167167
val instanceType =
168-
if (instanceArity == clsArity) clsType.EtaExpand(clsParams)
168+
if (instanceArity == clsArity) clsType.etaExpand(clsParams)
169169
else {
170170
val derivedParamTypes = derivedParams.map(_.typeRef)
171171

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,7 +1197,7 @@ class Namer { typer: Typer =>
11971197
val forwarderName = checkNoConflict(alias.toTypeName, isPrivate = false, span)
11981198
var target = pathType.select(sym)
11991199
if target.typeParams.nonEmpty then
1200-
target = target.EtaExpand(target.typeParams)
1200+
target = target.etaExpand(target.typeParams)
12011201
newSymbol(
12021202
cls, forwarderName,
12031203
Exported | Final,
@@ -1518,7 +1518,7 @@ class Namer { typer: Typer =>
15181518

15191519
def typedParentType(tree: untpd.Tree): tpd.Tree =
15201520
val parentTpt = typer.typedType(parent, AnyTypeConstructorProto)
1521-
val ptpe = parentTpt.tpe
1521+
val ptpe = parentTpt.tpe.dealias.etaCollapse
15221522
if ptpe.typeParams.nonEmpty
15231523
&& ptpe.underlyingClassRef(refinementOK = false).exists
15241524
then

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ object RefChecks {
372372
*/
373373
def checkOverride(checkSubType: (Type, Type) => Context ?=> Boolean, member: Symbol, other: Symbol): Unit =
374374
def memberTp(self: Type) =
375-
if (member.isClass) TypeAlias(member.typeRef.EtaExpand(member.typeParams))
375+
if (member.isClass) TypeAlias(member.typeRef.etaExpand(member.typeParams))
376376
else self.memberInfo(member)
377377
def otherTp(self: Type) =
378378
self.memberInfo(other)

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4306,7 +4306,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
43064306
AppliedType(tree.tpe, tp.typeParams.map(Function.const(TypeBounds.empty)))
43074307
else
43084308
// Eta-expand higher-kinded type
4309-
tree.tpe.EtaExpand(tp.typeParamSymbols)
4309+
tree.tpe.etaExpand(tp.typeParamSymbols)
43104310
tree.withType(tp1)
43114311
}
43124312
if (ctx.mode.is(Mode.Pattern) || ctx.mode.isQuotedPattern || tree1.tpe <:< pt) tree1

tests/neg/i4557.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ object O {
99
type S0[X, Y] = C1[X, Y]
1010
type S1 = C1[Int] // error
1111

12-
class D0 extends T0 // error
12+
class D0 extends T0 // was error, now ok
1313
class D1 extends T0[Int]
1414
class D2 extends T0[String, Int] // error
1515

16-
class E0 extends S0 // error
16+
class E0 extends S0 // was error, now ok
1717
class E1 extends S0[Int] // error
1818
class E2 extends S0[String, Int]
1919
}

tests/pos/i18623.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
final abstract class ForcedRecompilationToken[T]
2+
object ForcedRecompilationToken {
3+
implicit def default: ForcedRecompilationToken["abc"] = null
4+
}
5+
6+
class GoodNoParens[T](implicit ev: ForcedRecompilationToken[T])
7+
type BadNoParens[T] = GoodNoParens[T]
8+
9+
// error
10+
object A extends BadNoParens
11+
12+
// ok
13+
object B extends BadNoParens()
14+
object C extends GoodNoParens
15+

tests/pos/i18623a.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
final abstract class ForcedRecompilationToken[T]
2+
object ForcedRecompilationToken {
3+
implicit def default: ForcedRecompilationToken["abc"] = null
4+
}
5+
6+
object x {
7+
class GoodNoParens[T](implicit ev: ForcedRecompilationToken[T])
8+
}
9+
export x.GoodNoParens as BadNoParens
10+
11+
// error
12+
object A extends BadNoParens
13+
14+
// ok
15+
object B extends BadNoParens()
16+
object C extends x.GoodNoParens
17+
18+
object App extends App {
19+
println("compiled")
20+
}

0 commit comments

Comments
 (0)