Skip to content

Commit 4cd2a97

Browse files
committed
Document enum value changes in provablyDisjointClasses
1 parent 04f6fc3 commit 4cd2a97

File tree

2 files changed

+19
-4
lines changed

2 files changed

+19
-4
lines changed

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,11 +2983,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
29832983
*
29842984
* 1. Single inheritance of classes
29852985
* 2. Final classes cannot be extended
2986-
* 3. ConstantTypes with distinct values are non intersecting
2987-
* 4. TermRefs with distinct values are non intersecting
2986+
* 3. ConstantTypes with distinct values are non-intersecting
2987+
* 4. TermRefs with distinct values are non-intersecting
29882988
* 5. There is no value of type Nothing
29892989
*
2990-
* Note on soundness: the correctness of match types relies on on the
2990+
* Note on soundness: the correctness of match types relies on the
29912991
* property that in all possible contexts, the same match type expression
29922992
* is either stuck or reduces to the same case.
29932993
*
@@ -3206,13 +3206,28 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
32063206
end match
32073207
}
32083208

3209+
/** Are `cls1` and `cls1` provablyDisjoint classes, i.e., is `cls1 ⋔ cls2` true?
3210+
*
3211+
* Note that "class" where includes traits, module classes, and (in the recursive case)
3212+
* enum value term symbols.
3213+
*/
32093214
private def provablyDisjointClasses(cls1: Symbol, cls2: Symbol)(using Context): Boolean =
32103215
def isDecomposable(cls: Symbol): Boolean =
32113216
cls.is(Sealed) && !cls.hasAnonymousChild
32123217

32133218
def decompose(cls: Symbol): List[Symbol] =
32143219
cls.children.map: child =>
32153220
if child.isTerm then
3221+
// Enum vals with mixins, such as in i21860 or i22266,
3222+
// don't have a single class symbol.
3223+
// So instead of decomposing to NoSymbol
3224+
// (which leads to erroneously considering an enum type
3225+
// as disjoint from one of the mixin, eg. i21860.scala),
3226+
// or instead of decomposing to all the class symbols of
3227+
// the enum value (which leads to other mixins being decomposed,
3228+
// and infinite recursion, eg. i22266),
3229+
// we decompose to the enum value term symbol, and handle
3230+
// that within the rest of provablyDisjointClasses.
32163231
child.info.classSymbol.orElse(child)
32173232
else child
32183233
.filter(child => child.exists && child != cls)

docs/_spec/03-types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@ The following properties hold about ´⌈X⌉´ (we have paper proofs for those)
10711071
The "lower-bound rule" states that ´S <: T´ if ´T = q.X´ and ´q.X´ is a non-class type designator and ´S <: L´ where ´L´ is the lower bound of the underlying type definition of ´q.X´".
10721072
That rule is known to break transitivy of subtyping in Scala already.
10731073

1074-
Second, we define the relation ´⋔´ on *classes* (including traits and hidden classes of objects) as:
1074+
Second, we define the relation ´⋔´ on *classes* (including traits, hidden classes of objects, and enum terms) as:
10751075

10761076
- ´C ⋔ D´ if `´C ∉´ baseClasses´(D)´` and ´D´ is `final`
10771077
- ´C ⋔ D´ if `´D ∉´ baseClasses´(C)´` and ´C´ is `final`

0 commit comments

Comments
 (0)