1.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 30 15:14:36 2012 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 30 15:14:48 2012 +0000 1.3 @@ -124,6 +124,9 @@ 1.4 this.allowLambda = source.allowLambda(); 1.5 this.allowMethodReferences = source.allowMethodReferences(); 1.6 this.allowDefaultMethods = source.allowDefaultMethods(); 1.7 + this.allowIntersectionTypesInCast = 1.8 + source.allowIntersectionTypesInCast() && 1.9 + fac.options.isSet("allowIntersectionTypes"); 1.10 this.keepDocComments = keepDocComments; 1.11 docComments = newDocCommentTable(keepDocComments, fac); 1.12 this.keepLineMap = keepLineMap; 1.13 @@ -197,6 +200,10 @@ 1.14 */ 1.15 boolean allowDefaultMethods; 1.16 1.17 + /** Switch: should we allow intersection types in cast? 1.18 + */ 1.19 + boolean allowIntersectionTypesInCast; 1.20 + 1.21 /** Switch: should we keep docComments? 1.22 */ 1.23 boolean keepDocComments; 1.24 @@ -239,22 +246,38 @@ 1.25 } 1.26 1.27 protected boolean peekToken(TokenKind tk) { 1.28 - return S.token(1).kind == tk; 1.29 + return peekToken(0, tk); 1.30 + } 1.31 + 1.32 + protected boolean peekToken(int lookahead, TokenKind tk) { 1.33 + return S.token(lookahead + 1).kind == tk; 1.34 } 1.35 1.36 protected boolean peekToken(TokenKind tk1, TokenKind tk2) { 1.37 - return S.token(1).kind == tk1 && 1.38 - S.token(2).kind == tk2; 1.39 + return peekToken(0, tk1, tk2); 1.40 + } 1.41 + 1.42 + protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2) { 1.43 + return S.token(lookahead + 1).kind == tk1 && 1.44 + S.token(lookahead + 2).kind == tk2; 1.45 } 1.46 1.47 protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) { 1.48 - return S.token(1).kind == tk1 && 1.49 - S.token(2).kind == tk2 && 1.50 - S.token(3).kind == tk3; 1.51 + return peekToken(0, tk1, tk2, tk3); 1.52 + } 1.53 + 1.54 + protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2, TokenKind tk3) { 1.55 + return S.token(lookahead + 1).kind == tk1 && 1.56 + S.token(lookahead + 2).kind == tk2 && 1.57 + S.token(lookahead + 3).kind == tk3; 1.58 } 1.59 1.60 protected boolean peekToken(TokenKind... kinds) { 1.61 - for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) { 1.62 + return peekToken(0, kinds); 1.63 + } 1.64 + 1.65 + protected boolean peekToken(int lookahead, TokenKind... kinds) { 1.66 + for (; lookahead < kinds.length ; lookahead++) { 1.67 if (S.token(lookahead + 1).kind != kinds[lookahead]) { 1.68 return false; 1.69 } 1.70 @@ -966,102 +989,40 @@ 1.71 break; 1.72 case LPAREN: 1.73 if (typeArgs == null && (mode & EXPR) != 0) { 1.74 - if (peekToken(MONKEYS_AT) || 1.75 - peekToken(FINAL) || 1.76 - peekToken(RPAREN) || 1.77 - peekToken(IDENTIFIER, COMMA) || 1.78 - peekToken(IDENTIFIER, RPAREN, ARROW)) { 1.79 - //implicit n-ary lambda 1.80 - t = lambdaExpressionOrStatement(true, peekToken(MONKEYS_AT) || peekToken(FINAL), pos); 1.81 - break; 1.82 - } else { 1.83 - nextToken(); 1.84 - mode = EXPR | TYPE | NOPARAMS; 1.85 - t = term3(); 1.86 - if ((mode & TYPE) != 0 && token.kind == LT) { 1.87 - // Could be a cast to a parameterized type 1.88 - JCTree.Tag op = JCTree.Tag.LT; 1.89 - int pos1 = token.pos; 1.90 - nextToken(); 1.91 - mode &= (EXPR | TYPE); 1.92 - mode |= TYPEARG; 1.93 - JCExpression t1 = term3(); 1.94 - if ((mode & TYPE) != 0 && 1.95 - (token.kind == COMMA || token.kind == GT)) { 1.96 - mode = TYPE; 1.97 - ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); 1.98 - args.append(t1); 1.99 - while (token.kind == COMMA) { 1.100 - nextToken(); 1.101 - args.append(typeArgument()); 1.102 - } 1.103 - accept(GT); 1.104 - t = toP(F.at(pos1).TypeApply(t, args.toList())); 1.105 - checkGenerics(); 1.106 - mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type 1.107 - t = term3Rest(t, typeArgs); 1.108 - if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) { 1.109 - //explicit lambda (w/ generic type) 1.110 - mode = EXPR; 1.111 - JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER); 1.112 - if (token.kind == ELLIPSIS) { 1.113 - mods.flags = Flags.VARARGS; 1.114 - t = to(F.at(token.pos).TypeArray(t)); 1.115 - nextToken(); 1.116 - } 1.117 - t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos); 1.118 - break; 1.119 - } 1.120 - } else if ((mode & EXPR) != 0) { 1.121 - mode = EXPR; 1.122 - JCExpression e = term2Rest(t1, TreeInfo.shiftPrec); 1.123 - t = F.at(pos1).Binary(op, t, e); 1.124 - t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); 1.125 - } else { 1.126 - accept(GT); 1.127 - } 1.128 - } else if ((mode & TYPE) != 0 && 1.129 - (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) { 1.130 - //explicit lambda (w/ non-generic type) 1.131 + ParensResult pres = analyzeParens(); 1.132 + switch (pres) { 1.133 + case CAST: 1.134 + accept(LPAREN); 1.135 + mode = TYPE; 1.136 + int pos1 = pos; 1.137 + List<JCExpression> targets = List.of(t = term3()); 1.138 + while (token.kind == AMP) { 1.139 + checkIntersectionTypesInCast(); 1.140 + accept(AMP); 1.141 + targets = targets.prepend(term3()); 1.142 + } 1.143 + if (targets.length() > 1) { 1.144 + t = toP(F.at(pos1).TypeIntersection(targets.reverse())); 1.145 + } 1.146 + accept(RPAREN); 1.147 + mode = EXPR; 1.148 + JCExpression t1 = term3(); 1.149 + return F.at(pos).TypeCast(t, t1); 1.150 + case IMPLICIT_LAMBDA: 1.151 + case EXPLICIT_LAMBDA: 1.152 + t = lambdaExpressionOrStatement(true, pres == ParensResult.EXPLICIT_LAMBDA, pos); 1.153 + break; 1.154 + default: //PARENS 1.155 + accept(LPAREN); 1.156 mode = EXPR; 1.157 - JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER); 1.158 - if (token.kind == ELLIPSIS) { 1.159 - mods.flags = Flags.VARARGS; 1.160 - t = to(F.at(token.pos).TypeArray(t)); 1.161 - nextToken(); 1.162 - } 1.163 - t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos); 1.164 + t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec))); 1.165 + accept(RPAREN); 1.166 + t = toP(F.at(pos).Parens(t)); 1.167 break; 1.168 - } else { 1.169 - t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); 1.170 - } 1.171 - } 1.172 - 1.173 - accept(RPAREN); 1.174 - lastmode = mode; 1.175 - mode = EXPR; 1.176 - if ((lastmode & EXPR) == 0) { 1.177 - JCExpression t1 = term3(); 1.178 - return F.at(pos).TypeCast(t, t1); 1.179 - } else if ((lastmode & TYPE) != 0) { 1.180 - switch (token.kind) { 1.181 - /*case PLUSPLUS: case SUBSUB: */ 1.182 - case BANG: case TILDE: 1.183 - case LPAREN: case THIS: case SUPER: 1.184 - case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: 1.185 - case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL: 1.186 - case TRUE: case FALSE: case NULL: 1.187 - case NEW: case IDENTIFIER: case ASSERT: case ENUM: 1.188 - case BYTE: case SHORT: case CHAR: case INT: 1.189 - case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: 1.190 - JCExpression t1 = term3(); 1.191 - return F.at(pos).TypeCast(t, t1); 1.192 - } 1.193 } 1.194 } else { 1.195 return illegal(); 1.196 } 1.197 - t = toP(F.at(pos).Parens(t)); 1.198 break; 1.199 case THIS: 1.200 if ((mode & EXPR) != 0) { 1.201 @@ -1346,6 +1307,138 @@ 1.202 } 1.203 } 1.204 1.205 + /** 1.206 + * If we see an identifier followed by a '<' it could be an unbound 1.207 + * method reference or a binary expression. To disambiguate, look for a 1.208 + * matching '>' and see if the subsequent terminal is either '.' or '#'. 1.209 + */ 1.210 + @SuppressWarnings("fallthrough") 1.211 + ParensResult analyzeParens() { 1.212 + int depth = 0; 1.213 + boolean type = false; 1.214 + for (int lookahead = 0 ; ; lookahead++) { 1.215 + TokenKind tk = S.token(lookahead).kind; 1.216 + switch (tk) { 1.217 + case EXTENDS: case SUPER: case COMMA: 1.218 + type = true; 1.219 + case QUES: case DOT: case AMP: 1.220 + //skip 1.221 + break; 1.222 + case BYTE: case SHORT: case INT: case LONG: case FLOAT: 1.223 + case DOUBLE: case BOOLEAN: case CHAR: 1.224 + if (peekToken(lookahead, RPAREN)) { 1.225 + //Type, ')' -> cast 1.226 + return ParensResult.CAST; 1.227 + } else if (peekToken(lookahead, IDENTIFIER)) { 1.228 + //Type, 'Identifier -> explicit lambda 1.229 + return ParensResult.EXPLICIT_LAMBDA; 1.230 + } 1.231 + break; 1.232 + case LPAREN: 1.233 + if (lookahead != 0) { 1.234 + // '(' in a non-starting position -> parens 1.235 + return ParensResult.PARENS; 1.236 + } else if (peekToken(lookahead, RPAREN)) { 1.237 + // '(', ')' -> explicit lambda 1.238 + return ParensResult.EXPLICIT_LAMBDA; 1.239 + } 1.240 + break; 1.241 + case RPAREN: 1.242 + // if we have seen something that looks like a type, 1.243 + // then it's a cast expression 1.244 + if (type) return ParensResult.CAST; 1.245 + // otherwise, disambiguate cast vs. parenthesized expression 1.246 + // based on subsequent token. 1.247 + switch (S.token(lookahead + 1).kind) { 1.248 + /*case PLUSPLUS: case SUBSUB: */ 1.249 + case BANG: case TILDE: 1.250 + case LPAREN: case THIS: case SUPER: 1.251 + case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: 1.252 + case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL: 1.253 + case TRUE: case FALSE: case NULL: 1.254 + case NEW: case IDENTIFIER: case ASSERT: case ENUM: 1.255 + case BYTE: case SHORT: case CHAR: case INT: 1.256 + case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: 1.257 + return ParensResult.CAST; 1.258 + default: 1.259 + return ParensResult.PARENS; 1.260 + } 1.261 + case IDENTIFIER: 1.262 + if (peekToken(lookahead, IDENTIFIER)) { 1.263 + // Identifier, Identifier -> explicit lambda 1.264 + return ParensResult.EXPLICIT_LAMBDA; 1.265 + } else if (peekToken(lookahead, RPAREN, ARROW)) { 1.266 + // Identifier, ')' '->' -> implicit lambda 1.267 + return ParensResult.IMPLICIT_LAMBDA; 1.268 + } 1.269 + break; 1.270 + case FINAL: 1.271 + case ELLIPSIS: 1.272 + case MONKEYS_AT: 1.273 + //those can only appear in explicit lambdas 1.274 + return ParensResult.EXPLICIT_LAMBDA; 1.275 + case LBRACKET: 1.276 + if (peekToken(lookahead, RBRACKET, IDENTIFIER)) { 1.277 + // '[', ']', Identifier -> explicit lambda 1.278 + return ParensResult.EXPLICIT_LAMBDA; 1.279 + } else if (peekToken(lookahead, RBRACKET, RPAREN) || 1.280 + peekToken(lookahead, RBRACKET, AMP)) { 1.281 + // '[', ']', ')' -> cast 1.282 + // '[', ']', '&' -> cast (intersection type) 1.283 + return ParensResult.CAST; 1.284 + } else if (peekToken(lookahead, RBRACKET)) { 1.285 + //consume the ']' and skip 1.286 + type = true; 1.287 + lookahead++; 1.288 + break; 1.289 + } else { 1.290 + return ParensResult.PARENS; 1.291 + } 1.292 + case LT: 1.293 + depth++; break; 1.294 + case GTGTGT: 1.295 + depth--; 1.296 + case GTGT: 1.297 + depth--; 1.298 + case GT: 1.299 + depth--; 1.300 + if (depth == 0) { 1.301 + if (peekToken(lookahead, RPAREN) || 1.302 + peekToken(lookahead, AMP)) { 1.303 + // '>', ')' -> cast 1.304 + // '>', '&' -> cast 1.305 + return ParensResult.CAST; 1.306 + } else if (peekToken(lookahead, IDENTIFIER, COMMA) || 1.307 + peekToken(lookahead, IDENTIFIER, RPAREN, ARROW) || 1.308 + peekToken(lookahead, ELLIPSIS)) { 1.309 + // '>', Identifier, ',' -> explicit lambda 1.310 + // '>', Identifier, ')', '->' -> explicit lambda 1.311 + // '>', '...' -> explicit lambda 1.312 + return ParensResult.EXPLICIT_LAMBDA; 1.313 + } 1.314 + //it looks a type, but could still be (i) a cast to generic type, 1.315 + //(ii) an unbound method reference or (iii) an explicit lambda 1.316 + type = true; 1.317 + break; 1.318 + } else if (depth < 0) { 1.319 + //unbalanced '<', '>' - not a generic type 1.320 + return ParensResult.PARENS; 1.321 + } 1.322 + break; 1.323 + default: 1.324 + //this includes EOF 1.325 + return ParensResult.PARENS; 1.326 + } 1.327 + } 1.328 + } 1.329 + 1.330 + enum ParensResult { 1.331 + CAST, 1.332 + EXPLICIT_LAMBDA, 1.333 + IMPLICIT_LAMBDA, 1.334 + PARENS; 1.335 + } 1.336 + 1.337 JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) { 1.338 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); 1.339 params.append(firstParam); 1.340 @@ -3386,6 +3479,12 @@ 1.341 allowDefaultMethods = true; 1.342 } 1.343 } 1.344 + void checkIntersectionTypesInCast() { 1.345 + if (!allowIntersectionTypesInCast) { 1.346 + log.error(token.pos, "intersection.types.in.cast.not.supported.in.source", source.name); 1.347 + allowIntersectionTypesInCast = true; 1.348 + } 1.349 + } 1.350 1.351 /* 1.352 * a functional source tree and end position mappings