From abc8192fac301ad371c9a9a1102d6c043e886fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Bra=C4=8Devac?= Date: Wed, 23 Jul 2025 15:05:35 +0200 Subject: [PATCH] Suppress warnings in comprehensions with 22+ binds Fixes #23164 At that point, we emit a TupleXXL pattern case bundling all the variable bindings so far. The type tests in these patterns cannot be checked at runtime due to erasure. But we know these are safe, so we mark them as `@unchecked`. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 14 +++- tests/warn/i23164.scala | 72 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 tests/warn/i23164.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 38c36487e3a3..8184f18a8733 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -2102,7 +2102,19 @@ object desugar { val matchCheckMode = if (gen.checkMode == GenCheckMode.Check || gen.checkMode == GenCheckMode.CheckAndFilter) MatchCheck.IrrefutableGenFrom else MatchCheck.None - makeCaseLambda(CaseDef(gen.pat, EmptyTree, body) :: Nil, matchCheckMode) + val pat = gen.pat.match + case Tuple(pats) if pats.length > Definitions.MaxImplementedFunctionArity => + /* The pattern case is a tupleXXL, because we have bound > 21 variables in the comprehension. + * In this case, we need to mark all the typed patterns as @unchecked, or get loads of warnings. + * Cf. warn test i23164.scala */ + Tuple: + pats.map: + case t @ Bind(name, tp @ Typed(id, tpt)) => + val annotated = Annotated(tpt, New(ref(defn.UncheckedAnnot.typeRef))) + cpy.Bind(t)(name, cpy.Typed(tp)(id, annotated)).withMods(t.mods) + case t => t + case _ => gen.pat + makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil, matchCheckMode) } def hasGivenBind(pat: Tree): Boolean = pat.existsSubTree { diff --git a/tests/warn/i23164.scala b/tests/warn/i23164.scala new file mode 100644 index 000000000000..ac068555a5b3 --- /dev/null +++ b/tests/warn/i23164.scala @@ -0,0 +1,72 @@ +class T1[F[_]] +class T2[F[_]] +class T3[F[_]] +class T4[F[_]] +class T5[F[_]] +class T6[F[_]] +class T7[F[_]] +class T8[F[_]] +class T9[F[_]] +class T10[F[_]] +class T11[F[_]] +class T12[F[_]] +class T13[F[_]] +class T14[F[_]] +class T15[F[_]] +class T16[F[_]] +class T17[F[_]] +class T18[F[_]] +class T19[F[_]] +class T20[F[_]] +class T21[F[_]] +class T22[F[_]] + +class Result[F[_]: {T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22}] + +val r = for + t1 <- Option(new T1[Option]) + t2 <- Option(new T2[Option]) + t3 <- Option(new T3[Option]) + t4 <- Option(new T4[Option]) + t5 <- Option(new T5[Option]) + t6 <- Option(new T6[Option]) + t7 <- Option(new T7[Option]) + t8 <- Option(new T8[Option]) + t9 <- Option(new T9[Option]) + t10 <- Option(new T10[Option]) + t11 <- Option(new T11[Option]) + t12 <- Option(new T12[Option]) + t13 <- Option(new T13[Option]) + t14 <- Option(new T14[Option]) + t15 <- Option(new T15[Option]) + t16 <- Option(new T16[Option]) + t17 <- Option(new T17[Option]) + t18 <- Option(new T18[Option]) + t19 <- Option(new T19[Option]) + t20 <- Option(new T20[Option]) + t21 <- Option(new T21[Option]) + t22 <- Option(new T22[Option]) + given T1[Option] = t1 + given T2[Option] = t2 + given T3[Option] = t3 + given T4[Option] = t4 + given T5[Option] = t5 + given T6[Option] = t6 + given T7[Option] = t7 + given T8[Option] = t8 + given T9[Option] = t9 + given T10[Option] = t10 + given T11[Option] = t11 + given T12[Option] = t12 + given T13[Option] = t13 + given T14[Option] = t14 + given T15[Option] = t15 + given T16[Option] = t16 + given T17[Option] = t17 + given T18[Option] = t18 + given T19[Option] = t19 + given T20[Option] = t20 + given T21[Option] = t21 + given T22[Option] = t22 + result <- Option(new Result[Option]) +yield result \ No newline at end of file