8371683: TYPE_USE annotation on var lambda parameter should be rejected

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2026-02-25 07:06:55 +00:00
parent e92726c352
commit 6c39d1bb73
10 changed files with 115 additions and 17 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -156,12 +156,22 @@ public class Flags {
@Use({FlagTarget.CLASS})
public static final int IMPLICIT_CLASS = 1<<19;
/** Variable with implicit/inferred type.
*/
@Use(FlagTarget.VARIABLE)
public static final int VAR_VARIABLE = 1<<19;
/** Flag is set for compiler-generated anonymous method symbols
* that `own' an initializer block.
*/
@Use({FlagTarget.METHOD})
public static final int BLOCK = 1<<20;
/** A parameter of a lambda function.
*/
@Use(FlagTarget.VARIABLE)
public static final int LAMBDA_PARAMETER = 1<<20;
/** Flag is set for ClassSymbols that are being compiled from source.
*/
@Use({FlagTarget.CLASS})

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -272,6 +272,7 @@ public enum Source {
CASE_NULL(JDK21, Fragments.FeatureCaseNull, DiagKind.NORMAL),
PATTERN_SWITCH(JDK21, Fragments.FeaturePatternSwitch, DiagKind.PLURAL),
REDUNDANT_STRICTFP(JDK17),
TYPE_ANNOTATIONS_ON_VAR_LAMBDA_PARAMETER(MIN, JDK19),
UNCONDITIONAL_PATTERN_IN_INSTANCEOF(JDK21, Fragments.FeatureUnconditionalPatternsInInstanceof, DiagKind.PLURAL),
RECORD_PATTERNS(JDK21, Fragments.FeatureDeconstructionPatterns, DiagKind.PLURAL),
IMPLICIT_CLASSES(JDK25, Fragments.FeatureImplicitClasses, DiagKind.PLURAL),

View File

@ -4224,7 +4224,8 @@ public class Attr extends JCTree.Visitor {
type = resultInfo.pt;
}
tree.type = tree.var.type = type;
BindingSymbol v = new BindingSymbol(tree.var.mods.flags, tree.var.name, type, env.info.scope.owner);
BindingSymbol v = new BindingSymbol(tree.var.mods.flags | tree.var.declKind.additionalSymbolFlags,
tree.var.name, type, env.info.scope.owner);
v.pos = tree.pos;
tree.var.sym = v;
if (chk.checkUnique(tree.var.pos(), v, env.info.scope)) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -3544,7 +3544,10 @@ public class Check {
if (s.kind == PCK)
applicableTargets.add(names.PACKAGE);
} else if (target == names.TYPE_USE) {
if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
if (s.kind == VAR &&
(s.flags() & Flags.VAR_VARIABLE) != 0 &&
(!Feature.TYPE_ANNOTATIONS_ON_VAR_LAMBDA_PARAMETER.allowedInSource(source) ||
((s.flags() & Flags.LAMBDA_PARAMETER) == 0))) {
//cannot type annotate implicitly typed locals
continue;
} else if (s.kind == TYP || s.kind == VAR ||
@ -5632,8 +5635,8 @@ public class Check {
}
case JCVariableDecl variableDecl -> {
if (variableDecl.vartype != null &&
(variableDecl.sym.flags_field & RECORD) == 0 ||
(variableDecl.sym.flags_field & ~(Flags.PARAMETER | RECORD | GENERATED_MEMBER)) != 0) {
((variableDecl.sym.flags_field & RECORD) == 0 ||
(variableDecl.sym.flags_field & ~(Flags.PARAMETER | RECORD | GENERATED_MEMBER)) != 0)) {
/* we don't want to warn twice so if this variable is a compiler generated parameter of
* a canonical record constructor, we don't want to issue a warning as we will warn the
* corresponding compiler generated private record field anyways

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -281,7 +281,7 @@ public class MemberEnter extends JCTree.Visitor {
: tree.vartype.type;
Name name = tree.name;
VarSymbol v = new VarSymbol(0, name, vartype, enclScope.owner);
v.flags_field = chk.checkFlags(tree.mods.flags, v, tree);
v.flags_field = chk.checkFlags(tree.mods.flags | tree.declKind.additionalSymbolFlags, v, tree);
tree.sym = v;
if (tree.init != null) {
v.flags_field |= HASINIT;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -3902,7 +3902,7 @@ public class JavacParser implements Parser {
if (allowThisIdent ||
!lambdaParameter ||
LAX_IDENTIFIER.test(token.kind) ||
mods.flags != Flags.PARAMETER ||
(mods.flags & ~(Flags.PARAMETER | Flags.LAMBDA_PARAMETER)) != 0 ||
mods.annotations.nonEmpty()) {
JCExpression pn;
if (token.kind == UNDERSCORE && (catchParameter || lambdaParameter)) {
@ -5405,7 +5405,13 @@ public class JavacParser implements Parser {
* LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter
*/
protected JCVariableDecl formalParameter(boolean lambdaParameter, boolean recordComponent) {
JCModifiers mods = !recordComponent ? optFinal(Flags.PARAMETER) : modifiersOpt();
JCModifiers mods;
if (recordComponent) {
mods = modifiersOpt();
} else {
mods = optFinal(Flags.PARAMETER | (lambdaParameter ? Flags.LAMBDA_PARAMETER : 0));
}
if (recordComponent && mods.flags != 0) {
log.error(mods.pos, Errors.RecordCantDeclareFieldModifiers);
}
@ -5436,7 +5442,7 @@ public class JavacParser implements Parser {
}
protected JCVariableDecl implicitParameter() {
JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER | Flags.LAMBDA_PARAMETER);
return variableDeclaratorId(mods, null, false, true, false);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1012,9 +1012,16 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public static class JCVariableDecl extends JCStatement implements VariableTree {
public enum DeclKind {
EXPLICIT, // "SomeType name"
IMPLICIT, // "name"
VAR, // "var name"
EXPLICIT(0), // "SomeType name"
IMPLICIT(Flags.VAR_VARIABLE), // "name"
VAR(Flags.VAR_VARIABLE), // "var name"
;
public final long additionalSymbolFlags;
private DeclKind(long additionalSymbolFlags) {
this.additionalSymbolFlags = additionalSymbolFlags;
}
}
/** variable modifiers */

View File

@ -0,0 +1,9 @@
VarVariables.java:34:36: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.deconstruction.patterns), 19, 21
VarVariables.java:18:9: compiler.err.annotation.type.not.applicable
VarVariables.java:24:14: compiler.err.annotation.type.not.applicable
VarVariables.java:27:14: compiler.err.annotation.type.not.applicable
VarVariables.java:32:14: compiler.err.annotation.type.not.applicable
VarVariables.java:36:37: compiler.err.annotation.type.not.applicable
VarVariables.java:32:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.AutoCloseable
VarVariables.java:36:41: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.String
8 errors

View File

@ -0,0 +1,52 @@
/*
* @test /nodynamiccopyright/
* @bug 8371683
* @summary Test that type annotations cannot appears on 'var' variables
* @compile/fail/ref=VarVariables.out -XDrawDiagnostics VarVariables.java
* @compile/fail/ref=VarVariables-old.out --release 19 -XDrawDiagnostics -XDshould-stop.at=FLOW VarVariables.java
*/
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.util.List;
import java.util.function.Consumer;
class VarVariables {
private void test(Object o) {
@DA var v1 = "";
@DTA var v2 = "";
@TA var v3 = "";
Consumer<String> c1 = (@DA var v) -> {};
Consumer<String> c2 = (@DTA var v) -> {};
Consumer<String> c3 = (@TA var v) -> {};
for (@DA var v = ""; !v.isEmpty(); ) {}
for (@DTA var v = ""; !v.isEmpty(); ) {}
for (@TA var v = ""; !v.isEmpty(); ) {}
for (@DA var v : List.of("")) {}
for (@DTA var v : List.of("")) {}
for (@TA var v : List.of("")) {}
try (@DA var v = open()) {
} catch (Exception ex) {}
try (@DTA var v = open()) {
} catch (Exception ex) {}
try (@TA var v = open()) {
} catch (Exception ex) {}
boolean b1 = o instanceof R(@DA var v);
boolean b2 = o instanceof R(@DTA var v);
boolean b3 = o instanceof R(@TA var v);
}
private AutoCloseable open() {
return null;
}
record R(String str) {}
@Target(ElementType.TYPE_USE)
@interface TA { }
@Target({ElementType.TYPE_USE, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER})
@interface DTA { }
@Target({ElementType.LOCAL_VARIABLE, ElementType.PARAMETER})
@interface DA { }
}

View File

@ -0,0 +1,9 @@
VarVariables.java:18:9: compiler.err.annotation.type.not.applicable
VarVariables.java:21:32: compiler.err.annotation.type.not.applicable
VarVariables.java:24:14: compiler.err.annotation.type.not.applicable
VarVariables.java:27:14: compiler.err.annotation.type.not.applicable
VarVariables.java:32:14: compiler.err.annotation.type.not.applicable
VarVariables.java:36:37: compiler.err.annotation.type.not.applicable
VarVariables.java:32:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.AutoCloseable
VarVariables.java:36:41: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.String
8 errors