Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use cached underlyingMatchType when normalizing applied match aliases #20257

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2902,6 +2902,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
tp
case tp: ConstantType =>
tp
case tp: AppliedType if tp.tryCompiletimeConstantFold.exists =>
tp.tryCompiletimeConstantFold
case tp: HKTypeLambda =>
tp
case tp: ParamRef =>
Expand Down
36 changes: 11 additions & 25 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -468,12 +468,10 @@ object Types extends TypeUtils {
/** Does this application expand to a match type? */
def isMatchAlias(using Context): Boolean = underlyingMatchType.exists

def underlyingMatchType(using Context): Type = stripped match {
def underlyingMatchType(using Context): Type = stripped match
case tp: MatchType => tp
case tp: HKTypeLambda => tp.resType.underlyingMatchType
case tp: AppliedType => tp.underlyingMatchType
case _ => NoType
}

/** Is this a higher-kinded type lambda with given parameter variances?
* These lambdas are used as the RHS of higher-kinded abstract types or
Expand Down Expand Up @@ -4647,35 +4645,23 @@ object Types extends TypeUtils {

/** Exists if the tycon is a TypeRef of an alias with an underlying match type.
* Anything else should have already been reduced in `appliedTo` by the TypeAssigner.
* May reduce several HKTypeLambda applications before the underlying MatchType is reached.
*/
override def underlyingMatchType(using Context): Type =
if ctx.period != validUnderlyingMatch then
validUnderlyingMatch = if tycon.isProvisional then Nowhere else ctx.period
cachedUnderlyingMatch = superType.underlyingMatchType
cachedUnderlyingMatch

override def tryNormalize(using Context): Type = tycon.stripTypeVar match {
case tycon: TypeRef =>
def tryMatchAlias = tycon.info match
EugeneFlesselle marked this conversation as resolved.
Show resolved Hide resolved
case AliasingBounds(alias) if isMatchAlias =>
trace(i"normalize $this", typr, show = true) {
MatchTypeTrace.recurseWith(this) {
alias.applyIfParameterized(args.map(_.normalized)).tryNormalize
/* `applyIfParameterized` may reduce several HKTypeLambda applications
* before the underlying MatchType is reached.
* Even if they do not involve any match type normalizations yet,
* we still want to record these reductions in the MatchTypeTrace.
* They should however only be attempted if they eventually expand
* to a match type, which is ensured by the `isMatchAlias` guard.
*/
}
}
case _ =>
NoType
tryCompiletimeConstantFold.orElse(tryMatchAlias)
case _ =>
NoType
}
override def tryNormalize(using Context): Type =
def tryMatchAlias =
if isMatchAlias then trace(i"normalize $this", typr, show = true):
if MatchTypeTrace.isRecording then
MatchTypeTrace.recurseWith(this)(superType.tryNormalize)
else
underlyingMatchType.tryNormalize
else NoType
tryCompiletimeConstantFold.orElse(tryMatchAlias)

/** Is this an unreducible application to wildcard arguments?
* This is the case if tycon is higher-kinded. This means
Expand Down
14 changes: 14 additions & 0 deletions tests/neg/i12049d.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- [E007] Type Mismatch Error: tests/neg/i12049d.scala:14:52 -----------------------------------------------------------
14 |val x: M[NotRelevant[Nothing], Relevant[Nothing]] = 2 // error
| ^
| Found: (2 : Int)
| Required: M[NotRelevant[Nothing], Relevant[Nothing]]
|
| Note: a match type could not be fully reduced:
|
| trying to reduce M[NotRelevant[Nothing], Relevant[Nothing]]
| trying to reduce Relevant[Nothing]
| failed since selector Nothing
| is uninhabited (there are no values of that type).
|
| longer explanation available when compiling with `-explain`
14 changes: 14 additions & 0 deletions tests/neg/i12049d.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

trait A
trait B

type M[X, Y] = Y match
case A => Int
case B => String

type Relevant[Z] = Z match
case A => B
type NotRelevant[Z] = Z match
case B => A

val x: M[NotRelevant[Nothing], Relevant[Nothing]] = 2 // error
24 changes: 24 additions & 0 deletions tests/pos/i20166.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import scala.compiletime.ops.int.*

// NOTE ops.int.S is documented as equivalent to MyS

type MyS[X] = X match
case 0 => 1
case 1 => 2
case 2 => 3

type M[I <: Int] = 4 match
case 1 - 1 => "0"
case MyS[I] => "2"
case S[I] => "2" // Not provablyDisjoint before changes
case 2 + I => "3"
case I + 3 => "4"

val _: M[1] = "4"


type M2[I <: Int, P] = I match
case P => "b"
case _ => "c"

val _: M2[5, 2 + 3] = "b"
8 changes: 8 additions & 0 deletions tests/pos/matchtype-unusedArg/A_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

type Rec[X] = X match
case Int => Rec[X]

type M[Unused, Y] = Y match
case String => Double

def foo[X](d: M[Rec[X], "hi"]) = ???
2 changes: 2 additions & 0 deletions tests/pos/matchtype-unusedArg/B_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

def Test = foo[Int](3d) // crash before changes
Loading