Skip to content

Commit

Permalink
8250625: Compiler implementation of Pattern Matching for instanceof (…
Browse files Browse the repository at this point in the history
…Final)

Reviewed-by: vromero
  • Loading branch information
lahodaj committed Nov 5, 2020
1 parent 60e4aca commit 18bc95b
Show file tree
Hide file tree
Showing 86 changed files with 231 additions and 313 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
public boolean essentialAPI() default false;

public enum Feature {
PATTERN_MATCHING_IN_INSTANCEOF,
// 8242284:
// The TEXT_BLOCKS enum constant is not used in the JDK 15 codebase, but
// exists to support the bootcycle build of JDK 15. The bootcycle build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,9 @@ public enum ElementKind {
RECORD_COMPONENT,

/**
* {@preview Associated with pattern matching for {@code
* instanceof}, a preview feature of the Java language.
*
* This enum constant is associated with <i>pattern
* matching for {@code instanceof}</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* A binding variable in a pattern .
* @since 14
* A binding variable in a pattern.
* @since 16
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.PATTERN_MATCHING_IN_INSTANCEOF,
essentialAPI=false)
BINDING_VARIABLE;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,34 +25,17 @@

package com.sun.source.tree;

import javax.lang.model.element.Name;

/**
* {@preview Associated with pattern matching for instanceof, a preview feature of
* the Java language.
*
* This interface is associated with <i>pattern matching for instanceof</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* A binding pattern tree
*
* @since 14
* @since 16
*/
public interface BindingPatternTree extends PatternTree {

/**
* Returns the type of the bind variable.
* @return the type
* Returns the binding variable.
* @return the binding variable
*/
Tree getType();

/**
* A binding variable name.
* @return the name of the binding variable
*/
Name getBinding();
VariableTree getVariable();

}

Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,11 @@ public interface InstanceOfTree extends ExpressionTree {
/**
* Returns the type for which to check.
* @return the type
* @see #getPattern()
*/
Tree getType();

/**
* {@preview Associated with pattern matching for instanceof, a preview feature of
* the Java language.
*
* This method is associated with <i>pattern matching for instanceof</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns the tested pattern, or null if this instanceof does not use
* a pattern.
*
Expand All @@ -77,7 +70,7 @@ public interface InstanceOfTree extends ExpressionTree {
* returns null.
*
* @return the tested pattern, or null if this instanceof does not use a pattern
* @since 14
* @since 16
*/
PatternTree getPattern();
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,9 @@
package com.sun.source.tree;

/**
* {@preview Associated with pattern matching for instanceof, a preview feature of
* the Java language.
*
* This interface is associated with <i>pattern matching for instanceof</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* A tree node used as the base class for the different kinds of
* statements.
* patterns.
*
* @since 14
* @since 16
*/
public interface PatternTree extends Tree {}
10 changes: 1 addition & 9 deletions src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,17 +220,9 @@ public enum Kind {
PARENTHESIZED(ParenthesizedTree.class),

/**
* {@preview Associated with pattern matching for instanceof, a preview feature of
* the Java language.
*
* This enum constant is associated with <i>pattern matching for instanceof</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Used for instances of {@link BindingPatternTree}.
*
* @since 14
* @since 16
*/
BINDING_PATTERN(BindingPatternTree.class),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,19 +258,11 @@ public interface TreeVisitor<R,P> {
R visitLiteral(LiteralTree node, P p);

/**
* {@preview Associated with pattern matching for instanceof, a preview feature of
* the Java language.
*
* This method is associated with <i>pattern matching for instanceof</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Visits an BindingPattern node.
* @param node the node being visited
* @param p a parameter value
* @return a result value
* @since 14
* @since 16
*/
R visitBindingPattern(BindingPatternTree node, P p);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ public R visitInstanceOf(InstanceOfTree node, P p) {
*/
@Override
public R visitBindingPattern(BindingPatternTree node, P p) {
return scan(node.getType(), p);
return scan(node.getVariable(), p);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,7 @@ public boolean isEnabled() {
* @return true, if given feature is a preview feature.
*/
public boolean isPreview(Feature feature) {
if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF ||
feature == Feature.REIFIABLE_TYPES_INSTANCEOF ||
feature == Feature.SEALED_CLASSES)
if (feature == Feature.SEALED_CLASSES)
return true;
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
//When real preview features will be added, this method can be implemented to return 'true'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1855,7 +1855,7 @@ public Name getSimpleName() {
public static class BindingSymbol extends VarSymbol {

public BindingSymbol(Name name, Type type, Symbol owner) {
super(Flags.FINAL | Flags.HASINIT | Flags.MATCH_BINDING, name, type, owner);
super(Flags.HASINIT | Flags.MATCH_BINDING, name, type, owner);
}

public boolean isAliasFor(BindingSymbol b) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -951,9 +951,8 @@ private Attribute.TypeCompound toTypeCompound(Attribute.Compound a, TypeAnnotati
" within frame " + frame);
}

case BINDING_PATTERN:
case VARIABLE:
VarSymbol v = frame.hasTag(Tag.BINDINGPATTERN) ? ((JCBindingPattern) frame).symbol : ((JCVariableDecl) frame).sym;
VarSymbol v = ((JCVariableDecl) frame).sym;
if (v.getKind() != ElementKind.FIELD) {
appendTypeAnnotationsToOwner(v, v.getRawTypeAttributes());
}
Expand Down
36 changes: 21 additions & 15 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,6 @@ void checkAssignable(DiagnosticPosition pos, VarSymbol v, JCTree base, Env<AttrC
isAssignableAsBlankFinal(v, env)))) {
if (v.isResourceVariable()) { //TWR resource
log.error(pos, Errors.TryResourceMayNotBeAssigned(v));
} else if ((v.flags() & MATCH_BINDING) != 0) {
log.error(pos, Errors.PatternBindingMayNotBeAssigned(v));
} else {
log.error(pos, Errors.CantAssignValToFinalVar(v));
}
Expand Down Expand Up @@ -3933,10 +3931,14 @@ public void visitTypeTest(JCInstanceOf tree) {
if (tree.pattern.getTag() == BINDINGPATTERN) {
attribTree(tree.pattern, env, unknownExprInfo);
clazztype = tree.pattern.type;
if (types.isSubtype(exprtype, clazztype) &&
!exprtype.isErroneous() && !clazztype.isErroneous()) {
log.error(tree.pos(), Errors.InstanceofPatternNoSubtype(clazztype, exprtype));
}
JCBindingPattern pattern = (JCBindingPattern) tree.pattern;
typeTree = pattern.vartype;
typeTree = pattern.var.vartype;
if (!clazztype.hasTag(TYPEVAR)) {
clazztype = chk.checkClassOrArrayType(pattern.vartype.pos(), clazztype);
clazztype = chk.checkClassOrArrayType(pattern.var.vartype.pos(), clazztype);
}
} else {
clazztype = attribType(tree.pattern, env);
Expand All @@ -3962,7 +3964,9 @@ public void visitTypeTest(JCInstanceOf tree) {
valid = true;
}
} else {
log.error(typeTree.pos(), Errors.IllegalGenericTypeForInstof);
log.error(DiagnosticFlag.SOURCE_LEVEL, tree.pos(),
Feature.REIFIABLE_TYPES_INSTANCEOF.error(this.sourceName));
allowReifiableTypesInInstanceof = true;
}
if (!valid) {
clazztype = types.createErrorType(clazztype);
Expand All @@ -3975,15 +3979,17 @@ public void visitTypeTest(JCInstanceOf tree) {

public void visitBindingPattern(JCBindingPattern tree) {
ResultInfo varInfo = new ResultInfo(KindSelector.TYP, resultInfo.pt, resultInfo.checkContext);
tree.type = attribTree(tree.vartype, env, varInfo);
VarSymbol v = tree.symbol = new BindingSymbol(tree.name, tree.vartype.type, env.info.scope.owner);
if (chk.checkUnique(tree.pos(), v, env.info.scope)) {
chk.checkTransparentVar(tree.pos(), v, env.info.scope);
}
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, env, v, tree.pos());
tree.type = tree.var.type = attribTree(tree.var.vartype, env, varInfo);
BindingSymbol v = new BindingSymbol(tree.var.name, tree.var.vartype.type, env.info.scope.owner);
v.pos = tree.pos;
tree.var.sym = v;
if (chk.checkUnique(tree.var.pos(), v, env.info.scope)) {
chk.checkTransparentVar(tree.var.pos(), v, env.info.scope);
}
annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v, tree.var.pos());
annotate.flush();
result = tree.type;
matchBindings = new MatchBindings(List.of(tree.symbol), List.nil());
matchBindings = new MatchBindings(List.of(v), List.nil());
}

public void visitIndexed(JCArrayAccess tree) {
Expand Down Expand Up @@ -5733,9 +5739,9 @@ public void visitVarDef(JCVariableDecl that) {

@Override
public void visitBindingPattern(JCBindingPattern that) {
if (that.symbol == null) {
that.symbol = new BindingSymbol(that.name, that.type, syms.noSymbol);
that.symbol.adr = 0;
if (that.var.sym == null) {
that.var.sym = new BindingSymbol(that.var.name, that.var.type, syms.noSymbol);
that.var.sym.adr = 0;
}
super.visitBindingPattern(that);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1875,7 +1875,8 @@ void checkInit(DiagnosticPosition pos, VarSymbol sym) {
void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
trackable(sym) &&
!inits.isMember(sym.adr)) {
!inits.isMember(sym.adr) &&
(sym.flags_field & CLASH) == 0) {
log.error(pos, errkey);
inits.incl(sym.adr);
}
Expand Down Expand Up @@ -2758,6 +2759,12 @@ public void visitIdent(JCIdent tree) {
}
}

@Override
public void visitBindingPattern(JCBindingPattern tree) {
super.visitBindingPattern(tree);
initParam(tree.var);
}

void referenced(Symbol sym) {
unrefdResources.remove(sym);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ private List<BindingSymbol> intersection(DiagnosticPosition pos, List<BindingSym
(v1.flags() & CLASH) == 0 &&
(v2.flags() & CLASH) == 0) {
log.error(pos, Errors.MatchBindingExists);
v2.flags_field |= CLASH;
list = list.append(v2);
}
}
Expand All @@ -166,6 +167,7 @@ private final List<BindingSymbol> union(DiagnosticPosition pos, List<BindingSymb
(ov.flags() & CLASH) == 0 &&
(v.flags() & CLASH) == 0) {
log.error(pos, Errors.MatchBindingExists);
v.flags_field |= CLASH;
}
}
list = list.append(v);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,20 +153,20 @@ public void visitTypeTest(JCInstanceOf tree) {
//=>
//(let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp))
JCBindingPattern patt = (JCBindingPattern)tree.pattern;
VarSymbol pattSym = patt.symbol;
VarSymbol pattSym = patt.var.sym;
Type tempType = tree.expr.type.hasTag(BOT) ?
syms.objectType
: tree.expr.type;
VarSymbol temp = new VarSymbol(pattSym.flags() | Flags.SYNTHETIC,
names.fromString(pattSym.name.toString() + target.syntheticNameChar() + "temp"),
tempType,
patt.symbol.owner);
patt.var.sym.owner);
JCExpression translatedExpr = translate(tree.expr);
Type castTargetType = types.boxedTypeOrType(pattSym.erasure(types));

result = makeTypeTest(make.Ident(temp), make.Type(castTargetType));

VarSymbol bindingVar = bindingContext.bindingDeclared(patt.symbol);
VarSymbol bindingVar = bindingContext.bindingDeclared((BindingSymbol) patt.var.sym);
if (bindingVar != null) { //TODO: cannot be null here?
JCAssign fakeInit = (JCAssign)make.at(tree.pos).Assign(
make.Ident(bindingVar), convert(make.Ident(temp), castTargetType)).setType(bindingVar.erasure(types));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,9 +568,7 @@ public void visitCase(JCCase tree) {
}

public void visitBindingPattern(JCBindingPattern tree) {
if (tree.vartype != null) {
tree.vartype = translate(tree.vartype, null);
}
tree.var = translate(tree.var, null);
result = tree;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,10 @@ && scan(tree.rhs, that.rhs)
@Override
public void visitBindingPattern(JCBindingPattern tree) {
JCBindingPattern that = (JCBindingPattern) parameter;
result =
scan(tree.vartype, that.vartype)
&& tree.name == that.name;
result = scan(tree.var, that.var);
if (!result) {
return;
}
equiv.put(tree.symbol, that.symbol);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,6 @@ public void visitSelect(JCFieldAccess tree) {
super.visitSelect(tree);
}

@Override
public void visitBindingPattern(JCTree.JCBindingPattern tree) {
symbolHashes.computeIfAbsent(tree.symbol, k -> symbolHashes.size());
super.visitBindingPattern(tree);
}

@Override
public void visitVarDef(JCVariableDecl tree) {
symbolHashes.computeIfAbsent(tree.sym, k -> symbolHashes.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -932,10 +932,18 @@ JCExpression term2Rest(JCExpression t, int minprec) {
if (token.kind == INSTANCEOF) {
int pos = token.pos;
nextToken();
JCTree pattern = parseType();
int typePos = token.pos;
JCExpression type = parseType();
JCTree pattern;
if (token.kind == IDENTIFIER) {
checkSourceLevel(token.pos, Feature.PATTERN_MATCHING_IN_INSTANCEOF);
pattern = toP(F.at(token.pos).BindingPattern(ident(), pattern));
JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
JCVariableDecl var = toP(F.at(token.pos).VarDef(mods, ident(), type, null));
TreeInfo.getStartPos(var);
pattern = toP(F.at(typePos).BindingPattern(var));
TreeInfo.getStartPos(pattern);
} else {
pattern = type;
}
odStack[top] = F.at(pos).TypeTest(odStack[top], pattern);
} else {
Expand Down
Loading

0 comments on commit 18bc95b

Please sign in to comment.