Skip to content

Commit c794c5f

Browse files
Make isMatch false for applied MatchAliases
It is 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` 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 20d95b0 commit c794c5f

File tree

10 files changed

+68
-36
lines changed

10 files changed

+68
-36
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ class TypeApplications(val self: Type) extends AnyVal {
451451
*/
452452
final def toBounds(using Context): TypeBounds = self match {
453453
case self: TypeBounds => self // this can happen for wildcard args
454-
case _ => if (self.isMatch) MatchAlias(self) else TypeAlias(self)
454+
case _ => AliasingBounds(self)
455455
}
456456

457457
/** 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.

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

+26-6
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
@@ -4578,26 +4581,35 @@ object Types extends TypeUtils {
45784581

45794582
override def tryNormalize(using Context): Type = tycon.stripTypeVar match {
45804583
case tycon: TypeRef =>
4581-
def tryMatchAlias = tycon.info match {
4582-
case MatchAlias(alias) =>
4584+
def tryMatchAlias = tycon.info match
4585+
case AliasingBounds(alias) if isMatchAlias =>
45834586
trace(i"normalize $this", typr, show = true) {
45844587
MatchTypeTrace.recurseWith(this) {
45854588
alias.applyIfParameterized(args.map(_.normalized)).tryNormalize
4589+
/* `applyIfParameterized` may reduce several HKTypeLambda applications
4590+
* before the underlying MatchType is reached.
4591+
* Even if they do not involve any match type normalizations yet,
4592+
* we still want to record these reductions in the MatchTypeTrace.
4593+
* They should however only be attempted if they eventually expand
4594+
* to a match type, which is ensured by the `isMatchAlias` guard.
4595+
*/
45864596
}
45874597
}
45884598
case _ =>
45894599
NoType
4590-
}
45914600
tryCompiletimeConstantFold.orElse(tryMatchAlias)
45924601
case _ =>
45934602
NoType
45944603
}
45954604

4596-
/** Does this application expand to a match type? */
4605+
/** Does this application expand to a match type?
4606+
* Note: tycon can not be a non-aliased (higher-kinded abstraction of a) match type,
4607+
* since the args would then have already been substituted by the `TypeAssigner` using `appliedTo`.
4608+
*/
45974609
def isMatchAlias(using Context): Boolean = tycon.stripTypeVar match
45984610
case tycon: TypeRef =>
45994611
tycon.info match
4600-
case _: MatchAlias => true
4612+
case AliasingBounds(alias) => alias.underlyingMatchType.exists
46014613
case _ => false
46024614
case _ => false
46034615

@@ -5627,6 +5639,14 @@ object Types extends TypeUtils {
56275639
def lower(lo: Type)(using Context): TypeBounds = apply(lo, defn.AnyType)
56285640
}
56295641

5642+
object AliasingBounds:
5643+
/** A MatchAlias if alias is match type and TypeAlias o.w.
5644+
* Note that aliasing a MatchAlias returns a normal TypeAlias.
5645+
* */
5646+
def apply(alias: Type)(using Context): AliasingBounds =
5647+
if alias.isMatch then MatchAlias(alias) else TypeAlias(alias)
5648+
def unapply(tp: AliasingBounds): Option[Type] = Some(tp.alias)
5649+
56305650
object TypeAlias {
56315651
def apply(alias: Type)(using Context): TypeAlias = unique(new TypeAlias(alias))
56325652
def unapply(tp: TypeAlias): Option[Type] = Some(tp.alias)

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)

compiler/src/dotty/tools/dotc/inlines/Inlines.scala

+1-4
Original file line numberDiff line numberDiff line change
@@ -446,16 +446,13 @@ object Inlines:
446446
evidence
447447
}
448448

449-
def unrollTupleTypes(tpe: Type): Option[List[Type]] = tpe.dealias match
449+
def unrollTupleTypes(tpe: Type): Option[List[Type]] = tpe.dealias.normalized match
450450
case AppliedType(tycon, args) if defn.isTupleClass(tycon.typeSymbol) =>
451451
Some(args)
452452
case AppliedType(tycon, head :: tail :: Nil) if tycon.isRef(defn.PairClass) =>
453453
unrollTupleTypes(tail).map(head :: _)
454454
case tpe: TermRef if tpe.symbol == defn.EmptyTupleModule =>
455455
Some(Nil)
456-
case tpRef: TypeRef => tpRef.info match
457-
case MatchAlias(alias) => unrollTupleTypes(alias.tryNormalize)
458-
case _ => None
459456
case _ =>
460457
None
461458

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 =

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

tests/neg-macros/i11795.scala

-10
This file was deleted.

tests/neg/i17944.check

-8
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,6 @@
2929
| Therefore, reduction cannot advance to the remaining case
3030
|
3131
| case _ *: t => test.FindField0[t, ("i" : String), scala.compiletime.ops.int.S[(0 : Int)]]
32-
| trying to reduce test.FindField[(("s" : String) ->> String, ("i" : String) ->> Int), ("i" : String)]
33-
| trying to reduce test.FindField0[(("s" : String) ->> String, ("i" : String) ->> Int), ("i" : String), (0 : Int)]
34-
| failed since selector (("s" : String) ->> String, ("i" : String) ->> Int)
35-
| does not match case (("i" : String) ->> f) *: _ => (f, (0 : Int))
36-
| and cannot be shown to be disjoint from it either.
37-
| Therefore, reduction cannot advance to the remaining case
38-
|
39-
| case _ *: t => test.FindField0[t, ("i" : String), scala.compiletime.ops.int.S[(0 : Int)]]
4032
| trying to reduce test.FindField0[(("s" : String) ->> String, ("i" : String) ->> Int), ("i" : String), (0 : Int)]
4133
| failed since selector (("s" : String) ->> String, ("i" : String) ->> Int)
4234
| does not match case (("i" : String) ->> f) *: _ => (f, (0 : Int))

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
}

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)