Skip to content

Commit

Permalink
Allow to reduce type member extractors when the member is a class.
Browse files Browse the repository at this point in the history
  • Loading branch information
sjrd committed Aug 14, 2023
1 parent f0339b3 commit c88d23a
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 13 deletions.
36 changes: 23 additions & 13 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3354,23 +3354,33 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
val info = denot.info match
case TypeAlias(alias) => alias
case info => info // Notably, RealTypeBounds, which will eventually give a MatchResult.NoInstances
if info.isInstanceOf[ClassInfo] then
/* The member is not an alias (we'll get Stuck instead of NoInstances,
* which is not ideal, but we cannot make a RealTypeBounds of ClassInfo).
val infoRefersToSkolem = stableScrut match
case stableScrut: SkolemType =>
new TypeAccumulator[Boolean] {
def apply(prev: Boolean, tp: Type): Boolean =
prev || (tp eq stableScrut) || foldOver(prev, tp)
}.apply(false, info)
case _ =>
false
if infoRefersToSkolem && info.isInstanceOf[ClassInfo] then
/* We would like to create a `RealTypeBounds(info, info)` to get a `MatchResult.NoInstances`
* but that is not allowed for `ClassInfo`. So instead we return `false`, which will result
* in a `MatchResult.Stuck` instead.
*/
false
else
val infoRefersToSkolem = stableScrut match
case stableScrut: SkolemType =>
new TypeAccumulator[Boolean] {
def apply(prev: Boolean, tp: Type): Boolean =
prev || (tp eq stableScrut) || foldOver(prev, tp)
}.apply(false, info)
val info1 = info match
case ClassInfo(prefix, cls, _, _, _) =>
// Re-select the class from the prefix
prefix.select(cls)
case info: TypeBounds =>
// Will already trigger a MatchResult.NoInstances
info
case _ if infoRefersToSkolem =>
// Explicitly trigger a MatchResult.NoInstances
RealTypeBounds(info, info)
case _ =>
false
val info1 =
if infoRefersToSkolem && !info.isInstanceOf[TypeBounds] then RealTypeBounds(info, info) // to trigger a MatchResult.NoInstances
else info
info
rec(capture, info1, variance = 0, scrutIsWidenedAbstract)
case _ =>
false
Expand Down
11 changes: 11 additions & 0 deletions tests/neg/match-type-enumeration-value-hack.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- [E172] Type Error: tests/neg/match-type-enumeration-value-hack.scala:11:40 ------------------------------------------
11 | summon[Suit#Value =:= EnumValue[Suit]] // error
| ^
| Cannot prove that Suit#Value =:= EnumValue[Suit].
|
| Note: a match type could not be fully reduced:
|
| trying to reduce EnumValue[Suit]
| failed since selector Suit
| does not match case EnumValueAux[t] => t
| and cannot be shown to be disjoint from it either.
12 changes: 12 additions & 0 deletions tests/neg/match-type-enumeration-value-hack.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type EnumValueAux[A] = ({ type Value }) { type Value = A }

type EnumValue[E <: Enumeration] = E match
case EnumValueAux[t] => t

// A class extending Enumeration does not yet define a concrete enumeration
class Suit extends Enumeration:
val Hearts, Diamonds, Clubs, Spades = Val()

object Test:
summon[Suit#Value =:= EnumValue[Suit]] // error
end Test
11 changes: 11 additions & 0 deletions tests/pos/match-type-enumeration-value-hack.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type EnumValueAux[A] = ({ type Value }) { type Value = A }

type EnumValue[E <: Enumeration] = E match
case EnumValueAux[t] => t

object Suit extends Enumeration:
val Hearts, Diamonds, Clubs, Spades = Val()

object Test:
summon[Suit.Value =:= EnumValue[Suit.type]]
end Test

0 comments on commit c88d23a

Please sign in to comment.