Skip to content

Commit ef7db7a

Browse files
Make aliases of MatchAliases normal TypeAliases
Make `isMatch` false for applied `MatchAlias`es, i.e. true only for `MatchType`s and higher-kinded abstraction of them. As a result, code using `isMatch` to choose between a `TypeAlias` and `MatchAlias` will now use a `TypeAlias` when aliasing a `MatchAlias`. Which in turn allows for better de-aliasing, since `dealias` only de-aliases standard type aliases. The logic for this distinction has also been extracted to the common `AliasingBounds` supertype. `tryNormalize` on `AppliedType`s should only attempt reduction if there is an underlying match type. This could previously be identified by a `MatchAlias` tycon. We now need a recursive check.
1 parent 90c3fbd commit ef7db7a

File tree

9 files changed

+70
-26
lines changed

9 files changed

+70
-26
lines changed

Diff for: compiler/src/dotty/tools/dotc/core/TypeApplications.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ class TypeApplications(val self: Type) extends AnyVal {
461461
*/
462462
final def toBounds(using Context): TypeBounds = self match {
463463
case self: TypeBounds => self // this can happen for wildcard args
464-
case _ => if (self.isMatch) MatchAlias(self) else TypeAlias(self)
464+
case _ => AliasingBounds(self)
465465
}
466466

467467
/** Translate a type of the form From[T] to either To[T] or To[? <: T] (if `wildcardArg` is set). Keep other types as they are.

Diff for: compiler/src/dotty/tools/dotc/core/Types.scala

+27-5
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,10 @@ object Types extends TypeUtils {
458458

459459
/** Is this a match type or a higher-kinded abstraction of one?
460460
*/
461-
def isMatch(using Context): Boolean = underlyingMatchType.exists
461+
def isMatch(using Context): Boolean = stripped match
462+
case tp: MatchType => true
463+
case tp: HKTypeLambda => tp.resType.isMatch
464+
case _ => false
462465

463466
def underlyingMatchType(using Context): Type = stripped match {
464467
case tp: MatchType => tp
@@ -4587,16 +4590,22 @@ object Types extends TypeUtils {
45874590

45884591
override def tryNormalize(using Context): Type = tycon.stripTypeVar match {
45894592
case tycon: TypeRef =>
4590-
def tryMatchAlias = tycon.info match {
4591-
case MatchAlias(alias) =>
4593+
def tryMatchAlias = tycon.info match
4594+
case AliasingBounds(alias) if isMatchAlias =>
45924595
trace(i"normalize $this", typr, show = true) {
45934596
MatchTypeTrace.recurseWith(this) {
45944597
alias.applyIfParameterized(args.map(_.normalized)).tryNormalize
4598+
/* `applyIfParameterized` may reduce several HKTypeLambda applications
4599+
* before the underlying MatchType is reached.
4600+
* Even if they do not involve any match type normalizations yet,
4601+
* we still want to record these reductions in the MatchTypeTrace.
4602+
* They should however only be attempted if they eventually expand
4603+
* to a match type, which is ensured by the `isMatchAlias` guard.
4604+
*/
45954605
}
45964606
}
45974607
case _ =>
45984608
NoType
4599-
}
46004609
tryCompiletimeConstantFold.orElse(tryMatchAlias)
46014610
case _ =>
46024611
NoType
@@ -4606,7 +4615,12 @@ object Types extends TypeUtils {
46064615
def isMatchAlias(using Context): Boolean = tycon.stripTypeVar match
46074616
case tycon: TypeRef =>
46084617
tycon.info match
4609-
case _: MatchAlias => true
4618+
case AliasingBounds(alias) =>
4619+
alias.underlyingMatchType.exists
4620+
/* This is the only true case since anything other than
4621+
* a TypeRef of an alias with an underlying match type
4622+
* should have been already reduced by `appliedTo` in the TypeAssigner.
4623+
*/
46104624
case _ => false
46114625
case _ => false
46124626

@@ -5636,6 +5650,14 @@ object Types extends TypeUtils {
56365650
def lower(lo: Type)(using Context): TypeBounds = apply(lo, defn.AnyType)
56375651
}
56385652

5653+
object AliasingBounds:
5654+
/** A MatchAlias if alias is a match type and a TypeAlias o.w.
5655+
* Note that aliasing a MatchAlias returns a normal TypeAlias.
5656+
*/
5657+
def apply(alias: Type)(using Context): AliasingBounds =
5658+
if alias.isMatch then MatchAlias(alias) else TypeAlias(alias)
5659+
def unapply(tp: AliasingBounds): Option[Type] = Some(tp.alias)
5660+
56395661
object TypeAlias {
56405662
def apply(alias: Type)(using Context): TypeAlias = unique(new TypeAlias(alias))
56415663
def unapply(tp: TypeAlias): Option[Type] = Some(tp.alias)

Diff for: compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

+1-3
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,7 @@ class TreeUnpickler(reader: TastyReader,
412412
readType().appliedTo(until(end)(readType()))
413413
case TYPEBOUNDS =>
414414
val lo = readType()
415-
if nothingButMods(end) then
416-
if lo.isMatch then MatchAlias(readVariances(lo))
417-
else TypeAlias(readVariances(lo))
415+
if nothingButMods(end) then AliasingBounds(readVariances(lo))
418416
else
419417
val hi = readVariances(readType())
420418
createNullableTypeBounds(lo, hi)

Diff for: compiler/src/dotty/tools/dotc/inlines/Inlines.scala

+2-3
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,8 @@ object Inlines:
452452
unrollTupleTypes(tail).map(head :: _)
453453
case tpe: TermRef if tpe.symbol == defn.EmptyTupleModule =>
454454
Some(Nil)
455-
case tpRef: TypeRef => tpRef.info match
456-
case MatchAlias(alias) => unrollTupleTypes(alias.tryNormalize)
457-
case _ => None
455+
case tpe: AppliedType if tpe.isMatchAlias =>
456+
unrollTupleTypes(tpe.tryNormalize)
458457
case _ =>
459458
None
460459

Diff for: compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

+1-3
Original file line numberDiff line numberDiff line change
@@ -519,9 +519,7 @@ trait TypeAssigner {
519519
def assignType(tree: untpd.TypeBoundsTree, lo: Tree, hi: Tree, alias: Tree)(using Context): TypeBoundsTree =
520520
tree.withType(
521521
if !alias.isEmpty then alias.tpe
522-
else if lo eq hi then
523-
if lo.tpe.isMatch then MatchAlias(lo.tpe)
524-
else TypeAlias(lo.tpe)
522+
else if lo eq hi then AliasingBounds(lo.tpe)
525523
else TypeBounds(lo.tpe, hi.tpe))
526524

527525
def assignType(tree: untpd.Bind, sym: Symbol)(using Context): Bind =

Diff for: compiler/test/dotc/pos-test-pickling.blacklist

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ i17149.scala
6464
tuple-fold.scala
6565
mt-redux-norm.perspective.scala
6666
i18211.scala
67+
10867.scala
6768

6869
# Opaque type
6970
i5720.scala

Diff for: tests/neg-macros/i11795.scala

-10
This file was deleted.

Diff for: tests/pos-macros/i11795.scala

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
import scala.quoted._
22
import scala.deriving._
33

4-
def blah2[P <: Product, MEL <: Tuple: Type, MET <: Tuple: Type](m: Mirror.ProductOf[P] { type MirroredElemLabels = MEL; type MirroredElemTypes = MET})(using Quotes) = {
4+
def blah[P <: Product]
5+
(m: Mirror.ProductOf[P])
6+
(using Quotes, Type[m.MirroredElemLabels], Type[m.MirroredElemTypes]) = {
7+
type z = Tuple.Zip[m.MirroredElemLabels, m.MirroredElemTypes]
8+
Type.of[z] // error
9+
()
10+
}
11+
12+
def blah2[P <: Product, MEL <: Tuple: Type, MET <: Tuple: Type]
13+
(m: Mirror.ProductOf[P] { type MirroredElemLabels = MEL; type MirroredElemTypes = MET})
14+
(using Quotes) = {
515
Type.of[Tuple.Zip[MEL, MET]]
616
()
717
}

Diff for: tests/pos/i19821.scala

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
object Test:
3+
4+
trait T:
5+
type S
6+
type F = T.F[S]
7+
8+
def foo: F
9+
def bar: T.F[S]
10+
11+
object T:
12+
type F[X] = X match
13+
case String => Option[Int]
14+
15+
type G[X] = X match
16+
case Option[x] => Int
17+
18+
val t: T {type S = String} = ???
19+
20+
val b = t.bar
21+
val m1: T.G[b.type] = ???
22+
val _: Int = m1 // Ok
23+
24+
val f = t.foo
25+
val m: T.G[f.type] = ???
26+
val _: Int = m // Error before changes

0 commit comments

Comments
 (0)