diff --git a/compiler/src/dotty/tools/dotc/core/TypeUtils.scala b/compiler/src/dotty/tools/dotc/core/TypeUtils.scala index eb526c2b4d85..82c027744c38 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeUtils.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeUtils.scala @@ -152,6 +152,17 @@ class TypeUtils: def namedTupleElementTypes(derived: Boolean)(using Context): List[(TermName, Type)] = namedTupleElementTypesUpTo(Int.MaxValue, derived) + /** If this is a generic tuple type with arity <= MaxTupleArity, return the + * corresponding TupleN type, otherwise return this. + */ + def normalizedTupleType(using Context): Type = + if self.isGenericTuple then + self.tupleElementTypes match + case Some(elems) if elems.size <= Definitions.MaxTupleArity => defn.tupleType(elems) + case _ => self + else + self + def isNamedTupleType(using Context): Boolean = self match case defn.NamedTuple(_, _) => true case _ => false diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 6499d806a9a5..0bcf2f5cce69 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -942,7 +942,7 @@ trait Applications extends Compatibility { def makeVarArg(n: Int, elemFormal: Type): Unit = { val args = typedArgBuf.takeRight(n).toList typedArgBuf.dropRightInPlace(n) - val elemtpt = TypeTree(elemFormal, inferred = true) + val elemtpt = TypeTree(elemFormal.normalizedTupleType, inferred = true) typedArgBuf += seqToRepeated(SeqLiteral(args, elemtpt)) } diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 4f596776d497..761a24e10474 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -53,7 +53,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): if defn.SpecialClassTagClasses.contains(sym) then classTagModul.select(sym.name.toTermName).withSpan(span) else - val ctype = escapeJavaArray(erasure(tp)) + val ctype = escapeJavaArray(erasure(tp.normalizedTupleType)) if ctype.exists then classTagModul.select(nme.apply) .appliedToType(tp) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 915bfb8ee1e1..7d2bf2f463ba 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -847,10 +847,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // Otherwise, map combinations of A *: B *: .... EmptyTuple with nesting levels <= 22 // to the Tuple class of the right arity and select from that one def trySmallGenericTuple(qual: Tree, withCast: Boolean) = - if qual.tpe.isSmallGenericTuple then + val tp = qual.tpe.widenTermRefExpr + val tpNormalized = tp.normalizedTupleType + if tp ne tpNormalized then if withCast then - val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil) - typedSelectWithAdapt(tree, pt, qual.cast(defn.tupleType(elems))) + typedSelectWithAdapt(tree, pt, qual.cast(tpNormalized)) else typedSelectWithAdapt(tree, pt, qual) else EmptyTree diff --git a/tests/run/i22345.scala b/tests/run/i22345.scala new file mode 100644 index 000000000000..86cc3a01930e --- /dev/null +++ b/tests/run/i22345.scala @@ -0,0 +1,2 @@ +@main def Test: Unit = + val a: Array[(Int, String)] = Array[Int *: String *: EmptyTuple]() diff --git a/tests/run/i22345b.scala b/tests/run/i22345b.scala new file mode 100644 index 000000000000..a331a66ea80a --- /dev/null +++ b/tests/run/i22345b.scala @@ -0,0 +1,2 @@ +@main def Test: Unit = + val a: Array[(Int, String)] = Array[Int *: String *: EmptyTuple]((1, "hello")) diff --git a/tests/run/i22345c.scala b/tests/run/i22345c.scala new file mode 100644 index 000000000000..25bafae0c390 --- /dev/null +++ b/tests/run/i22345c.scala @@ -0,0 +1,4 @@ +def makeSeq[T](args: T*): Seq[T] = args + +@main def Test: Unit = + val a: Array[(Int, String)] = makeSeq[Int *: String *: EmptyTuple]().toArray