From a932d56771249fb21ac7ff1162681a411fb7b5c1 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Thu, 3 Sep 2026 15:50:19 +0200 Subject: [PATCH] Fix Java record unapply crash under explicit nulls #26497 did not consider explicit nulls, specifically the flexible types that are added for Java varargs. This PR fixes a crash when using the unapply under explicit nulls. --- .../src/dotty/tools/dotc/typer/Applications.scala | 4 ++-- .../pos/java-record-varargs-src/J.java | 4 ++++ .../pos/java-record-varargs-src/S.scala | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tests/explicit-nulls/pos/java-record-varargs-src/J.java create mode 100644 tests/explicit-nulls/pos/java-record-varargs-src/S.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 1c5ce218c6da..e8e5589d1a7f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1920,7 +1920,7 @@ trait Applications extends Compatibility { // For `Rec()` we do `Boolean` if componentTypes.isEmpty then defn.BooleanType else if isVararg then - val defn.ArrayOf(elemType) = componentTypes.last.runtimeChecked + val defn.ArrayOf(elemType) = componentTypes.last.stripNull().runtimeChecked val wrapperType = defn.Array_UnapplySeqWrapper.typeRef.appliedTo(elemType) // For `Rec(T*)` we do `Array.UnapplySeqWrapper[T]` if componentTypes.length == 1 then wrapperType @@ -1948,7 +1948,7 @@ trait Applications extends Compatibility { if fields.isEmpty then Literal(Constant(true)) else if isVararg then val lastField = accessor(fields.last) - val defn.ArrayOf(lastElemType) = lastField.tpe.runtimeChecked + val defn.ArrayOf(lastElemType) = lastField.tpe.stripNull().runtimeChecked val lastFieldSeq = ref(defn.ArrayModule.requiredMethod(nme.unapplySeq)) .appliedToType(lastElemType).appliedTo(lastField) if fields.length == 1 then lastFieldSeq diff --git a/tests/explicit-nulls/pos/java-record-varargs-src/J.java b/tests/explicit-nulls/pos/java-record-varargs-src/J.java new file mode 100644 index 000000000000..0c1d4cd44f0b --- /dev/null +++ b/tests/explicit-nulls/pos/java-record-varargs-src/J.java @@ -0,0 +1,4 @@ +public class J { + public record RecVarOnly(String... xs) {} + public record RecVar(int x, String... xs) {} +} diff --git a/tests/explicit-nulls/pos/java-record-varargs-src/S.scala b/tests/explicit-nulls/pos/java-record-varargs-src/S.scala new file mode 100644 index 000000000000..d8c77f86d4f4 --- /dev/null +++ b/tests/explicit-nulls/pos/java-record-varargs-src/S.scala @@ -0,0 +1,15 @@ +import J.* + +def varargOnly(r: RecVarOnly): Unit = + r match + case RecVarOnly(xs*) => xs.foreach(x => ()) + r match + case RecVarOnly(a, rest*) => () + case _ => () + +def varargWithPrefix(r: RecVar): Unit = + r match + case RecVar(x, xs*) => xs.foreach(x => ()) + r match + case RecVar(x, a, b) => () + case _ => ()