8341901: Using 'var' keyword switch pattern matching causes compiler error

Reviewed-by: vromero, abimpoudis
This commit is contained in:
Jan Lahoda 2024-11-19 09:13:37 +00:00
parent 76a55c3cb6
commit 8bd080bcc9
3 changed files with 102 additions and 4 deletions

View File

@ -4198,6 +4198,7 @@ public class Attr extends JCTree.Visitor {
if (chk.checkUnique(tree.var.pos(), v, env.info.scope)) {
chk.checkTransparentVar(tree.var.pos(), v, env.info.scope);
}
chk.validate(tree.var.vartype, env, true);
if (tree.var.isImplicitlyTyped()) {
setSyntheticVariableType(tree.var, type == Type.noType ? syms.errType
: type);
@ -4207,7 +4208,6 @@ public class Attr extends JCTree.Visitor {
annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v, tree.var.pos());
}
annotate.flush();
chk.validate(tree.var.vartype, env, true);
result = tree.type;
if (v.isUnnamedVariable()) {
matchBindings = MatchBindingsComputer.EMPTY;

View File

@ -738,12 +738,18 @@ public class TreeMaker implements JCTree.Factory {
}
/** Create a qualified identifier from a symbol, adding enough qualifications
* to make the reference unique.
* to make the reference unique. The types in the AST nodes will be erased.
*/
public JCExpression QualIdent(Symbol sym) {
return isUnqualifiable(sym)
JCExpression result = isUnqualifiable(sym)
? Ident(sym)
: Select(QualIdent(sym.owner), sym);
if (sym.kind == TYP) {
result.setType(types.erasure(sym.type));
}
return result;
}
/** Create an identifier that refers to the variable declared in given variable

View File

@ -23,18 +23,28 @@
/*
* @test
* @bug 8332725
* @bug 8332725 8341901
* @summary Verify the AST model works correctly for binding patterns with var
*/
import com.sun.source.tree.BindingPatternTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.TreeScanner;
import com.sun.source.util.Trees;
import java.net.URI;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
@ -45,6 +55,7 @@ public class BindingPatternVarTypeModel {
public static void main(String... args) throws Exception {
new BindingPatternVarTypeModel().run();
new BindingPatternVarTypeModel().runVarParameterized();
}
private void run() throws Exception {
@ -86,4 +97,85 @@ public class BindingPatternVarTypeModel {
throw new AssertionError("Didn't find the binding pattern!");
}
}
private void runVarParameterized() throws Exception {
JavaFileObject input =
SimpleJavaFileObject.forSource(URI.create("mem:///Test.java"),
"""
package test;
public class Test {
record R(N.I i) {}
int test(Object o) {
Test.N.I checkType0 = null;
var checkType1 = checkType0;
return switch (o) {
case R(var checkType2) -> 0;
default -> 0;
};
}
static class N<T> {
interface I {}
}
}
""");
DiagnosticListener<JavaFileObject> noErrors = d -> {
if (d.getKind() == Diagnostic.Kind.ERROR) {
throw new IllegalStateException(d.toString());
}
};
JavacTask task =
(JavacTask) compiler.getTask(null, null, noErrors, null, null, List.of(input));
CompilationUnitTree cut = task.parse().iterator().next();
Trees trees = Trees.instance(task);
task.analyze();
new TreePathScanner<Void, Void>() {
private boolean checkAttributes;
@Override
public Void visitVariable(VariableTree node, Void p) {
boolean prevCheckAttributes = checkAttributes;
try {
checkAttributes |=
node.getName().toString().startsWith("checkType");
return super.visitVariable(node, p);
} finally {
checkAttributes = prevCheckAttributes;
}
}
@Override
public Void visitIdentifier(IdentifierTree node, Void p) {
checkType();
return super.visitIdentifier(node, p);
}
@Override
public Void visitMemberSelect(MemberSelectTree node, Void p) {
checkType();
return super.visitMemberSelect(node, p);
}
private void checkType() {
if (!checkAttributes) {
return ;
}
TypeMirror type = trees.getTypeMirror(getCurrentPath());
if (type.getKind() == TypeKind.PACKAGE) {
return ; //OK
}
if (type.getKind() != TypeKind.DECLARED) {
throw new AssertionError("Expected a declared type, but got: " +
type.getKind());
}
if (!((DeclaredType) type).getTypeArguments().isEmpty()) {
throw new AssertionError("Unexpected type arguments: " +
((DeclaredType) type).getTypeArguments());
}
}
}.scan(cut, null);
}
}