< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java

Print this page
rev 51258 : imported patch switch


   9  * by Oracle in the LICENSE file that accompanied this code.
  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 
  30 import javax.lang.model.element.ElementKind;
  31 import javax.tools.JavaFileObject;
  32 

  33 import com.sun.source.tree.IdentifierTree;
  34 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
  35 import com.sun.source.tree.MemberSelectTree;
  36 import com.sun.source.tree.TreeVisitor;
  37 import com.sun.source.util.SimpleTreeVisitor;
  38 import com.sun.tools.javac.code.*;
  39 import com.sun.tools.javac.code.Lint.LintCategory;
  40 import com.sun.tools.javac.code.Scope.WriteableScope;
  41 import com.sun.tools.javac.code.Source.Feature;
  42 import com.sun.tools.javac.code.Symbol.*;
  43 import com.sun.tools.javac.code.Type.*;
  44 import com.sun.tools.javac.code.TypeMetadata.Annotations;
  45 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
  46 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
  47 import com.sun.tools.javac.comp.Check.CheckContext;
  48 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
  49 import com.sun.tools.javac.jvm.*;
  50 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
  51 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
  52 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArgs;


1378     }
1379 
1380     public void visitLabelled(JCLabeledStatement tree) {
1381         // Check that label is not used in an enclosing statement
1382         Env<AttrContext> env1 = env;
1383         while (env1 != null && !env1.tree.hasTag(CLASSDEF)) {
1384             if (env1.tree.hasTag(LABELLED) &&
1385                 ((JCLabeledStatement) env1.tree).label == tree.label) {
1386                 log.error(tree.pos(),
1387                           Errors.LabelAlreadyInUse(tree.label));
1388                 break;
1389             }
1390             env1 = env1.next;
1391         }
1392 
1393         attribStat(tree.body, env.dup(tree));
1394         result = null;
1395     }
1396 
1397     public void visitSwitch(JCSwitch tree) {
1398         Type seltype = attribExpr(tree.selector, env);




































































1399 
1400         Env<AttrContext> switchEnv =
1401             env.dup(tree, env.info.dup(env.info.scope.dup()));
1402 
1403         try {
1404 
1405             boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
1406             boolean stringSwitch = types.isSameType(seltype, syms.stringType);
1407             if (!enumSwitch && !stringSwitch)
1408                 seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
1409 
1410             // Attribute all cases and
1411             // check that there are no duplicate case labels or default clauses.
1412             Set<Object> labels = new HashSet<>(); // The set of case labels.
1413             boolean hasDefault = false;      // Is there a default label?
1414             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {



1415                 JCCase c = l.head;
1416                 if (c.pat != null) {
1417                     if (enumSwitch) {
1418                         Symbol sym = enumConstant(c.pat, seltype);











1419                         if (sym == null) {
1420                             log.error(c.pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
1421                         } else if (!labels.add(sym)) {
1422                             log.error(c.pos(), Errors.DuplicateCaseLabel);
1423                         }
1424                     } else {
1425                         Type pattype = attribExpr(c.pat, switchEnv, seltype);
1426                         if (!pattype.hasTag(ERROR)) {
1427                             if (pattype.constValue() == null) {
1428                                 log.error(c.pat.pos(),
1429                                           (stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
1430                             } else if (!labels.add(pattype.constValue())) {
1431                                 log.error(c.pos(), Errors.DuplicateCaseLabel);
1432                             }
1433                         }
1434                     }

1435                 } else if (hasDefault) {
1436                     log.error(c.pos(), Errors.DuplicateDefaultLabel);
1437                 } else {
1438                     hasDefault = true;
1439                 }
1440                 Env<AttrContext> caseEnv =
1441                     switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
1442                 try {
1443                     attribStats(c.stats, caseEnv);
1444                 } finally {
1445                     caseEnv.info.scope.leave();
1446                     addVars(c.stats, switchEnv.info.scope);
1447                 }
1448             }
1449 
1450             result = null;
1451         }
1452         finally {
1453             switchEnv.info.scope.leave();
1454         }
1455     }
1456     // where
1457         /** Add any variables defined in stats to the switch scope. */
1458         private static void addVars(List<JCStatement> stats, WriteableScope switchScope) {
1459             for (;stats.nonEmpty(); stats = stats.tail) {
1460                 JCTree stat = stats.head;
1461                 if (stat.hasTag(VARDEF))
1462                     switchScope.enter(((JCVariableDecl) stat).sym);
1463             }
1464         }
1465     // where
1466     /** Return the selected enumeration constant symbol, or null. */
1467     private Symbol enumConstant(JCTree tree, Type enumType) {
1468         if (tree.hasTag(IDENT)) {
1469             JCIdent ident = (JCIdent)tree;
1470             Name name = ident.name;
1471             for (Symbol sym : enumType.tsym.members().getSymbolsByName(name)) {
1472                 if (sym.kind == VAR) {


1592 
1593         tree.polyKind = (!allowPoly ||
1594                 pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly ||
1595                 isBooleanOrNumeric(env, tree)) ?
1596                 PolyKind.STANDALONE : PolyKind.POLY;
1597 
1598         if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
1599             //this means we are returning a poly conditional from void-compatible lambda expression
1600             resultInfo.checkContext.report(tree, diags.fragment(Fragments.ConditionalTargetCantBeVoid));
1601             result = tree.type = types.createErrorType(resultInfo.pt);
1602             return;
1603         }
1604 
1605         ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
1606                 unknownExprInfo :
1607                 resultInfo.dup(conditionalContext(resultInfo.checkContext));
1608 
1609         Type truetype = attribTree(tree.truepart, env, condInfo);
1610         Type falsetype = attribTree(tree.falsepart, env, condInfo);
1611 
1612         Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(tree, truetype, falsetype) : pt();


1613         if (condtype.constValue() != null &&
1614                 truetype.constValue() != null &&
1615                 falsetype.constValue() != null &&
1616                 !owntype.hasTag(NONE)) {
1617             //constant folding
1618             owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
1619         }
1620         result = check(tree, owntype, KindSelector.VAL, resultInfo);
1621     }
1622     //where
1623         private boolean isBooleanOrNumeric(Env<AttrContext> env, JCExpression tree) {
1624             switch (tree.getTag()) {
1625                 case LITERAL: return ((JCLiteral)tree).typetag.isSubRangeOf(DOUBLE) ||
1626                               ((JCLiteral)tree).typetag == BOOLEAN ||
1627                               ((JCLiteral)tree).typetag == BOT;
1628                 case LAMBDA: case REFERENCE: return false;
1629                 case PARENS: return isBooleanOrNumeric(env, ((JCParens)tree).expr);
1630                 case CONDEXPR:
1631                     JCConditional condTree = (JCConditional)tree;
1632                     return isBooleanOrNumeric(env, condTree.truepart) &&


1673                 //this will use enclosing check context to check compatibility of
1674                 //subexpression against target type; if we are in a method check context,
1675                 //depending on whether boxing is allowed, we could have incompatibilities
1676                 @Override
1677                 public void report(DiagnosticPosition pos, JCDiagnostic details) {
1678                     enclosingContext.report(pos, diags.fragment(Fragments.IncompatibleTypeInConditional(details)));
1679                 }
1680             };
1681         }
1682 
1683         /** Compute the type of a conditional expression, after
1684          *  checking that it exists.  See JLS 15.25. Does not take into
1685          *  account the special case where condition and both arms
1686          *  are constants.
1687          *
1688          *  @param pos      The source position to be used for error
1689          *                  diagnostics.
1690          *  @param thentype The type of the expression's then-part.
1691          *  @param elsetype The type of the expression's else-part.
1692          */
1693         Type condType(DiagnosticPosition pos,
1694                                Type thentype, Type elsetype) {






1695             // If same type, that is the result
1696             if (types.isSameType(thentype, elsetype))
1697                 return thentype.baseType();
1698 
1699             Type thenUnboxed = (thentype.isPrimitive())
1700                 ? thentype : types.unboxedType(thentype);
1701             Type elseUnboxed = (elsetype.isPrimitive())
1702                 ? elsetype : types.unboxedType(elsetype);
1703 
1704             // Otherwise, if both arms can be converted to a numeric
1705             // type, return the least numeric type that fits both arms
1706             // (i.e. return larger of the two, or return int if one
1707             // arm is short, the other is char).
1708             if (thenUnboxed.isPrimitive() && elseUnboxed.isPrimitive()) {
1709                 // If one arm has an integer subrange type (i.e., byte,
1710                 // short, or char), and the other is an integer constant
1711                 // that fits into the subrange, return the subrange type.
1712                 if (thenUnboxed.getTag().isStrictSubRangeOf(INT) &&
1713                     elseUnboxed.hasTag(INT) &&
1714                     types.isAssignable(elseUnboxed, thenUnboxed)) {
1715                     return thenUnboxed.baseType();
1716                 }
1717                 if (elseUnboxed.getTag().isStrictSubRangeOf(INT) &&
1718                     thenUnboxed.hasTag(INT) &&
1719                     types.isAssignable(thenUnboxed, elseUnboxed)) {
1720                     return elseUnboxed.baseType();
1721                 }
1722 
1723                 for (TypeTag tag : primitiveTags) {
1724                     Type candidate = syms.typeOfTag[tag.ordinal()];
1725                     if (types.isSubtype(thenUnboxed, candidate) &&
1726                         types.isSubtype(elseUnboxed, candidate)) {
1727                         return candidate;
1728                     }
1729                 }
1730             }
1731 
1732             // Those were all the cases that could result in a primitive
1733             if (thentype.isPrimitive())
1734                 thentype = types.boxedClass(thentype).type;
1735             if (elsetype.isPrimitive())
1736                 elsetype = types.boxedClass(elsetype).type;
1737 
1738             if (types.isSubtype(thentype, elsetype))
1739                 return elsetype.baseType();
1740             if (types.isSubtype(elsetype, thentype))
1741                 return thentype.baseType();
1742 
1743             if (thentype.hasTag(VOID) || elsetype.hasTag(VOID)) {
1744                 log.error(pos,
1745                           Errors.NeitherConditionalSubtype(thentype,
1746                                                            elsetype));
1747                 return thentype.baseType();
1748             }
1749 






1750             // both are known to be reference types.  The result is
1751             // lub(thentype,elsetype). This cannot fail, as it will
1752             // always be possible to infer "Object" if nothing better.
1753             return types.lub(thentype.baseType(), elsetype.baseType());
1754         }
1755 
1756     final static TypeTag[] primitiveTags = new TypeTag[]{
1757         BYTE,
1758         CHAR,
1759         SHORT,
1760         INT,
1761         LONG,
1762         FLOAT,
1763         DOUBLE,
1764         BOOLEAN,
1765     };
1766 
1767     public void visitIf(JCIf tree) {
1768         attribExpr(tree.cond, env, syms.booleanType);
1769         attribStat(tree.thenpart, env);
1770         if (tree.elsepart != null)
1771             attribStat(tree.elsepart, env);
1772         chk.checkEmptyIf(tree);
1773         result = null;
1774     }
1775 
1776     public void visitExec(JCExpressionStatement tree) {
1777         //a fresh environment is required for 292 inference to work properly ---
1778         //see Infer.instantiatePolymorphicSignatureInstance()
1779         Env<AttrContext> localEnv = env.dup(tree);
1780         attribExpr(tree.expr, localEnv);
1781         result = null;
1782     }
1783 
1784     public void visitBreak(JCBreak tree) {
1785         tree.target = findJumpTarget(tree.pos(), tree.getTag(), tree.label, env);





























































1786         result = null;
1787     }
1788 
1789     public void visitContinue(JCContinue tree) {
1790         tree.target = findJumpTarget(tree.pos(), tree.getTag(), tree.label, env);
1791         result = null;
1792     }
1793     //where
1794         /** Return the target of a break or continue statement, if it exists,
1795          *  report an error if not.
1796          *  Note: The target of a labelled break or continue is the
1797          *  (non-labelled) statement tree referred to by the label,
1798          *  not the tree representing the labelled statement itself.
1799          *
1800          *  @param pos     The position to be used for error diagnostics
1801          *  @param tag     The tag of the jump statement. This is either
1802          *                 Tree.BREAK or Tree.CONTINUE.
1803          *  @param label   The label of the jump statement, or null if no
1804          *                 label is given.
1805          *  @param env     The environment current at the jump statement.
1806          */
1807         private JCTree findJumpTarget(DiagnosticPosition pos,
1808                                     JCTree.Tag tag,
1809                                     Name label,
1810                                     Env<AttrContext> env) {























1811             // Search environments outwards from the point of jump.
1812             Env<AttrContext> env1 = env;

1813             LOOP:
1814             while (env1 != null) {
1815                 switch (env1.tree.getTag()) {
1816                     case LABELLED:
1817                         JCLabeledStatement labelled = (JCLabeledStatement)env1.tree;
1818                         if (label == labelled.label) {
1819                             // If jump is a continue, check that target is a loop.
1820                             if (tag == CONTINUE) {
1821                                 if (!labelled.body.hasTag(DOLOOP) &&
1822                                         !labelled.body.hasTag(WHILELOOP) &&
1823                                         !labelled.body.hasTag(FORLOOP) &&
1824                                         !labelled.body.hasTag(FOREACHLOOP))
1825                                     log.error(pos, Errors.NotLoopLabel(label));

1826                                 // Found labelled statement target, now go inwards
1827                                 // to next non-labelled tree.
1828                                 return TreeInfo.referencedStatement(labelled);
1829                             } else {
1830                                 return labelled;
1831                             }
1832                         }
1833                         break;
1834                     case DOLOOP:
1835                     case WHILELOOP:
1836                     case FORLOOP:
1837                     case FOREACHLOOP:
1838                         if (label == null) return env1.tree;
1839                         break;
1840                     case SWITCH:
1841                         if (label == null && tag == BREAK) return env1.tree;











1842                         break;
1843                     case LAMBDA:
1844                     case METHODDEF:
1845                     case CLASSDEF:
1846                         break LOOP;
1847                     default:
1848                 }
1849                 env1 = env1.next;
1850             }
1851             if (label != null)
1852                 log.error(pos, Errors.UndefLabel(label));
1853             else if (tag == CONTINUE)
1854                 log.error(pos, Errors.ContOutsideLoop);
1855             else
1856                 log.error(pos, Errors.BreakOutsideSwitchLoop);
1857             return null;
1858         }
1859 
1860     public void visitReturn(JCReturn tree) {
1861         // Check that there is an enclosing method which is
1862         // nested within than the enclosing class.
1863         if (env.info.returnResult == null) {
1864             log.error(tree.pos(), Errors.RetOutsideMeth);


1865         } else {
1866             // Attribute return expression, if it exists, and check that
1867             // it conforms to result type of enclosing method.
1868             if (tree.expr != null) {
1869                 if (env.info.returnResult.pt.hasTag(VOID)) {
1870                     env.info.returnResult.checkContext.report(tree.expr.pos(),
1871                               diags.fragment(Fragments.UnexpectedRetVal));
1872                 }
1873                 attribTree(tree.expr, env, env.info.returnResult);
1874             } else if (!env.info.returnResult.pt.hasTag(VOID) &&
1875                     !env.info.returnResult.pt.hasTag(NONE)) {
1876                 env.info.returnResult.checkContext.report(tree.pos(),
1877                               diags.fragment(Fragments.MissingRetVal(env.info.returnResult.pt)));
1878             }
1879         }
1880         result = null;
1881     }
1882 
1883     public void visitThrow(JCThrow tree) {
1884         Type owntype = attribExpr(tree.expr, env, allowPoly ? Type.noType : syms.throwableType);


2927                     }
2928                 } else {
2929                     /* if the field is static then we need to create a fake clinit
2930                      * method, this method can later be reused by LTM.
2931                      */
2932                     MethodSymbol clinit = clinits.get(enclClass);
2933                     if (clinit == null) {
2934                         Type clinitType = new MethodType(List.nil(),
2935                                 syms.voidType, List.nil(), syms.methodClass);
2936                         clinit = new MethodSymbol(STATIC | SYNTHETIC | PRIVATE,
2937                                 names.clinit, clinitType, enclClass);
2938                         clinit.params = List.nil();
2939                         clinits.put(enclClass, clinit);
2940                     }
2941                     newScopeOwner = clinit;
2942                 }
2943                 lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dupUnshared(newScopeOwner)));
2944             } else {
2945                 lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
2946             }

2947             return lambdaEnv;
2948         }
2949 
2950     @Override
2951     public void visitReference(final JCMemberReference that) {
2952         if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
2953             if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
2954                 //method reference only allowed in assignment or method invocation/cast context
2955                 log.error(that.pos(), Errors.UnexpectedMref);
2956             }
2957             result = that.type = types.createErrorType(pt());
2958             return;
2959         }
2960         final Env<AttrContext> localEnv = env.dup(that);
2961         try {
2962             //attribute member reference qualifier - if this is a constructor
2963             //reference, the expected kind must be a type
2964             Type exprType = attribTree(that.expr, env, memberReferenceQualifierResult(that));
2965 
2966             if (that.getMode() == JCMemberReference.ReferenceMode.NEW) {




   9  * by Oracle in the LICENSE file that accompanied this code.
  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;
  51 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
  52 import com.sun.tools.javac.jvm.*;
  53 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
  54 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
  55 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArgs;


1381     }
1382 
1383     public void visitLabelled(JCLabeledStatement tree) {
1384         // Check that label is not used in an enclosing statement
1385         Env<AttrContext> env1 = env;
1386         while (env1 != null && !env1.tree.hasTag(CLASSDEF)) {
1387             if (env1.tree.hasTag(LABELLED) &&
1388                 ((JCLabeledStatement) env1.tree).label == tree.label) {
1389                 log.error(tree.pos(),
1390                           Errors.LabelAlreadyInUse(tree.label));
1391                 break;
1392             }
1393             env1 = env1.next;
1394         }
1395 
1396         attribStat(tree.body, env.dup(tree));
1397         result = null;
1398     }
1399 
1400     public void visitSwitch(JCSwitch tree) {
1401         handleSwitch(tree, tree.selector, tree.cases, (c, caseEnv) -> {
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) {
1469         Type seltype = attribExpr(selector, env);
1470 
1471         Env<AttrContext> switchEnv =
1472             env.dup(switchTree, env.info.dup(env.info.scope.dup()));
1473 
1474         try {

1475             boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
1476             boolean stringSwitch = types.isSameType(seltype, syms.stringType);
1477             if (!enumSwitch && !stringSwitch)
1478                 seltype = chk.checkType(selector.pos(), seltype, syms.intType);
1479 
1480             // Attribute all cases and
1481             // check that there are no duplicate case labels or default clauses.
1482             Set<Object> labels = new HashSet<>(); // The set of case labels.
1483             boolean hasDefault = false;      // Is there a default label?
1484             @SuppressWarnings("removal")
1485             CaseKind caseKind = null;
1486             boolean wasError = false;
1487             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
1488                 JCCase c = l.head;
1489                 if (caseKind == null) {
1490                     caseKind = c.caseKind;
1491                 } else if (caseKind != c.caseKind && !wasError) {
1492                     log.error(c.pos(),
1493                               Errors.SwitchMixingCaseTypes);
1494                     wasError = true;
1495                 }
1496                 if (c.getExpressions().nonEmpty()) {
1497                     for (JCExpression pat : c.getExpressions()) {
1498                         if (TreeInfo.isNull(pat)) {
1499                             log.error(pat.pos(),
1500                                       Errors.SwitchNullNotAllowed);
1501                         } else if (enumSwitch) {
1502                             Symbol sym = enumConstant(pat, seltype);
1503                             if (sym == null) {
1504                                 log.error(pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
1505                             } else if (!labels.add(sym)) {
1506                                 log.error(c.pos(), Errors.DuplicateCaseLabel);
1507                             }
1508                         } else {
1509                             Type pattype = attribExpr(pat, switchEnv, seltype);
1510                             if (!pattype.hasTag(ERROR)) {
1511                                 if (pattype.constValue() == null) {
1512                                     log.error(pat.pos(),
1513                                               (stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
1514                                 } else if (!labels.add(pattype.constValue())) {
1515                                     log.error(c.pos(), Errors.DuplicateCaseLabel);
1516                                 }
1517                             }
1518                         }
1519                     }
1520                 } else if (hasDefault) {
1521                     log.error(c.pos(), Errors.DuplicateDefaultLabel);
1522                 } else {
1523                     hasDefault = true;
1524                 }
1525                 Env<AttrContext> caseEnv =
1526                     switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
1527                 try {
1528                     attribCase.accept(c, caseEnv);
1529                 } finally {
1530                     caseEnv.info.scope.leave();
1531                     addVars(c.stats, switchEnv.info.scope);
1532                 }
1533             }
1534         } finally {



1535             switchEnv.info.scope.leave();
1536         }
1537     }
1538     // where
1539         /** Add any variables defined in stats to the switch scope. */
1540         private static void addVars(List<JCStatement> stats, WriteableScope switchScope) {
1541             for (;stats.nonEmpty(); stats = stats.tail) {
1542                 JCTree stat = stats.head;
1543                 if (stat.hasTag(VARDEF))
1544                     switchScope.enter(((JCVariableDecl) stat).sym);
1545             }
1546         }
1547     // where
1548     /** Return the selected enumeration constant symbol, or null. */
1549     private Symbol enumConstant(JCTree tree, Type enumType) {
1550         if (tree.hasTag(IDENT)) {
1551             JCIdent ident = (JCIdent)tree;
1552             Name name = ident.name;
1553             for (Symbol sym : enumType.tsym.members().getSymbolsByName(name)) {
1554                 if (sym.kind == VAR) {


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())) {
1798                 // If one arm has an integer subrange type (i.e., byte,
1799                 // short, or char), and the other is an integer constant
1800                 // that fits into the subrange, return the subrange type.
1801                 for (Type type : unboxedTypes) {
1802                     if (!type.getTag().isStrictSubRangeOf(INT)) {
1803                         continue;
1804                     }
1805                     if (unboxedTypes.stream().filter(t -> t != type).allMatch(t -> t.hasTag(INT) && types.isAssignable(t, type)))
1806                         return type.baseType();



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);
1852         attribStat(tree.thenpart, env);
1853         if (tree.elsepart != null)
1854             attribStat(tree.elsepart, env);
1855         chk.checkEmptyIf(tree);
1856         result = null;
1857     }
1858 
1859     public void visitExec(JCExpressionStatement tree) {
1860         //a fresh environment is required for 292 inference to work properly ---
1861         //see Infer.instantiatePolymorphicSignatureInstance()
1862         Env<AttrContext> localEnv = env.dup(tree);
1863         attribExpr(tree.expr, localEnv);
1864         result = null;
1865     }
1866 
1867     public void visitBreak(JCBreak tree) {
1868         if (env.info.breakResult != null) {
1869             if (tree.value == null) {
1870                 tree.target = findJumpTarget(tree.pos(), tree.getTag(), null, env);
1871                 if (tree.target.hasTag(SWITCH_EXPRESSION)) {
1872                     log.error(tree.pos(), Errors.BreakMissingValue);
1873                 }
1874             } else {
1875                 if (env.info.breakResult.pt.hasTag(VOID)) {
1876                     //can happen?
1877                     env.info.breakResult.checkContext.report(tree.value.pos(),
1878                               diags.fragment(Fragments.UnexpectedRetVal));
1879                 }
1880                 boolean attribute = true;
1881                 if (tree.value.hasTag(IDENT)) {
1882                     //disambiguate break <LABEL> and break <ident-as-an-expression>:
1883                     Name label = ((JCIdent) tree.value).name;
1884                     Pair<JCTree, Error> jumpTarget = findJumpTargetNoError(tree.getTag(), label, env);
1885 
1886                     if (jumpTarget.fst != null) {
1887                         JCTree speculative = deferredAttr.attribSpeculative(tree.value, env, unknownExprInfo);
1888                         if (!speculative.type.hasTag(ERROR)) {
1889                             log.error(tree.pos(), Errors.BreakAmbiguousTarget(label));
1890                             if (jumpTarget.snd == null) {
1891                                 tree.target = jumpTarget.fst;
1892                                 attribute = false;
1893                             } else {
1894                                 //nothing
1895                             }
1896                         } else {
1897                             if (jumpTarget.snd != null) {
1898                                 log.error(tree.pos(), jumpTarget.snd);
1899                             }
1900                             tree.target = jumpTarget.fst;
1901                             attribute = false;
1902                         }
1903                     }
1904                 }
1905                 if (attribute) {
1906                     attribTree(tree.value, env, env.info.breakResult);
1907                     JCTree immediateTarget = findJumpTarget(tree.pos(), tree.getTag(), null, env);
1908                     if (immediateTarget.getTag() != SWITCH_EXPRESSION) {
1909                         log.error(tree.pos(), Errors.BreakExprNotImmediate);
1910                         Env<AttrContext> env1 = env;
1911                         while (env1 != null && env1.tree.getTag() != SWITCH_EXPRESSION) {
1912                             env1 = env1.next;
1913                         }
1914                         Assert.checkNonNull(env1);
1915                         tree.target = env1.tree;
1916                     } else {
1917                         tree.target = immediateTarget;
1918                     }
1919                 }
1920             }
1921         } else {
1922             if (tree.value == null || tree.value.hasTag(IDENT)) {
1923                 Name label = tree.value != null ? ((JCIdent) tree.value).name : null;
1924                 tree.target = findJumpTarget(tree.pos(), tree.getTag(), label, env);
1925             } else {
1926                 log.error(tree.pos(), Errors.BreakComplexValueNoSwitchExpression);
1927                 attribTree(tree.value, env, unknownExprInfo);
1928             }
1929         }
1930         result = null;
1931     }
1932 
1933     public void visitContinue(JCContinue tree) {
1934         tree.target = findJumpTarget(tree.pos(), tree.getTag(), tree.label, env);
1935         result = null;
1936     }
1937     //where
1938         /** Return the target of a break or continue statement, if it exists,
1939          *  report an error if not.
1940          *  Note: The target of a labelled break or continue is the
1941          *  (non-labelled) statement tree referred to by the label,
1942          *  not the tree representing the labelled statement itself.
1943          *
1944          *  @param pos     The position to be used for error diagnostics
1945          *  @param tag     The tag of the jump statement. This is either
1946          *                 Tree.BREAK or Tree.CONTINUE.
1947          *  @param label   The label of the jump statement, or null if no
1948          *                 label is given.
1949          *  @param env     The environment current at the jump statement.
1950          */
1951         private JCTree findJumpTarget(DiagnosticPosition pos,
1952                                                    JCTree.Tag tag,
1953                                                    Name label,
1954                                                    Env<AttrContext> env) {
1955             Pair<JCTree, Error> jumpTarget = findJumpTargetNoError(tag, label, env);
1956 
1957             if (jumpTarget.snd != null) {
1958                 log.error(pos, jumpTarget.snd);
1959             }
1960 
1961             return jumpTarget.fst;
1962         }
1963         /** Return the target of a break or continue statement, if it exists,
1964          *  report an error if not.
1965          *  Note: The target of a labelled break or continue is the
1966          *  (non-labelled) statement tree referred to by the label,
1967          *  not the tree representing the labelled statement itself.
1968          *
1969          *  @param tag     The tag of the jump statement. This is either
1970          *                 Tree.BREAK or Tree.CONTINUE.
1971          *  @param label   The label of the jump statement, or null if no
1972          *                 label is given.
1973          *  @param env     The environment current at the jump statement.
1974          */
1975         private Pair<JCTree, JCDiagnostic.Error> findJumpTargetNoError(JCTree.Tag tag,
1976                                                                        Name label,
1977                                                                        Env<AttrContext> env) {
1978             // Search environments outwards from the point of jump.
1979             Env<AttrContext> env1 = env;
1980             JCDiagnostic.Error pendingError = null;
1981             LOOP:
1982             while (env1 != null) {
1983                 switch (env1.tree.getTag()) {
1984                     case LABELLED:
1985                         JCLabeledStatement labelled = (JCLabeledStatement)env1.tree;
1986                         if (label == labelled.label) {
1987                             // If jump is a continue, check that target is a loop.
1988                             if (tag == CONTINUE) {
1989                                 if (!labelled.body.hasTag(DOLOOP) &&
1990                                         !labelled.body.hasTag(WHILELOOP) &&
1991                                         !labelled.body.hasTag(FORLOOP) &&
1992                                         !labelled.body.hasTag(FOREACHLOOP)) {
1993                                     pendingError = Errors.NotLoopLabel(label);
1994                                 }
1995                                 // Found labelled statement target, now go inwards
1996                                 // to next non-labelled tree.
1997                                 return Pair.of(TreeInfo.referencedStatement(labelled), pendingError);
1998                             } else {
1999                                 return Pair.of(labelled, pendingError);
2000                             }
2001                         }
2002                         break;
2003                     case DOLOOP:
2004                     case WHILELOOP:
2005                     case FORLOOP:
2006                     case FOREACHLOOP:
2007                         if (label == null) return Pair.of(env1.tree, pendingError);
2008                         break;
2009                     case SWITCH:
2010                         if (label == null && tag == BREAK) return Pair.of(env1.tree, null);
2011                         break;
2012                     case SWITCH_EXPRESSION:
2013                         if (tag == BREAK) {
2014                             if (label == null) {
2015                                 return Pair.of(env1.tree, null);
2016                             } else {
2017                                 pendingError = Errors.BreakOutsideSwitchExpression;
2018                             }
2019                         } else {
2020                             pendingError = Errors.ContinueOutsideSwitchExpression;
2021                         }
2022                         break;
2023                     case LAMBDA:
2024                     case METHODDEF:
2025                     case CLASSDEF:
2026                         break LOOP;
2027                     default:
2028                 }
2029                 env1 = env1.next;
2030             }
2031             if (label != null)
2032                 return Pair.of(null, Errors.UndefLabel(label));
2033             else if (tag == CONTINUE)
2034                 return Pair.of(null, Errors.ContOutsideLoop);
2035             else
2036                 return Pair.of(null, Errors.BreakOutsideSwitchLoop);

2037         }
2038 
2039     public void visitReturn(JCReturn tree) {
2040         // Check that there is an enclosing method which is
2041         // nested within than the enclosing class.
2042         if (env.info.returnResult == null) {
2043             log.error(tree.pos(), Errors.RetOutsideMeth);
2044         } else if (env.info.breakResult != null) {
2045             log.error(tree.pos(), Errors.ReturnOutsideSwitchExpression);
2046         } else {
2047             // Attribute return expression, if it exists, and check that
2048             // it conforms to result type of enclosing method.
2049             if (tree.expr != null) {
2050                 if (env.info.returnResult.pt.hasTag(VOID)) {
2051                     env.info.returnResult.checkContext.report(tree.expr.pos(),
2052                               diags.fragment(Fragments.UnexpectedRetVal));
2053                 }
2054                 attribTree(tree.expr, env, env.info.returnResult);
2055             } else if (!env.info.returnResult.pt.hasTag(VOID) &&
2056                     !env.info.returnResult.pt.hasTag(NONE)) {
2057                 env.info.returnResult.checkContext.report(tree.pos(),
2058                               diags.fragment(Fragments.MissingRetVal(env.info.returnResult.pt)));
2059             }
2060         }
2061         result = null;
2062     }
2063 
2064     public void visitThrow(JCThrow tree) {
2065         Type owntype = attribExpr(tree.expr, env, allowPoly ? Type.noType : syms.throwableType);


3108                     }
3109                 } else {
3110                     /* if the field is static then we need to create a fake clinit
3111                      * method, this method can later be reused by LTM.
3112                      */
3113                     MethodSymbol clinit = clinits.get(enclClass);
3114                     if (clinit == null) {
3115                         Type clinitType = new MethodType(List.nil(),
3116                                 syms.voidType, List.nil(), syms.methodClass);
3117                         clinit = new MethodSymbol(STATIC | SYNTHETIC | PRIVATE,
3118                                 names.clinit, clinitType, enclClass);
3119                         clinit.params = List.nil();
3120                         clinits.put(enclClass, clinit);
3121                     }
3122                     newScopeOwner = clinit;
3123                 }
3124                 lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dupUnshared(newScopeOwner)));
3125             } else {
3126                 lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
3127             }
3128             lambdaEnv.info.breakResult = null;
3129             return lambdaEnv;
3130         }
3131 
3132     @Override
3133     public void visitReference(final JCMemberReference that) {
3134         if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
3135             if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
3136                 //method reference only allowed in assignment or method invocation/cast context
3137                 log.error(that.pos(), Errors.UnexpectedMref);
3138             }
3139             result = that.type = types.createErrorType(pt());
3140             return;
3141         }
3142         final Env<AttrContext> localEnv = env.dup(that);
3143         try {
3144             //attribute member reference qualifier - if this is a constructor
3145             //reference, the expected kind must be a type
3146             Type exprType = attribTree(that.expr, env, memberReferenceQualifierResult(that));
3147 
3148             if (that.getMode() == JCMemberReference.ReferenceMode.NEW) {


< prev index next >