Skip to content

Commit c5f63b2

Browse files
authored
Don't check bounds in match type cases at CC (#23738)
For soundness it's enough to check bounds in reduced match types.
2 parents 3a4c98a + c54c538 commit c5f63b2

File tree

2 files changed

+41
-21
lines changed

2 files changed

+41
-21
lines changed

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -144,29 +144,30 @@ object Checking {
144144
def checkAppliedTypesIn(tpt: TypeTree)(using Context): Unit =
145145
val checker = new TypeTraverser:
146146
def traverse(tp: Type) =
147-
tp match
147+
tp.normalized match
148148
case tp @ AppliedType(tycon, argTypes) =>
149-
// Should the type be re-checked in the CC phase?
150-
// Exempted are types that are not themselves capture-checked.
151-
// Since the type constructor could not foresee possible capture sets,
152-
// it's better to be lenient for backwards compatibility.
153-
// Also exempted are match aliases. See tuple-ops.scala for an example that
154-
// would fail otherwise.
155-
def checkableUnderCC =
156-
tycon.typeSymbol.is(CaptureChecked) && !tp.isMatchAlias
157-
if !(tycon.typeSymbol.is(JavaDefined) && ctx.compilationUnit.isJava)
158-
// Don't check bounds in Java units that refer to Java type constructors.
159-
// Scala is not obliged to do Java type checking and in fact i17763 goes wrong
160-
// if we attempt to check bounds of F-bounded mutually recursive Java interfaces.
161-
// Do check all bounds in Scala units and those bounds in Java units that
162-
// occur in applications of Scala type constructors.
163-
&& (!isCaptureChecking || checkableUnderCC) then
164-
checkAppliedType(
165-
untpd.AppliedTypeTree(TypeTree(tycon), argTypes.map(TypeTree(_)))
166-
.withType(tp).withSpan(tpt.span.toSynthetic),
167-
tpt)
149+
if !(isCaptureChecking && defn.MatchCase.isInstance(tp)) then
150+
// Don't check match type cases under cc. For soundness it's enough
151+
// to check bounds in reduced match types.
152+
// See tuple-ops.scala and tuple-ops-2.scala for examples that would fail otherwise.
153+
if !(tycon.typeSymbol.is(JavaDefined) && ctx.compilationUnit.isJava)
154+
// Don't check bounds in Java units that refer to Java type constructors.
155+
// Scala is not obliged to do Java type checking and in fact i17763 goes wrong
156+
// if we attempt to check bounds of F-bounded mutually recursive Java interfaces.
157+
// Do check all bounds in Scala units and those bounds in Java units that
158+
// occur in applications of Scala type constructors.
159+
&& (!isCaptureChecking || tycon.typeSymbol.is(CaptureChecked))
160+
// When capture checking, types that are not themselves capture-checked
161+
// are exempted. Since the type constructor could not foresee possible
162+
// capture sets, it's better to be lenient for backwards compatibility.
163+
then
164+
checkAppliedType(
165+
untpd.AppliedTypeTree(TypeTree(tycon), argTypes.map(TypeTree(_)))
166+
.withType(tp).withSpan(tpt.span.toSynthetic),
167+
tpt)
168+
traverseChildren(tp)
168169
case _ =>
169-
traverseChildren(tp)
170+
traverseChildren(tp)
170171
checker.traverse(tpt.tpe)
171172

172173
def checkNoWildcard(tree: Tree)(using Context): Tree = tree.tpe match {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
sealed trait Tup
2+
case object Emp extends Tup
3+
type Emp = Emp.type
4+
case class Cons[h, t <: Tup](hh: h, tt: t) extends Tup
5+
6+
type Union[T <: Tup] = T match
7+
case Emp => Nothing
8+
case Cons[h, t] => h | Union[t]
9+
10+
type Concat[T <: Tup, U <: Tup] <: Tup = T match
11+
case Emp => U
12+
case Cons[h, t] => Cons[h, Concat[t, U]]
13+
14+
type FlatMap[T <: Tup, F[_ <: Union[T]] <: Tup] <: Tup = T match
15+
case Emp => Emp
16+
case Cons[h, t] => Concat[F[h], FlatMap[t, F]]
17+
18+
type A =
19+
FlatMap[Cons[Boolean, Cons[String, Emp]], [T] =>> Cons[T, Cons[List[T], Emp]]]

0 commit comments

Comments
 (0)