From e329739e14d06e0c296cd8a77a4e89fa124fde1f Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Wed, 23 Oct 2024 22:30:34 +0200 Subject: [PATCH] improve the pattern type from the switch expression type + uses findSubtypeCorrespondingTo() extracted from #3024 --- .../compiler/ast/EitherOrMultiPattern.java | 7 ++ .../internal/compiler/ast/GuardedPattern.java | 6 + .../internal/compiler/ast/RecordPattern.java | 13 +- .../lookup/ParameterizedTypeBinding.java | 113 +++++++++--------- 4 files changed, 75 insertions(+), 64 deletions(-) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/EitherOrMultiPattern.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/EitherOrMultiPattern.java index 9d4e81fe9b0..8ef74f12e1c 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/EitherOrMultiPattern.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/EitherOrMultiPattern.java @@ -54,6 +54,13 @@ public void setIsGuarded() { this.patterns[i].setIsGuarded(); } + @Override + public void setOuterExpressionType(TypeBinding expressionType) { + super.setOuterExpressionType(expressionType); + for (int i = 0; i < this.patternsCount; i++) + this.patterns[i].setOuterExpressionType(expressionType); + } + @Override public TypeBinding resolveType(BlockScope scope) { boolean hasError = false; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java index e6ea35d4fa6..47e6f2b846f 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java @@ -76,6 +76,12 @@ public void setIsEitherOrPattern() { this.primaryPattern.setIsEitherOrPattern(); } + @Override + public void setOuterExpressionType(TypeBinding expressionType) { + super.setOuterExpressionType(expressionType); + this.primaryPattern.setOuterExpressionType(expressionType); + } + @Override public boolean coversType(TypeBinding type, Scope scope) { return isUnguarded() && this.primaryPattern.coversType(type, scope); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java index bc26d4f3489..29168628300 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java @@ -23,15 +23,7 @@ import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.lookup.*; public class RecordPattern extends Pattern { @@ -141,6 +133,9 @@ public TypeBinding resolveType(BlockScope scope) { } this.isTotalTypeNode = super.coversType(this.resolvedType, scope); + TypeBinding recordType = this.resolvedType; + if (recordType instanceof ParameterizedTypeBinding ptb && this.outerExpressionType instanceof ParameterizedTypeBinding outerBinding) + recordType = outerBinding.findSubtypeCorrespondingTo(ptb); RecordComponentBinding[] components = this.resolvedType.capture(scope, this.sourceStart, this.sourceEnd).components(); for (int i = 0; i < components.length; i++) { Pattern p1 = this.patterns[i]; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java index 35d2a9fb398..ec061043dd8 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java @@ -1110,68 +1110,71 @@ public boolean isRawSubstitution() { @Override public ReferenceBinding[] permittedTypes() { List permittedTypes = new ArrayList<>(); -NextPermittedType: for (ReferenceBinding pt : this.type.permittedTypes()) { - // Step 1: Gather all type variables that would need to be solved. - Map map = new HashMap<>(); - TypeBinding current = pt; - do { - if (current.kind() == Binding.GENERIC_TYPE) { - for (TypeVariableBinding tvb : current.typeVariables()) { - map.put(tvb, null); - } + pt = this.findSubtypeCorrespondingTo(pt); + + if (pt != null && pt.isCompatibleWith(this)) + permittedTypes.add(pt); + } + + return permittedTypes.toArray(new ReferenceBinding[0]); + } + + public ReferenceBinding findSubtypeCorrespondingTo(ReferenceBinding pt) { + // Step 1: Gather all type variables that would need to be solved. + Map map = new HashMap<>(); + TypeBinding current = pt; + do { + if (current.kind() == Binding.GENERIC_TYPE) { + for (TypeVariableBinding tvb : current.typeVariables()) { + map.put(tvb, null); } - current = current.enclosingType(); - } while (current != null); - - // Step 2: Collect substitutes - current = this; - TypeBinding sooper = pt.findSuperTypeOriginatingFrom(this); - do { - if (sooper.isParameterizedType()) { - if (current.isParameterizedType()) { - for (int i = 0, length = sooper.typeArguments().length; i < length; i++) { - TypeBinding t = sooper.typeArguments()[i]; - if (t instanceof TypeVariableBinding tvb) { - map.put(tvb, current.typeArguments()[i]); - } else if (TypeBinding.notEquals(t, this.typeArguments()[i])) { - continue NextPermittedType; - } + } + current = current.enclosingType(); + } while (current != null); + + // Step 2: Collect substitutes + current = this; + TypeBinding sooper = pt.findSuperTypeOriginatingFrom(this); + do { + if (sooper.isParameterizedType()) { + if (current.isParameterizedType()) { + for (int i = 0, length = sooper.typeArguments().length; i < length; i++) { + TypeBinding t = sooper.typeArguments()[i]; + if (t instanceof TypeVariableBinding tvb) { + map.put(tvb, current.typeArguments()[i]); + } else if (TypeBinding.notEquals(t, this.typeArguments()[i])) { + return null; // not matchable } } } - current = current.enclosingType(); - sooper = sooper.enclosingType(); - } while (current != null); - - Substitution substitution = new Substitution() { - @Override - public LookupEnvironment environment() { - return ParameterizedTypeBinding.this.environment; - } - @Override - public boolean isRawSubstitution() { - return false; - } - @Override - public TypeBinding substitute(TypeVariableBinding typeVariable) { - TypeBinding retVal = map.get(typeVariable.unannotated()); - if (retVal == null) { - retVal = ParameterizedTypeBinding.this.environment.createWildcard((ReferenceBinding) typeVariable.declaringElement, typeVariable.rank, null, null, Wildcard.UNBOUND); - map.put(typeVariable, retVal); - } - return retVal; + } + current = current.enclosingType(); + sooper = sooper.enclosingType(); + } while (current != null); + + Substitution substitution = new Substitution() { + @Override + public LookupEnvironment environment() { + return ParameterizedTypeBinding.this.environment; + } + @Override + public boolean isRawSubstitution() { + return false; + } + @Override + public TypeBinding substitute(TypeVariableBinding typeVariable) { + TypeBinding retVal = map.get(typeVariable.unannotated()); + if (retVal == null) { + retVal = ParameterizedTypeBinding.this.environment.createWildcard((ReferenceBinding) typeVariable.declaringElement, typeVariable.rank, null, null, Wildcard.UNBOUND); + map.put(typeVariable, retVal); } - }; - - // Step 3: compute subtype with parameterizations if any. - pt = (ReferenceBinding) Scope.substitute(substitution, pt); - - if (pt.isCompatibleWith(this)) - permittedTypes.add(pt); - } + return retVal; + } + }; - return permittedTypes.toArray(new ReferenceBinding[0]); + // Step 3: compute subtype with parameterizations if any. + return (ReferenceBinding) Scope.substitute(substitution, pt); } @Override