From dd9831b25af3d69982ce8c28906872239538e57c Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Wed, 10 Apr 2024 00:12:17 +0200 Subject: [PATCH 1/3] Add tests for #20071 and #20136 Both observe different behaviours match type reductions depending on whether they are compiled together or separately. They both compile only with separate compilation. --- tests/neg/{i20071.scala => i20071a.scala} | 0 tests/neg/i20071b/A_1.scala | 13 +++++++++++++ tests/neg/i20071b/B_2.scala | 8 ++++++++ tests/pos/i20136a.scala | 14 ++++++++++++++ tests/pos/i20136b/A_1.scala | 8 ++++++++ tests/pos/i20136b/B_2.scala | 8 ++++++++ 6 files changed, 51 insertions(+) rename tests/neg/{i20071.scala => i20071a.scala} (100%) create mode 100644 tests/neg/i20071b/A_1.scala create mode 100644 tests/neg/i20071b/B_2.scala create mode 100644 tests/pos/i20136a.scala create mode 100644 tests/pos/i20136b/A_1.scala create mode 100644 tests/pos/i20136b/B_2.scala diff --git a/tests/neg/i20071.scala b/tests/neg/i20071a.scala similarity index 100% rename from tests/neg/i20071.scala rename to tests/neg/i20071a.scala diff --git a/tests/neg/i20071b/A_1.scala b/tests/neg/i20071b/A_1.scala new file mode 100644 index 000000000000..ea3aa97c6a6f --- /dev/null +++ b/tests/neg/i20071b/A_1.scala @@ -0,0 +1,13 @@ + +trait Scope +object Scope: + given i: Int = ??? + +type ReferencesScope[S] >: Int <: Int + +type ScopeToInt[Why] = Why match + case Scope => Int + +def foo[T](using d: ReferencesScope[T]): Any = ??? + +def bar[T](using d: ScopeToInt[T]): Any = ??? diff --git a/tests/neg/i20071b/B_2.scala b/tests/neg/i20071b/B_2.scala new file mode 100644 index 000000000000..0b5169cf901c --- /dev/null +++ b/tests/neg/i20071b/B_2.scala @@ -0,0 +1,8 @@ + +def test: Unit = + foo[Scope] // ok + bar[Scope] // error + + import Scope.i + bar[Scope] // ok + diff --git a/tests/pos/i20136a.scala b/tests/pos/i20136a.scala new file mode 100644 index 000000000000..5378119f14d2 --- /dev/null +++ b/tests/pos/i20136a.scala @@ -0,0 +1,14 @@ + +trait Expr: + type Value +object Expr: + type Of[V] = Expr { type Value = V } + type ExtractValue[E <: Expr] = E match + case Expr.Of[v] => v + +trait TC[E <: Expr]: + type Elem = Expr.ExtractValue[E] +class BIExpr extends Expr: + type Value = BigInt +class Foo extends TC[BIExpr]: + val v: Elem = 0 diff --git a/tests/pos/i20136b/A_1.scala b/tests/pos/i20136b/A_1.scala new file mode 100644 index 000000000000..7c8dc3ebbf52 --- /dev/null +++ b/tests/pos/i20136b/A_1.scala @@ -0,0 +1,8 @@ +package a + +trait Expr: + type Value +object Expr: + type Of[V] = Expr { type Value = V } + type ExtractValue[E <: Expr] = E match + case Expr.Of[v] => v diff --git a/tests/pos/i20136b/B_2.scala b/tests/pos/i20136b/B_2.scala new file mode 100644 index 000000000000..54a3da158f89 --- /dev/null +++ b/tests/pos/i20136b/B_2.scala @@ -0,0 +1,8 @@ +package a + +trait TC[E <: Expr]: + type Elem = Expr.ExtractValue[E] +class BIExpr extends Expr: + type Value = BigInt +class Foo extends TC[BIExpr]: + val v: Elem = 0 From d421f88a64d090493c323626550f93632d66f534 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Wed, 10 Apr 2024 00:23:44 +0200 Subject: [PATCH 2/3] Do not flag match types as `Deferred` This already wasn't the case for unpickled match types, which caused varying results for `ImplicitRunInfo#isAnchor`, by not reaching the `isMatchAlias` condition. Ensures both #20071 and #20136 each have the same result, when compiled with a classpath dependency as when merged. Note that they both still fail (20071 compiles but shouldn't), but at least do so consistently. Also update TreeUnpickler MATCHtpt doc to align with changes from #19871 Co-authored-by: Guillaume Martres --- compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 -- compiler/src/dotty/tools/dotc/typer/Namer.scala | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index a75cc6c666d0..25e5aa4fa040 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1542,8 +1542,6 @@ class TreeUnpickler(reader: TastyReader, // as the reduction of the match type definition! // // We also override the type, as that's what Typer does. - // The difference here is that a match type that reduces to a non-match type - // makes the TypeRef for that definition will have a TypeAlias info instead of a MatchAlias. tpt.overwriteType(tpt.tpe.normalized) tpt case TYPEBOUNDStpt => diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 15d7885776c5..6586eba9b933 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -268,8 +268,8 @@ class Namer { typer: Typer => else if flags.isAllOf(EnumValue) && ctx.owner.isStaticOwner then flags |= JavaStatic case tree: TypeDef => def analyzeRHS(rhs: Tree): Unit = rhs match - case _: TypeBoundsTree | _: MatchTypeTree => - flags |= Deferred // Typedefs with Match rhs classify as abstract + case _: TypeBoundsTree => + flags |= Deferred case LambdaTypeTree(_, body) => analyzeRHS(body) case _ => From c794eab1bf161c8d97381f9e793b735b5d01aa92 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Wed, 10 Apr 2024 00:40:04 +0200 Subject: [PATCH 3/3] Normalize types in `liftToAnchors` instead of in `collectParts` Fixes #20136 Co-authored-by: Guillaume Martres --- compiler/src/dotty/tools/dotc/typer/Implicits.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 5b233bd98730..5ffc81744d85 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -636,7 +636,7 @@ trait ImplicitRunInfo: else if implicitScopeCache.contains(t) then parts += t else partSeen += t - t.dealias.normalized match + t.dealias match case t: TypeRef => if isAnchor(t.symbol) then parts += t @@ -817,7 +817,7 @@ trait ImplicitRunInfo: else AndType.make(apply(lo), apply(hi)) case u => apply(u) - def apply(t: Type) = t.dealias match + def apply(t: Type) = t.dealias.normalized match case t: TypeRef => if t.symbol.isClass || isAnchor(t.symbol) then t else applyToUnderlying(t) case t: TypeVar => apply(t.underlying)