10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.javac.comp;
27
28 import java.util.*;
29 import java.util.function.BiConsumer;
30
31 import javax.lang.model.element.ElementKind;
32 import javax.tools.JavaFileObject;
33
34 import com.sun.source.tree.CaseTree.CaseKind;
35 import com.sun.source.tree.IdentifierTree;
36 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
37 import com.sun.source.tree.MemberSelectTree;
38 import com.sun.source.tree.TreeVisitor;
39 import com.sun.source.util.SimpleTreeVisitor;
40 import com.sun.tools.javac.code.*;
41 import com.sun.tools.javac.code.Lint.LintCategory;
42 import com.sun.tools.javac.code.Scope.WriteableScope;
43 import com.sun.tools.javac.code.Source.Feature;
44 import com.sun.tools.javac.code.Symbol.*;
45 import com.sun.tools.javac.code.Type.*;
46 import com.sun.tools.javac.code.TypeMetadata.Annotations;
47 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
48 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
49 import com.sun.tools.javac.comp.Check.CheckContext;
690 }
691
692 WriteableScope copyScope(WriteableScope sc) {
693 WriteableScope newScope = WriteableScope.create(sc.owner);
694 List<Symbol> elemsList = List.nil();
695 for (Symbol sym : sc.getSymbols()) {
696 elemsList = elemsList.prepend(sym);
697 }
698 for (Symbol s : elemsList) {
699 newScope.enter(s);
700 }
701 return newScope;
702 }
703
704 /** Derived visitor method: attribute an expression tree.
705 */
706 public Type attribExpr(JCTree tree, Env<AttrContext> env, Type pt) {
707 return attribTree(tree, env, new ResultInfo(KindSelector.VAL, !pt.hasTag(ERROR) ? pt : Type.noType));
708 }
709
710 /** Derived visitor method: attribute an expression tree.
711 */
712 public Type attribExpr(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
713 return attribTree(tree, env, resultInfo);
714 }
715
716 /** Derived visitor method: attribute an expression tree with
717 * no constraints on the computed type.
718 */
719 public Type attribExpr(JCTree tree, Env<AttrContext> env) {
720 return attribTree(tree, env, unknownExprInfo);
721 }
722
723 /** Derived visitor method: attribute a type tree.
724 */
725 public Type attribType(JCTree tree, Env<AttrContext> env) {
726 Type result = attribType(tree, env, Type.noType);
727 return result;
728 }
729
730 /** Derived visitor method: attribute a type tree.
731 */
732 Type attribType(JCTree tree, Env<AttrContext> env, Type pt) {
733 Type result = attribTree(tree, env, new ResultInfo(KindSelector.TYP, pt));
734 return result;
735 }
1407 attribStats(c.stats, caseEnv);
1408 });
1409 result = null;
1410 }
1411
1412 public void visitSwitchExpression(JCSwitchExpression tree) {
1413 tree.polyKind = (pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly) ?
1414 PolyKind.STANDALONE : PolyKind.POLY;
1415
1416 if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
1417 //this means we are returning a poly conditional from void-compatible lambda expression
1418 resultInfo.checkContext.report(tree, diags.fragment(Fragments.SwitchExpressionTargetCantBeVoid));
1419 result = tree.type = types.createErrorType(resultInfo.pt);
1420 return;
1421 }
1422
1423 ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
1424 unknownExprInfo :
1425 resultInfo.dup(switchExpressionContext(resultInfo.checkContext));
1426
1427 ListBuffer<Type> caseTypes = new ListBuffer<>();
1428
1429 handleSwitch(tree, tree.selector, tree.cases, (c, caseEnv) -> {
1430 caseEnv.info.breakResult = condInfo;
1431 attribStats(c.stats, caseEnv);
1432 new TreeScanner() {
1433 @Override
1434 public void visitBreak(JCBreak brk) {
1435 if (brk.target == tree)
1436 caseTypes.append(brk.value != null ? brk.value.type : syms.errType);
1437 super.visitBreak(brk);
1438 }
1439
1440 @Override public void visitClassDef(JCClassDecl tree) {}
1441 @Override public void visitLambda(JCLambda tree) {}
1442 @Override public void visitMethodDef(JCMethodDecl tree) {}
1443 }.scan(c.stats);
1444 });
1445
1446 Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(tree, caseTypes.toList()) : pt();
1447
1448 result = tree.type = check(tree, owntype, KindSelector.VAL, resultInfo);
1449 }
1450 //where:
1451 CheckContext switchExpressionContext(CheckContext checkContext) {
1452 return new Check.NestedCheckContext(checkContext) {
1453 //this will use enclosing check context to check compatibility of
1454 //subexpression against target type; if we are in a method check context,
1455 //depending on whether boxing is allowed, we could have incompatibilities
1456 @Override
1457 public void report(DiagnosticPosition pos, JCDiagnostic details) {
1458 enclosingContext.report(pos, diags.fragment(Fragments.IncompatibleTypeInSwitchExpression(details)));
1459 }
1460 };
1461 }
1462
1463 private void handleSwitch(JCTree switchTree,
1464 JCExpression selector,
1465 List<JCCase> cases,
1466 BiConsumer<JCCase, Env<AttrContext>> attribCase) {
1672
1673 tree.polyKind = (!allowPoly ||
1674 pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly ||
1675 isBooleanOrNumeric(env, tree)) ?
1676 PolyKind.STANDALONE : PolyKind.POLY;
1677
1678 if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
1679 //this means we are returning a poly conditional from void-compatible lambda expression
1680 resultInfo.checkContext.report(tree, diags.fragment(Fragments.ConditionalTargetCantBeVoid));
1681 result = tree.type = types.createErrorType(resultInfo.pt);
1682 return;
1683 }
1684
1685 ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
1686 unknownExprInfo :
1687 resultInfo.dup(conditionalContext(resultInfo.checkContext));
1688
1689 Type truetype = attribTree(tree.truepart, env, condInfo);
1690 Type falsetype = attribTree(tree.falsepart, env, condInfo);
1691
1692 Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(tree, List.of(truetype, falsetype)) : pt();
1693 if (condtype.constValue() != null &&
1694 truetype.constValue() != null &&
1695 falsetype.constValue() != null &&
1696 !owntype.hasTag(NONE)) {
1697 //constant folding
1698 owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
1699 }
1700 result = check(tree, owntype, KindSelector.VAL, resultInfo);
1701 }
1702 //where
1703 private boolean isBooleanOrNumeric(Env<AttrContext> env, JCExpression tree) {
1704 switch (tree.getTag()) {
1705 case LITERAL: return ((JCLiteral)tree).typetag.isSubRangeOf(DOUBLE) ||
1706 ((JCLiteral)tree).typetag == BOOLEAN ||
1707 ((JCLiteral)tree).typetag == BOT;
1708 case LAMBDA: case REFERENCE: return false;
1709 case PARENS: return isBooleanOrNumeric(env, ((JCParens)tree).expr);
1710 case CONDEXPR:
1711 JCConditional condTree = (JCConditional)tree;
1712 return isBooleanOrNumeric(env, condTree.truepart) &&
1753 //this will use enclosing check context to check compatibility of
1754 //subexpression against target type; if we are in a method check context,
1755 //depending on whether boxing is allowed, we could have incompatibilities
1756 @Override
1757 public void report(DiagnosticPosition pos, JCDiagnostic details) {
1758 enclosingContext.report(pos, diags.fragment(Fragments.IncompatibleTypeInConditional(details)));
1759 }
1760 };
1761 }
1762
1763 /** Compute the type of a conditional expression, after
1764 * checking that it exists. See JLS 15.25. Does not take into
1765 * account the special case where condition and both arms
1766 * are constants.
1767 *
1768 * @param pos The source position to be used for error
1769 * diagnostics.
1770 * @param thentype The type of the expression's then-part.
1771 * @param elsetype The type of the expression's else-part.
1772 */
1773 Type condType(DiagnosticPosition pos,
1774 List<Type> condTypes) {
1775 if (condTypes.isEmpty()) {
1776 return syms.objectType; //TODO: how to handle?
1777 }
1778 if (condTypes.size() == 1) {
1779 return condTypes.head;
1780 }
1781 Type first = condTypes.head;
1782 // If same type, that is the result
1783 if (condTypes.tail.stream().allMatch(t -> types.isSameType(first, t)))
1784 return first.baseType();
1785
1786 List<Type> unboxedTypes = condTypes.stream()
1787 .map(t -> t.isPrimitive() ? t : types.unboxedType(t))
1788 .collect(List.collector());
1789
1790 // Otherwise, if both arms can be converted to a numeric
1791 // type, return the least numeric type that fits both arms
1792 // (i.e. return larger of the two, or return int if one
1793 // arm is short, the other is char).
1794 if (unboxedTypes.stream().allMatch(t -> t.isPrimitive())) {
1804 }
1805
1806 for (TypeTag tag : primitiveTags) {
1807 Type candidate = syms.typeOfTag[tag.ordinal()];
1808 if (unboxedTypes.stream().allMatch(t -> types.isSubtype(t, candidate))) {
1809 return candidate;
1810 }
1811 }
1812 }
1813
1814 // Those were all the cases that could result in a primitive
1815 condTypes = condTypes.stream()
1816 .map(t -> t.isPrimitive() ? types.boxedClass(t).type : t)
1817 .collect(List.collector());
1818
1819 for (Type type : condTypes) {
1820 if (condTypes.stream().filter(t -> t != type).allMatch(t -> types.isAssignable(t, type)))
1821 return type.baseType();
1822 }
1823
1824 if (condTypes.stream().anyMatch(t -> t.hasTag(VOID))) {
1825 //XXX:
1826 log.error(pos,
1827 Errors.NeitherConditionalSubtype(condTypes.head,
1828 condTypes.tail.head));
1829 return condTypes.head.baseType();
1830 }
1831
1832 // both are known to be reference types. The result is
1833 // lub(thentype,elsetype). This cannot fail, as it will
1834 // always be possible to infer "Object" if nothing better.
1835 return types.lub(condTypes.stream().map(t -> t.baseType()).collect(List.collector()));
1836 }
1837
1838 final static TypeTag[] primitiveTags = new TypeTag[]{
1839 BYTE,
1840 CHAR,
1841 SHORT,
1842 INT,
1843 LONG,
1844 FLOAT,
1845 DOUBLE,
1846 BOOLEAN,
1847 };
1848
1849 public void visitIf(JCIf tree) {
1850 attribExpr(tree.cond, env, syms.booleanType);
|
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.javac.comp;
27
28 import java.util.*;
29 import java.util.function.BiConsumer;
30 import java.util.stream.Collectors;
31
32 import javax.lang.model.element.ElementKind;
33 import javax.tools.JavaFileObject;
34
35 import com.sun.source.tree.CaseTree.CaseKind;
36 import com.sun.source.tree.IdentifierTree;
37 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
38 import com.sun.source.tree.MemberSelectTree;
39 import com.sun.source.tree.TreeVisitor;
40 import com.sun.source.util.SimpleTreeVisitor;
41 import com.sun.tools.javac.code.*;
42 import com.sun.tools.javac.code.Lint.LintCategory;
43 import com.sun.tools.javac.code.Scope.WriteableScope;
44 import com.sun.tools.javac.code.Source.Feature;
45 import com.sun.tools.javac.code.Symbol.*;
46 import com.sun.tools.javac.code.Type.*;
47 import com.sun.tools.javac.code.TypeMetadata.Annotations;
48 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
49 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
50 import com.sun.tools.javac.comp.Check.CheckContext;
691 }
692
693 WriteableScope copyScope(WriteableScope sc) {
694 WriteableScope newScope = WriteableScope.create(sc.owner);
695 List<Symbol> elemsList = List.nil();
696 for (Symbol sym : sc.getSymbols()) {
697 elemsList = elemsList.prepend(sym);
698 }
699 for (Symbol s : elemsList) {
700 newScope.enter(s);
701 }
702 return newScope;
703 }
704
705 /** Derived visitor method: attribute an expression tree.
706 */
707 public Type attribExpr(JCTree tree, Env<AttrContext> env, Type pt) {
708 return attribTree(tree, env, new ResultInfo(KindSelector.VAL, !pt.hasTag(ERROR) ? pt : Type.noType));
709 }
710
711 /** Derived visitor method: attribute an expression tree with
712 * no constraints on the computed type.
713 */
714 public Type attribExpr(JCTree tree, Env<AttrContext> env) {
715 return attribTree(tree, env, unknownExprInfo);
716 }
717
718 /** Derived visitor method: attribute a type tree.
719 */
720 public Type attribType(JCTree tree, Env<AttrContext> env) {
721 Type result = attribType(tree, env, Type.noType);
722 return result;
723 }
724
725 /** Derived visitor method: attribute a type tree.
726 */
727 Type attribType(JCTree tree, Env<AttrContext> env, Type pt) {
728 Type result = attribTree(tree, env, new ResultInfo(KindSelector.TYP, pt));
729 return result;
730 }
1402 attribStats(c.stats, caseEnv);
1403 });
1404 result = null;
1405 }
1406
1407 public void visitSwitchExpression(JCSwitchExpression tree) {
1408 tree.polyKind = (pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly) ?
1409 PolyKind.STANDALONE : PolyKind.POLY;
1410
1411 if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
1412 //this means we are returning a poly conditional from void-compatible lambda expression
1413 resultInfo.checkContext.report(tree, diags.fragment(Fragments.SwitchExpressionTargetCantBeVoid));
1414 result = tree.type = types.createErrorType(resultInfo.pt);
1415 return;
1416 }
1417
1418 ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
1419 unknownExprInfo :
1420 resultInfo.dup(switchExpressionContext(resultInfo.checkContext));
1421
1422 ListBuffer<DiagnosticPosition> caseTypePositions = new ListBuffer<>();
1423 ListBuffer<Type> caseTypes = new ListBuffer<>();
1424
1425 handleSwitch(tree, tree.selector, tree.cases, (c, caseEnv) -> {
1426 caseEnv.info.breakResult = condInfo;
1427 attribStats(c.stats, caseEnv);
1428 new TreeScanner() {
1429 @Override
1430 public void visitBreak(JCBreak brk) {
1431 if (brk.target == tree) {
1432 caseTypePositions.append(brk.value != null ? brk.value.pos() : brk.pos());
1433 caseTypes.append(brk.value != null ? brk.value.type : syms.errType);
1434 }
1435 super.visitBreak(brk);
1436 }
1437
1438 @Override public void visitClassDef(JCClassDecl tree) {}
1439 @Override public void visitLambda(JCLambda tree) {}
1440 }.scan(c.stats);
1441 });
1442
1443 if (tree.cases.isEmpty()) {
1444 log.error(tree.pos(),
1445 Errors.SwitchExpressionEmpty);
1446 }
1447
1448 Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(caseTypePositions.toList(), caseTypes.toList()) : pt();
1449
1450 result = tree.type = check(tree, owntype, KindSelector.VAL, resultInfo);
1451 }
1452 //where:
1453 CheckContext switchExpressionContext(CheckContext checkContext) {
1454 return new Check.NestedCheckContext(checkContext) {
1455 //this will use enclosing check context to check compatibility of
1456 //subexpression against target type; if we are in a method check context,
1457 //depending on whether boxing is allowed, we could have incompatibilities
1458 @Override
1459 public void report(DiagnosticPosition pos, JCDiagnostic details) {
1460 enclosingContext.report(pos, diags.fragment(Fragments.IncompatibleTypeInSwitchExpression(details)));
1461 }
1462 };
1463 }
1464
1465 private void handleSwitch(JCTree switchTree,
1466 JCExpression selector,
1467 List<JCCase> cases,
1468 BiConsumer<JCCase, Env<AttrContext>> attribCase) {
1674
1675 tree.polyKind = (!allowPoly ||
1676 pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly ||
1677 isBooleanOrNumeric(env, tree)) ?
1678 PolyKind.STANDALONE : PolyKind.POLY;
1679
1680 if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
1681 //this means we are returning a poly conditional from void-compatible lambda expression
1682 resultInfo.checkContext.report(tree, diags.fragment(Fragments.ConditionalTargetCantBeVoid));
1683 result = tree.type = types.createErrorType(resultInfo.pt);
1684 return;
1685 }
1686
1687 ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
1688 unknownExprInfo :
1689 resultInfo.dup(conditionalContext(resultInfo.checkContext));
1690
1691 Type truetype = attribTree(tree.truepart, env, condInfo);
1692 Type falsetype = attribTree(tree.falsepart, env, condInfo);
1693
1694 Type owntype = (tree.polyKind == PolyKind.STANDALONE) ?
1695 condType(List.of(tree.truepart.pos(), tree.falsepart.pos()),
1696 List.of(truetype, falsetype)) : pt();
1697 if (condtype.constValue() != null &&
1698 truetype.constValue() != null &&
1699 falsetype.constValue() != null &&
1700 !owntype.hasTag(NONE)) {
1701 //constant folding
1702 owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
1703 }
1704 result = check(tree, owntype, KindSelector.VAL, resultInfo);
1705 }
1706 //where
1707 private boolean isBooleanOrNumeric(Env<AttrContext> env, JCExpression tree) {
1708 switch (tree.getTag()) {
1709 case LITERAL: return ((JCLiteral)tree).typetag.isSubRangeOf(DOUBLE) ||
1710 ((JCLiteral)tree).typetag == BOOLEAN ||
1711 ((JCLiteral)tree).typetag == BOT;
1712 case LAMBDA: case REFERENCE: return false;
1713 case PARENS: return isBooleanOrNumeric(env, ((JCParens)tree).expr);
1714 case CONDEXPR:
1715 JCConditional condTree = (JCConditional)tree;
1716 return isBooleanOrNumeric(env, condTree.truepart) &&
1757 //this will use enclosing check context to check compatibility of
1758 //subexpression against target type; if we are in a method check context,
1759 //depending on whether boxing is allowed, we could have incompatibilities
1760 @Override
1761 public void report(DiagnosticPosition pos, JCDiagnostic details) {
1762 enclosingContext.report(pos, diags.fragment(Fragments.IncompatibleTypeInConditional(details)));
1763 }
1764 };
1765 }
1766
1767 /** Compute the type of a conditional expression, after
1768 * checking that it exists. See JLS 15.25. Does not take into
1769 * account the special case where condition and both arms
1770 * are constants.
1771 *
1772 * @param pos The source position to be used for error
1773 * diagnostics.
1774 * @param thentype The type of the expression's then-part.
1775 * @param elsetype The type of the expression's else-part.
1776 */
1777 Type condType(List<DiagnosticPosition> positions, List<Type> condTypes) {
1778 if (condTypes.isEmpty()) {
1779 return syms.objectType; //TODO: how to handle?
1780 }
1781 if (condTypes.size() == 1) {
1782 return condTypes.head;
1783 }
1784 Type first = condTypes.head;
1785 // If same type, that is the result
1786 if (condTypes.tail.stream().allMatch(t -> types.isSameType(first, t)))
1787 return first.baseType();
1788
1789 List<Type> unboxedTypes = condTypes.stream()
1790 .map(t -> t.isPrimitive() ? t : types.unboxedType(t))
1791 .collect(List.collector());
1792
1793 // Otherwise, if both arms can be converted to a numeric
1794 // type, return the least numeric type that fits both arms
1795 // (i.e. return larger of the two, or return int if one
1796 // arm is short, the other is char).
1797 if (unboxedTypes.stream().allMatch(t -> t.isPrimitive())) {
1807 }
1808
1809 for (TypeTag tag : primitiveTags) {
1810 Type candidate = syms.typeOfTag[tag.ordinal()];
1811 if (unboxedTypes.stream().allMatch(t -> types.isSubtype(t, candidate))) {
1812 return candidate;
1813 }
1814 }
1815 }
1816
1817 // Those were all the cases that could result in a primitive
1818 condTypes = condTypes.stream()
1819 .map(t -> t.isPrimitive() ? types.boxedClass(t).type : t)
1820 .collect(List.collector());
1821
1822 for (Type type : condTypes) {
1823 if (condTypes.stream().filter(t -> t != type).allMatch(t -> types.isAssignable(t, type)))
1824 return type.baseType();
1825 }
1826
1827 Iterator<DiagnosticPosition> posIt = positions.iterator();
1828
1829 condTypes = condTypes.stream()
1830 .map(t -> chk.checkNonVoid(posIt.next(), t))
1831 .collect(List.collector());
1832
1833 // both are known to be reference types. The result is
1834 // lub(thentype,elsetype). This cannot fail, as it will
1835 // always be possible to infer "Object" if nothing better.
1836 return types.lub(condTypes.stream().map(t -> t.baseType()).collect(List.collector()));
1837 }
1838
1839 final static TypeTag[] primitiveTags = new TypeTag[]{
1840 BYTE,
1841 CHAR,
1842 SHORT,
1843 INT,
1844 LONG,
1845 FLOAT,
1846 DOUBLE,
1847 BOOLEAN,
1848 };
1849
1850 public void visitIf(JCIf tree) {
1851 attribExpr(tree.cond, env, syms.booleanType);
|