Skip to content
Permalink
Browse files

8236670: Conflicting bindings accepted in some cases

Reviewed-by: mcimadamore
  • Loading branch information
Jan Lahoda
Jan Lahoda committed Jan 14, 2020
1 parent eccf39b commit a35d087f540e2618c016c5ec75e53b600be01dbf
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, 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
@@ -228,7 +228,8 @@ public static String toString(long flags) {
public static final long EFFECTIVELY_FINAL = 1L<<41;

/**
* Flag that marks non-override equivalent methods with the same signature.
* Flag that marks non-override equivalent methods with the same signature,
* or a conflicting match binding (BindingSymbol).
*/
public static final long CLASH = 1L<<42;

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, 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
@@ -1785,6 +1785,29 @@ 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);
}

public boolean isAliasFor(BindingSymbol b) {
return aliases().containsAll(b.aliases());
}

List<BindingSymbol> aliases() {
return List.of(this);
}

public void preserveBinding() {
flags_field |= Flags.MATCH_BINDING_TO_OUTER;
}

public boolean isPreserved() {
return (flags_field & Flags.MATCH_BINDING_TO_OUTER) != 0;
}
}

/** A class for method symbols.
*/
public static class MethodSymbol extends Symbol implements ExecutableElement {
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, 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
@@ -49,7 +49,7 @@
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
import com.sun.tools.javac.comp.MatchBindingsComputer.MatchBindings;
import com.sun.tools.javac.jvm.*;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
@@ -642,6 +642,8 @@ KindSelector pkind() {
*/
Type result;

MatchBindings matchBindings = MatchBindingsComputer.EMPTY;

/** Visitor method: attribute a tree, catching any completion failure
* exceptions. Return the tree's type.
*
@@ -660,6 +662,8 @@ Type attribTree(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
} else {
tree.accept(this);
}
matchBindings = matchBindingsComputer.finishBindings(tree,
matchBindings);
if (tree == breakTree &&
resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
breakTreeFound(copyEnv(env));
@@ -1418,30 +1422,27 @@ public void visitDoLoop(JCDoWhileLoop tree) {
attribExpr(tree.cond, env, syms.booleanType);
if (!breaksOutOf(tree, tree.body)) {
//include condition's body when false after the while, if cannot get out of the loop
List<BindingSymbol> bindings = matchBindingsComputer.getMatchBindings(tree.cond, false);

bindings.forEach(env.info.scope::enter);
bindings.forEach(BindingSymbol::preserveBinding);
MatchBindings condBindings = matchBindings;
condBindings.bindingsWhenFalse.forEach(env.info.scope::enter);
condBindings.bindingsWhenFalse.forEach(BindingSymbol::preserveBinding);
}
result = null;
}

public void visitWhileLoop(JCWhileLoop tree) {
attribExpr(tree.cond, env, syms.booleanType);
MatchBindings condBindings = matchBindings;
// include condition's bindings when true in the body:
Env<AttrContext> whileEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true));
Env<AttrContext> whileEnv = bindingEnv(env, condBindings.bindingsWhenTrue);
try {
attribStat(tree.body, whileEnv.dup(tree));
} finally {
whileEnv.info.scope.leave();
}
if (!breaksOutOf(tree, tree.body)) {
//include condition's bindings when false after the while, if cannot get out of the loop
List<BindingSymbol> bindings =
matchBindingsComputer.getMatchBindings(tree.cond, false);

bindings.forEach(env.info.scope::enter);
bindings.forEach(BindingSymbol::preserveBinding);
condBindings.bindingsWhenFalse.forEach(env.info.scope::enter);
condBindings.bindingsWhenFalse.forEach(BindingSymbol::preserveBinding);
}
result = null;
}
@@ -1454,15 +1455,15 @@ private boolean breaksOutOf(JCTree loop, JCTree body) {
public void visitForLoop(JCForLoop tree) {
Env<AttrContext> loopEnv =
env.dup(env.tree, env.info.dup(env.info.scope.dup()));
MatchBindings condBindings = MatchBindingsComputer.EMPTY;
try {
attribStats(tree.init, loopEnv);
List<BindingSymbol> matchBindings = List.nil();
if (tree.cond != null) {
attribExpr(tree.cond, loopEnv, syms.booleanType);
// include condition's bindings when true in the body and step:
matchBindings = matchBindingsComputer.getMatchBindings(tree.cond, true);
condBindings = matchBindings;
}
Env<AttrContext> bodyEnv = bindingEnv(loopEnv, matchBindings);
Env<AttrContext> bodyEnv = bindingEnv(loopEnv, condBindings.bindingsWhenTrue);
try {
bodyEnv.tree = tree; // before, we were not in loop!
attribStats(tree.step, bodyEnv);
@@ -1477,11 +1478,8 @@ public void visitForLoop(JCForLoop tree) {
}
if (!breaksOutOf(tree, tree.body)) {
//include condition's body when false after the while, if cannot get out of the loop
List<BindingSymbol> bindings =
matchBindingsComputer.getMatchBindings(tree.cond, false);

bindings.forEach(env.info.scope::enter);
bindings.forEach(BindingSymbol::preserveBinding);
condBindings.bindingsWhenFalse.forEach(env.info.scope::enter);
condBindings.bindingsWhenFalse.forEach(BindingSymbol::preserveBinding);
}
}

@@ -1818,6 +1816,7 @@ void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resou

public void visitConditional(JCConditional tree) {
Type condtype = attribExpr(tree.cond, env, syms.booleanType);
MatchBindings condBindings = matchBindings;

tree.polyKind = (!allowPoly ||
pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly ||
@@ -1841,21 +1840,25 @@ public void visitConditional(JCConditional tree) {
// include x's bindings when false in z

Type truetype;
Env<AttrContext> trueEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true));
Env<AttrContext> trueEnv = bindingEnv(env, condBindings.bindingsWhenTrue);
try {
truetype = attribTree(tree.truepart, trueEnv, condInfo);
} finally {
trueEnv.info.scope.leave();
}

MatchBindings trueBindings = matchBindings;

Type falsetype;
Env<AttrContext> falseEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, false));
Env<AttrContext> falseEnv = bindingEnv(env, condBindings.bindingsWhenFalse);
try {
falsetype = attribTree(tree.falsepart, falseEnv, condInfo);
} finally {
falseEnv.info.scope.leave();
}

MatchBindings falseBindings = matchBindings;

Type owntype = (tree.polyKind == PolyKind.STANDALONE) ?
condType(List.of(tree.truepart.pos(), tree.falsepart.pos()),
List.of(truetype, falsetype)) : pt();
@@ -1867,6 +1870,7 @@ public void visitConditional(JCConditional tree) {
owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
}
result = check(tree, owntype, KindSelector.VAL, resultInfo);
matchBindings = matchBindingsComputer.conditional(tree, condBindings, trueBindings, falseBindings);
}
//where
private boolean isBooleanOrNumeric(Env<AttrContext> env, JCExpression tree) {
@@ -2022,8 +2026,8 @@ public void visitIf(JCIf tree) {
// include x's bindings when true in y
// include x's bindings when false in z

List<BindingSymbol> thenBindings = matchBindingsComputer.getMatchBindings(tree.cond, true);
Env<AttrContext> thenEnv = bindingEnv(env, thenBindings);
MatchBindings condBindings = matchBindings;
Env<AttrContext> thenEnv = bindingEnv(env, condBindings.bindingsWhenTrue);

try {
attribStat(tree.thenpart, thenEnv);
@@ -2034,10 +2038,9 @@ public void visitIf(JCIf tree) {
preFlow(tree.thenpart);
boolean aliveAfterThen = flow.aliveAfter(env, tree.thenpart, make);
boolean aliveAfterElse;
List<BindingSymbol> elseBindings = matchBindingsComputer.getMatchBindings(tree.cond, false);

if (tree.elsepart != null) {
Env<AttrContext> elseEnv = bindingEnv(env, elseBindings);
Env<AttrContext> elseEnv = bindingEnv(env, condBindings.bindingsWhenFalse);
try {
attribStat(tree.elsepart, elseEnv);
} finally {
@@ -2054,9 +2057,9 @@ public void visitIf(JCIf tree) {
List<BindingSymbol> afterIfBindings = List.nil();

if (aliveAfterThen && !aliveAfterElse) {
afterIfBindings = thenBindings;
afterIfBindings = condBindings.bindingsWhenTrue;
} else if (aliveAfterElse && !aliveAfterThen) {
afterIfBindings = elseBindings;
afterIfBindings = condBindings.bindingsWhenFalse;
}

afterIfBindings.forEach(env.info.scope::enter);
@@ -3767,6 +3770,7 @@ public void visitUnary(JCUnary tree) {
}
}
result = check(tree, owntype, KindSelector.VAL, resultInfo);
matchBindings = matchBindingsComputer.unary(tree, matchBindings);
}

public void visitBinary(JCBinary tree) {
@@ -3778,26 +3782,29 @@ public void visitBinary(JCBinary tree) {
// x || y
// include x's bindings when false in y

List<BindingSymbol> matchBindings;
MatchBindings lhsBindings = matchBindings;
List<BindingSymbol> propagatedBindings;
switch (tree.getTag()) {
case AND:
matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, true);
propagatedBindings = lhsBindings.bindingsWhenTrue;
break;
case OR:
matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, false);
propagatedBindings = lhsBindings.bindingsWhenFalse;
break;
default:
matchBindings = List.nil();
propagatedBindings = List.nil();
break;
}
Env<AttrContext> rhsEnv = bindingEnv(env, matchBindings);
Env<AttrContext> rhsEnv = bindingEnv(env, propagatedBindings);
Type right;
try {
right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, rhsEnv));
} finally {
rhsEnv.info.scope.leave();
}

matchBindings = matchBindingsComputer.binary(tree, lhsBindings, matchBindings);

// Find operator.
Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag(), left, right);
Type owntype = types.createErrorType(tree.type);
@@ -3918,6 +3925,7 @@ public void visitBindingPattern(JCBindingPattern tree) {
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, env, v, tree.pos());
annotate.flush();
result = tree.type;
matchBindings = new MatchBindings(List.of(tree.symbol), List.nil());
}

public void visitIndexed(JCArrayAccess tree) {
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2020, 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
@@ -3604,7 +3604,10 @@ boolean checkUnique(DiagnosticPosition pos, Symbol sym, Scope s) {
} else if ((sym.flags() & MATCH_BINDING) != 0 &&
(byName.flags() & MATCH_BINDING) != 0 &&
(byName.flags() & MATCH_BINDING_TO_OUTER) == 0) {
//this error will be reported separatelly in MatchBindingsComputer
if (!sym.type.isErroneous()) {
log.error(pos, Errors.MatchBindingExists);
sym.flags_field |= CLASH;
}
return false;
} else {
duplicateError(pos, byName);

0 comments on commit a35d087

Please sign in to comment.