diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index ceec2392af1a..ecbb34ea2949 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -145,22 +145,26 @@ object Checking { val checker = new TypeTraverser: def traverse(tp: Type) = tp match - case AppliedType(tycon, argTypes) - if !(tycon.typeSymbol.is(JavaDefined) && ctx.compilationUnit.isJava) - // Don't check bounds in Java units that refer to Java type constructors. - // Scala is not obliged to do Java type checking and in fact i17763 goes wrong - // if we attempt to check bounds of F-bounded mutually recursive Java interfaces. - // Do check all bounds in Scala units and those bounds in Java units that - // occur in applications of Scala type constructors. - && !isCaptureChecking || tycon.typeSymbol.is(CaptureChecked) - // Don't check bounds when capture checking type constructors that were not - // themselves capture checked. Since the type constructor could not foresee - // possible capture sets, it's better to be lenient for backwards compatibility. - => - checkAppliedType( - untpd.AppliedTypeTree(TypeTree(tycon), argTypes.map(TypeTree(_))) - .withType(tp).withSpan(tpt.span.toSynthetic), - tpt) + case tp @ AppliedType(tycon, argTypes) => + // Should the type be re-checked in the CC phase? + // Exempted are types that are not themselves capture-checked. + // Since the type constructor could not foresee possible capture sets, + // it's better to be lenient for backwards compatibility. + // Also exempted are match aliases. See tuple-ops.scala for an example that + // would fail otherwise. + def checkableUnderCC = + tycon.typeSymbol.is(CaptureChecked) && !tp.isMatchAlias + if !(tycon.typeSymbol.is(JavaDefined) && ctx.compilationUnit.isJava) + // Don't check bounds in Java units that refer to Java type constructors. + // Scala is not obliged to do Java type checking and in fact i17763 goes wrong + // if we attempt to check bounds of F-bounded mutually recursive Java interfaces. + // Do check all bounds in Scala units and those bounds in Java units that + // occur in applications of Scala type constructors. + && (!isCaptureChecking || checkableUnderCC) then + checkAppliedType( + untpd.AppliedTypeTree(TypeTree(tycon), argTypes.map(TypeTree(_))) + .withType(tp).withSpan(tpt.span.toSynthetic), + tpt) case _ => traverseChildren(tp) checker.traverse(tpt.tpe) diff --git a/tests/pos-custom-args/captures/tuple-ops.scala b/tests/pos-custom-args/captures/tuple-ops.scala new file mode 100644 index 000000000000..6259328dd9ab --- /dev/null +++ b/tests/pos-custom-args/captures/tuple-ops.scala @@ -0,0 +1,13 @@ +sealed trait Tupp + +case object EmptyTupp extends Tupp +type EmptyTupp = EmptyTupp.type +infix case class `*::`[H, T <: Tupp](h: H, t: T) extends Tupp + +type Union[T <: Tupp] = T match + case EmptyTupp => Nothing + case h *:: t => h | Union[t] + +type Map[T <: Tupp, F[_ <: Union[T]]] <: Tupp = T match + case EmptyTupp => EmptyTupp + case h *:: t => F[h] *:: Map[t, F] \ No newline at end of file