Skip to content

Commit 275bcd0

Browse files
committed
Record type inference fails when 'var' and <> mixed
Fixes eclipse-jdt#1361
1 parent df7f21e commit 275bcd0

File tree

2 files changed

+56
-32
lines changed

2 files changed

+56
-32
lines changed

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,48 +1149,52 @@ public boolean reduceAndIncorporate(ConstraintFormula constraint) throws Inferen
11491149
final int numVars = variableSet.size();
11501150
if (numVars > 0) {
11511151
final InferenceVariable[] variables = variableSet.toArray(new InferenceVariable[numVars]);
1152-
variables: if (!isRecordPatternTypeInference && !tmpBoundSet.hasCaptureBound(variableSet)) {
1152+
variables: if (!tmpBoundSet.hasCaptureBound(variableSet)) {
11531153
// try to instantiate this set of variables in a fresh copy of the bound set:
11541154
BoundSet prevBoundSet = tmpBoundSet;
11551155
tmpBoundSet = tmpBoundSet.copy();
11561156
for (int j = 0; j < variables.length; j++) {
11571157
InferenceVariable variable = variables[j];
1158-
// try lower bounds:
1159-
TypeBinding[] lowerBounds = tmpBoundSet.lowerBounds(variable, true/*onlyProper*/);
1160-
if (lowerBounds != Binding.NO_TYPES) {
1161-
TypeBinding lub = this.scope.lowerUpperBound(lowerBounds);
1162-
if (lub == TypeBinding.VOID || lub == null)
1163-
return null;
1164-
tmpBoundSet.addBound(new TypeBound(variable, lub, ReductionResult.SAME), this.environment);
1158+
if (isRecordPatternTypeInference) {
1159+
tmpBoundSet.addBound(new TypeBound(variable, this.object, ReductionResult.SAME), this.environment);
11651160
} else {
1166-
TypeBinding[] upperBounds = tmpBoundSet.upperBounds(variable, true/*onlyProper*/);
1167-
// check exception bounds:
1168-
if (tmpBoundSet.inThrows.contains(variable.prototype()) && tmpBoundSet.hasOnlyTrivialExceptionBounds(variable, upperBounds)) {
1169-
TypeBinding runtimeException = this.scope.getType(TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION, 3);
1170-
tmpBoundSet.addBound(new TypeBound(variable, runtimeException, ReductionResult.SAME), this.environment);
1161+
// try lower bounds:
1162+
TypeBinding[] lowerBounds = tmpBoundSet.lowerBounds(variable, true/*onlyProper*/);
1163+
if (lowerBounds != Binding.NO_TYPES) {
1164+
TypeBinding lub = this.scope.lowerUpperBound(lowerBounds);
1165+
if (lub == TypeBinding.VOID || lub == null)
1166+
return null;
1167+
tmpBoundSet.addBound(new TypeBound(variable, lub, ReductionResult.SAME), this.environment);
11711168
} else {
1172-
// try upper bounds:
1173-
TypeBinding glb = this.object;
1174-
if (upperBounds != Binding.NO_TYPES) {
1175-
if (upperBounds.length == 1) {
1176-
glb = upperBounds[0];
1177-
} else {
1178-
TypeBinding[] glbs = Scope.greaterLowerBound(upperBounds, this.scope, this.environment);
1179-
if (glbs == null) {
1180-
return null;
1181-
} else if (glbs.length == 1) {
1182-
glb = glbs[0];
1169+
TypeBinding[] upperBounds = tmpBoundSet.upperBounds(variable, true/*onlyProper*/);
1170+
// check exception bounds:
1171+
if (tmpBoundSet.inThrows.contains(variable.prototype()) && tmpBoundSet.hasOnlyTrivialExceptionBounds(variable, upperBounds)) {
1172+
TypeBinding runtimeException = this.scope.getType(TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION, 3);
1173+
tmpBoundSet.addBound(new TypeBound(variable, runtimeException, ReductionResult.SAME), this.environment);
1174+
} else {
1175+
// try upper bounds:
1176+
TypeBinding glb = this.object;
1177+
if (upperBounds != Binding.NO_TYPES) {
1178+
if (upperBounds.length == 1) {
1179+
glb = upperBounds[0];
11831180
} else {
1184-
glb = intersectionFromGlb(glbs);
1185-
if (glb == null) {
1186-
// inconsistent intersection
1187-
tmpBoundSet = prevBoundSet; // clean up
1188-
break variables; // and start over
1181+
TypeBinding[] glbs = Scope.greaterLowerBound(upperBounds, this.scope, this.environment);
1182+
if (glbs == null) {
1183+
return null;
1184+
} else if (glbs.length == 1) {
1185+
glb = glbs[0];
1186+
} else {
1187+
glb = intersectionFromGlb(glbs);
1188+
if (glb == null) {
1189+
// inconsistent intersection
1190+
tmpBoundSet = prevBoundSet; // clean up
1191+
break variables; // and start over
1192+
}
11891193
}
11901194
}
11911195
}
1196+
tmpBoundSet.addBound(new TypeBound(variable, glb, ReductionResult.SAME), this.environment);
11921197
}
1193-
tmpBoundSet.addBound(new TypeBound(variable, glb, ReductionResult.SAME), this.environment);
11941198
}
11951199
}
11961200
}

org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordPatternTest.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2022, 2023 IBM Corporation and others.
2+
* Copyright (c) 2022, 2025 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -28,7 +28,7 @@ public class RecordPatternTest extends AbstractRegressionTest9 {
2828
static {
2929
// TESTS_NUMBERS = new int [] { 40 };
3030
// TESTS_RANGE = new int[] { 1, -1 };
31-
// TESTS_NAMES = new String[] { "testRecordTypeInfer_4643" };
31+
// TESTS_NAMES = new String[] { "testRecordPatternTypeInference_001" };
3232
}
3333
private String extraLibPath;
3434
public static Class<?> testClass() {
@@ -5089,5 +5089,25 @@ public static void main(String[] args) {
50895089
"Record component with type Integer is not compatible with type String\n" +
50905090
"----------\n");
50915091
}
5092+
public void testRecordTypeInfer_1361_001() {
5093+
runConformTest(new String[] { "X.java",
5094+
"""
5095+
record Record<T>(T a) {}
5096+
public class X {
5097+
static void test(Object o) {
5098+
if (o instanceof Record(var x)) {
5099+
var v = new Record<>(x);
5100+
Record<Object> r = v;
5101+
System.out.println(true);
5102+
}
5103+
}
5104+
public static void main(String[] args) {
5105+
Record<Integer> r = new Record<>(10);
5106+
test(r);
5107+
}
5108+
}
5109+
""" },
5110+
"true");
5111+
}
50925112

50935113
}

0 commit comments

Comments
 (0)