Skip to content

Commit

Permalink
improve the pattern type from the switch expression type
Browse files Browse the repository at this point in the history
+ uses findSubtypeCorrespondingTo() extracted from #3024
  • Loading branch information
stephan-herrmann committed Oct 23, 2024
1 parent 7d2f381 commit e329739
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1110,68 +1110,71 @@ public boolean isRawSubstitution() {
@Override
public ReferenceBinding[] permittedTypes() {
List<ReferenceBinding> permittedTypes = new ArrayList<>();
NextPermittedType:
for (ReferenceBinding pt : this.type.permittedTypes()) {
// Step 1: Gather all type variables that would need to be solved.
Map<TypeVariableBinding, TypeBinding> 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<TypeVariableBinding, TypeBinding> 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
Expand Down

0 comments on commit e329739

Please sign in to comment.