Skip to content

Commit 835cf96

Browse files
Generic record pattern not working in EJC (#4627)
+ remove unmotivated check parameterizedWithWildcard() + consistently use the captured type Tc + extract wildcard from the expected capture + do not replace type arguments with type variables - substitute only betas for captures, all else remains Fixes #4002
1 parent 4f93d44 commit 835cf96

File tree

2 files changed

+63
-26
lines changed

2 files changed

+63
-26
lines changed

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

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2014,27 +2014,23 @@ private boolean findRPrimeAndResultingBounds(TypeBinding typeBinding, InferenceV
20142014
return true;
20152015
}
20162016
private TypeBinding deriveTPrime(RecordPattern recordPattern, TypeBinding candidateT, InferenceVariable[] alphas, TypeBinding typeBinding) {
2017-
ParameterizedTypeBinding parameterizedType = null;
2018-
TypeBinding tPrime = null;
2019-
if (candidateT.isParameterizedType()) {
2020-
parameterizedType = InferenceContext18.parameterizedWithWildcard(candidateT);
2021-
}
2022-
if (parameterizedType != null && parameterizedType.arguments != null) {
2023-
TypeBinding[] arguments = parameterizedType.capture(this.scope, recordPattern.sourceStart, recordPattern.sourceEnd).arguments;
2017+
TypeBinding tPrime = candidateT.capture(this.scope, recordPattern.sourceStart, recordPattern.sourceEnd);
2018+
if (tPrime instanceof ParameterizedTypeBinding parameterizedType && parameterizedType.arguments != null) {
2019+
TypeBinding[] arguments = parameterizedType.arguments;
20242020
/* addTypeVariableSubstitutions() gives a beta for every argument which is
20252021
* a super set of betas required by 18_5_5_item_3_bullet_1 betas.
20262022
* this happens since we are just reusing 18.5.2.1 utility
20272023
* And hence the name notJust18_5_5_item_3_bullet_1Betas
20282024
* TODO: a Just18_5_5_item_3_bullet_1Betas utility?
20292025
*/
20302026
InferenceVariable[] notJust18_5_5_item_3_bullet_1Betas = addTypeVariableSubstitutions(arguments, true);
2031-
TypeVariableBinding[] typeVariables = getTPrimeArgumentsAndCreateBounds(parameterizedType,
2027+
TypeBinding[] typeArguments = getTPrimeArgumentsAndCreateBounds(parameterizedType,
20322028
notJust18_5_5_item_3_bullet_1Betas);
20332029
tPrime = this.environment.createParameterizedType(
2034-
parameterizedType.genericType(), typeVariables,
2030+
parameterizedType.genericType(), typeArguments,
20352031
parameterizedType.enclosingType(), parameterizedType.getTypeAnnotations());
2036-
createAdditionalBoundswithU((ParameterizedTypeBinding) tPrime, notJust18_5_5_item_3_bullet_1Betas, typeVariables);
2037-
} else if (candidateT.isTypeVariable() || candidateT.isIntersectionType18()) {
2032+
createAdditionalBoundswithU((ParameterizedTypeBinding) tPrime, notJust18_5_5_item_3_bullet_1Betas, typeArguments);
2033+
} else if (tPrime.isTypeVariable() || tPrime.isIntersectionType18()) {
20382034
// 18.5.5_item_3_bullet_3
20392035
/* If T is a type variable or an intersection type, then for each upper bound of the type
20402036
* variable or element of the intersection type, this step and step 4 are repeated
@@ -2051,20 +2047,20 @@ private TypeBinding deriveTPrime(RecordPattern recordPattern, TypeBinding candid
20512047
return null;
20522048
}
20532049
}
2054-
return tPrime = candidateT; //18.5.5_item_3_bullet_2
2050+
return tPrime = candidateT; //18.5.5_item_3_bullet_4
20552051
} else if (candidateT.isClass() || candidateT.isInterface()) {
20562052
tPrime = candidateT; //18.5.5_item_3_bullet_2
20572053
}
20582054
return tPrime;
20592055
}
20602056

20612057
private void createAdditionalBoundswithU(ParameterizedTypeBinding tPrime, InferenceVariable[] notJust18_5_5_item_3_bullet_1Betas,
2062-
TypeVariableBinding[] typeVariables) {
2058+
TypeBinding[] typeArguments) {
20632059
TypeVariableBinding[] typeParams = tPrime.original().typeVariables();
20642060
TypeBinding[] aArr = tPrime.typeArguments();
20652061
for (int i = 0, l = notJust18_5_5_item_3_bullet_1Betas.length; i < l; ++i) {
20662062
InferenceVariable beta = notJust18_5_5_item_3_bullet_1Betas[i];
2067-
if (beta == null || !beta.equals(typeVariables[i])) continue; //not an expected inference variable.
2063+
if (beta == null || !beta.equals(typeArguments[i])) continue; //not an expected inference variable.
20682064

20692065
TypeBinding[] uArr = typeParams[i]!= null ? typeParams[i].allUpperBounds() : null;
20702066
if (uArr == null || uArr.length == 0) {
@@ -2095,17 +2091,17 @@ private void createAdditionalBoundswithU(ParameterizedTypeBinding tPrime, Infere
20952091
}
20962092
}
20972093

2098-
private TypeVariableBinding[] getTPrimeArgumentsAndCreateBounds(
2094+
private TypeBinding[] getTPrimeArgumentsAndCreateBounds(
20992095
ParameterizedTypeBinding parameterizedType,
21002096
InferenceVariable[] beta) {
21012097
TypeBinding[] arguments = parameterizedType.typeArguments();
2102-
TypeVariableBinding[] typeVariables = new TypeVariableBinding[arguments.length];
2098+
TypeBinding[] typearguments = Arrays.copyOf(arguments, arguments.length);
21032099
InferenceSubstitution theta = new InferenceSubstitution(this.environment, beta, this.currentInvocation);
21042100
TypeBound bound;
21052101
for (int i = 0, l = arguments.length; i < l; ++i) {
21062102
bound = null;
2107-
if (arguments[i].kind() == Binding.WILDCARD_TYPE && beta[i] != null) {
2108-
WildcardBinding wildcard = (WildcardBinding) arguments[i];
2103+
if (arguments[i].getClass() == CaptureBinding.class && beta[i] != null) { // exclude subclass CaptureBinding18
2104+
WildcardBinding wildcard = ((CaptureBinding) arguments[i]).wildcard;
21092105
switch(wildcard.boundKind) {
21102106
case Wildcard.EXTENDS :
21112107
TypeBinding uTheta = Scope.substitute(theta, wildcard.allBounds());
@@ -2121,20 +2117,14 @@ private TypeVariableBinding[] getTPrimeArgumentsAndCreateBounds(
21212117
default:
21222118
continue;
21232119
}
2124-
} else {
2125-
/* As per 18_5_5_item_3_bullet_1 should not have a beta here
2126-
* instead the same typevariable */
2127-
typeVariables[i] = parameterizedType.type.typeVariables()[i];
21282120
}
21292121
if (bound != null) {
21302122
this.currentBounds.addBound(bound, this.environment);
2131-
typeVariables[i] = beta[i];
2132-
} else {
2133-
typeVariables[i] = parameterizedType.type.typeVariables()[i];
2123+
typearguments[i] = beta[i];
21342124

21352125
}
21362126
}
2137-
return typeVariables;
2127+
return typearguments;
21382128
}
21392129

21402130
public boolean isInexactVarargsInference() {

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4999,4 +4999,51 @@ public static void main(String[] args) {
49994999
"'var' is not allowed as an element type of an array\n" +
50005000
"----------\n");
50015001
}
5002+
5003+
public void testGH4002() {
5004+
runConformTest(new String[] {
5005+
"Example.java",
5006+
"""
5007+
import java.util.List;
5008+
5009+
public class Example {
5010+
5011+
private static boolean matches(ComponentType<?> type, ComponentType.RegularComponentType<?> eventType) {
5012+
return switch (type) {
5013+
case ComponentType.RegularComponentType<?> regular -> switch (regular) {
5014+
case ComponentType.ClassType(var clazz) -> switch (eventType) {
5015+
case ComponentType.ClassType(var eventClazz) -> clazz == eventClazz;
5016+
};
5017+
};
5018+
/* Workaround:
5019+
case ComponentType.Wildcard<?> wildcard -> switch (eventType) {
5020+
case ComponentType.ClassType(var eventClazz) -> wildcard.bound().isAssignableFrom(eventClazz);
5021+
};
5022+
/**/
5023+
case ComponentType.Wildcard(var bound) -> switch (eventType) {
5024+
case ComponentType.ClassType(var eventClazz) -> bound.isAssignableFrom(eventClazz);
5025+
};
5026+
/**/
5027+
default -> false;
5028+
};
5029+
}
5030+
5031+
sealed interface ComponentType<T> {
5032+
5033+
sealed interface RegularComponentType<T> extends ComponentType<T> {
5034+
}
5035+
5036+
record ClassType<T>(Class<T> clazz) implements RegularComponentType<T> {
5037+
}
5038+
5039+
// "implements ComponentType<T>" works, javac (JDK 21 & JDK 24) accepts both
5040+
record Wildcard<T>(Class<T> bound) implements ComponentType<List<? extends T>> {
5041+
}
5042+
5043+
}
5044+
5045+
}
5046+
"""
5047+
});
5048+
}
50025049
}

0 commit comments

Comments
 (0)