Skip to content

Commit c88d23a

Browse files
committed
Allow to reduce type member extractors when the member is a class.
1 parent f0339b3 commit c88d23a

File tree

4 files changed

+57
-13
lines changed

4 files changed

+57
-13
lines changed

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

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3354,23 +3354,33 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
33543354
val info = denot.info match
33553355
case TypeAlias(alias) => alias
33563356
case info => info // Notably, RealTypeBounds, which will eventually give a MatchResult.NoInstances
3357-
if info.isInstanceOf[ClassInfo] then
3358-
/* The member is not an alias (we'll get Stuck instead of NoInstances,
3359-
* which is not ideal, but we cannot make a RealTypeBounds of ClassInfo).
3357+
val infoRefersToSkolem = stableScrut match
3358+
case stableScrut: SkolemType =>
3359+
new TypeAccumulator[Boolean] {
3360+
def apply(prev: Boolean, tp: Type): Boolean =
3361+
prev || (tp eq stableScrut) || foldOver(prev, tp)
3362+
}.apply(false, info)
3363+
case _ =>
3364+
false
3365+
if infoRefersToSkolem && info.isInstanceOf[ClassInfo] then
3366+
/* We would like to create a `RealTypeBounds(info, info)` to get a `MatchResult.NoInstances`
3367+
* but that is not allowed for `ClassInfo`. So instead we return `false`, which will result
3368+
* in a `MatchResult.Stuck` instead.
33603369
*/
33613370
false
33623371
else
3363-
val infoRefersToSkolem = stableScrut match
3364-
case stableScrut: SkolemType =>
3365-
new TypeAccumulator[Boolean] {
3366-
def apply(prev: Boolean, tp: Type): Boolean =
3367-
prev || (tp eq stableScrut) || foldOver(prev, tp)
3368-
}.apply(false, info)
3372+
val info1 = info match
3373+
case ClassInfo(prefix, cls, _, _, _) =>
3374+
// Re-select the class from the prefix
3375+
prefix.select(cls)
3376+
case info: TypeBounds =>
3377+
// Will already trigger a MatchResult.NoInstances
3378+
info
3379+
case _ if infoRefersToSkolem =>
3380+
// Explicitly trigger a MatchResult.NoInstances
3381+
RealTypeBounds(info, info)
33693382
case _ =>
3370-
false
3371-
val info1 =
3372-
if infoRefersToSkolem && !info.isInstanceOf[TypeBounds] then RealTypeBounds(info, info) // to trigger a MatchResult.NoInstances
3373-
else info
3383+
info
33743384
rec(capture, info1, variance = 0, scrutIsWidenedAbstract)
33753385
case _ =>
33763386
false
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- [E172] Type Error: tests/neg/match-type-enumeration-value-hack.scala:11:40 ------------------------------------------
2+
11 | summon[Suit#Value =:= EnumValue[Suit]] // error
3+
| ^
4+
| Cannot prove that Suit#Value =:= EnumValue[Suit].
5+
|
6+
| Note: a match type could not be fully reduced:
7+
|
8+
| trying to reduce EnumValue[Suit]
9+
| failed since selector Suit
10+
| does not match case EnumValueAux[t] => t
11+
| and cannot be shown to be disjoint from it either.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
type EnumValueAux[A] = ({ type Value }) { type Value = A }
2+
3+
type EnumValue[E <: Enumeration] = E match
4+
case EnumValueAux[t] => t
5+
6+
// A class extending Enumeration does not yet define a concrete enumeration
7+
class Suit extends Enumeration:
8+
val Hearts, Diamonds, Clubs, Spades = Val()
9+
10+
object Test:
11+
summon[Suit#Value =:= EnumValue[Suit]] // error
12+
end Test
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
type EnumValueAux[A] = ({ type Value }) { type Value = A }
2+
3+
type EnumValue[E <: Enumeration] = E match
4+
case EnumValueAux[t] => t
5+
6+
object Suit extends Enumeration:
7+
val Hearts, Diamonds, Clubs, Spades = Val()
8+
9+
object Test:
10+
summon[Suit.Value =:= EnumValue[Suit.type]]
11+
end Test

0 commit comments

Comments
 (0)