Index: /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/comp/Attr.java =================================================================== --- /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/comp/Attr.java (revision 145) +++ /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/comp/Attr.java (working copy) @@ -760,7 +760,6 @@ public void visitForeachLoop(JCEnhancedForLoop tree) { Env loopEnv = env.dup(env.tree, env.info.dup(env.info.scope.dup())); - attribStat(tree.var, loopEnv); Type exprType = types.upperBound(attribExpr(tree.expr, loopEnv)); chk.checkNonVoid(tree.pos(), exprType); Type elemtype = types.elemtype(exprType); // perhaps expr is an array? @@ -777,6 +776,10 @@ : types.upperBound(iterableParams.head); } } + if (tree.var.vartype==null) { // infer the type of the variable if needed + tree.var.type=elemtype; + } + attribStat(tree.var, loopEnv); chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type); loopEnv.tree = tree; // before, we were not in loop! attribStat(tree.body, loopEnv); Index: /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java =================================================================== --- /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java (revision 145) +++ /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java (working copy) @@ -28,7 +28,6 @@ package com.sun.tools.javac.comp; import java.util.*; -import java.util.Set; import javax.tools.JavaFileObject; import com.sun.tools.javac.code.*; @@ -44,6 +43,7 @@ import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; + import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; /** This is the second phase of Enter, in which classes are completed @@ -611,7 +611,7 @@ if ((tree.mods.flags & STATIC) != 0) localEnv.info.staticLevel++; return localEnv; } - + public void visitVarDef(JCVariableDecl tree) { Env localEnv = env; if ((tree.mods.flags & STATIC) != 0 || @@ -619,10 +619,32 @@ localEnv = env.dup(tree, env.info.dup()); localEnv.info.staticLevel++; } - attr.attribType(tree.vartype, localEnv); + + // the type is not known but is declared + if (tree.type==null && tree.vartype!=null) { + tree.type=attr.attribType(tree.vartype, localEnv); + } + Scope enclScope = enter.enterScope(env); - VarSymbol v = - new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner); + + VarSymbol v; + if (tree.type!=null) { + v = new VarSymbol(0, tree.name, tree.type, enclScope.owner); + } + else { + // create a variable without its type and infer it + v = new VarSymbol(0, tree.name, null, enclScope.owner); + // In order to catch self-references, we set + // the variable's declaration position to + // maximal possible value, effectively marking + // the variable as undefined. + v.pos = Position.MAXPOS; + tree.sym = v; + v.type = attr.attribExpr(tree.init, initEnv(tree, env), Type.noType).baseType(); + v.pos = Position.NOPOS; + + } + v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree); tree.sym = v; if (tree.init != null) { Index: /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/parser/Parser.java =================================================================== --- /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/parser/Parser.java (revision 145) +++ /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/parser/Parser.java (working copy) @@ -123,6 +123,9 @@ /** The name table. */ private Name.Table names; + + private final boolean inferLocallyAlgol; + private final boolean inferLocallyFinal; /** Construct a parser from a given scanner, tree factory and log. */ @@ -144,6 +147,8 @@ this.allowForeach = source.allowForeach(); this.allowStaticImport = source.allowStaticImport(); this.allowAnnotations = source.allowAnnotations(); + this.inferLocallyAlgol = "Algol".equals(options.get("inferLocally")); + this.inferLocallyFinal = "final".equals(options.get("inferLocally")); this.keepDocComments = keepDocComments; if (keepDocComments) docComments = new HashMap(); this.errorTree = F.Erroneous(); @@ -1545,12 +1550,27 @@ allowEnums && S.token() == ENUM) { stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); } else { + Name name = S.name(); JCExpression t = type(); - stats.appendList(variableDeclarators(mods, t, + if (inferLocallyFinal && S.token() == EQ && t.tag == JCTree.IDENT && (mods.flags & Flags.FINAL) != 0) { + accept(EQ); + JCExpression init = variableInitializer(); + stats.append(to(F.at(pos).VarDef(mods, name, null, init))); + accept(SEMI); + } else { + if (inferLocallyAlgol && S.token() == COLONASSIGN && t.tag == JCTree.IDENT) { + S.nextToken(); + JCExpression init = variableInitializer(); + stats.append(to(F.at(pos).VarDef(mods, name, null, init))); + accept(SEMI); + } else { + stats.appendList(variableDeclarators(mods, t, new ListBuffer())); - // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon - storeEnd(stats.elems.last(), S.endPos()); - accept(SEMI); + // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon + storeEnd(stats.elems.last(), S.endPos()); + accept(SEMI); + } + } } break; } @@ -1581,7 +1601,14 @@ default: Name name = S.name(); JCExpression t = term(EXPR | TYPE); - if (S.token() == COLON && t.tag == JCTree.IDENT) { + if (inferLocallyAlgol && S.token() == COLONASSIGN && t.tag == JCTree.IDENT) { + S.nextToken(); + JCExpression init = variableInitializer(); + JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); + stats.append(to(F.at(pos).VarDef(mods, name, null, init))); + accept(SEMI); + + } else if (S.token() == COLON && t.tag == JCTree.IDENT) { S.nextToken(); JCStatement stat = statement(); stats.append(F.at(pos).Labelled(name, stat)); @@ -1873,14 +1900,32 @@ ListBuffer stats = lb(); int pos = S.pos(); if (S.token() == FINAL || S.token() == MONKEYS_AT) { - return variableDeclarators(optFinal(0), type(), stats).toList(); + JCModifiers mods=optFinal(0); + Name name = S.name(); + JCExpression t=type(); + if (inferLocallyFinal && S.token() == COLON && t.tag == JCTree.IDENT && (mods.flags & Flags.FINAL) != 0) { + return stats.append(to(F.at(pos).VarDef(mods, name, null, null))).toList(); + } else { + if (inferLocallyAlgol && S.token() == COLON && t.tag == JCTree.IDENT) { + return stats.append(to(F.at(pos).VarDef(mods, name, null, null))).toList(); + } else { + return variableDeclarators(mods, t, stats).toList(); + } + } } else { + Name name = S.name(); JCExpression t = term(EXPR | TYPE); - if ((lastmode & TYPE) != 0 && - (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM)) - return variableDeclarators(modifiersOpt(), t, stats).toList(); - else - return moreStatementExpressions(pos, t, stats).toList(); + if ((lastmode & TYPE) != 0) { + if (inferLocallyAlgol && S.token() == COLON && t.tag == JCTree.IDENT) { + JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); + return stats.append(to(F.at(pos).VarDef(mods, name, null, null))).toList(); + } else { + if (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM) { + return variableDeclarators(modifiersOpt(), t, stats).toList(); + } + } + } + return moreStatementExpressions(pos, t, stats).toList(); } } Index: /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/parser/Token.java =================================================================== --- /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/parser/Token.java (revision 145) +++ /home/forax/java/workspace/java-compiler/src/share/classes/com/sun/tools/javac/parser/Token.java (working copy) @@ -111,6 +111,7 @@ COMMA(","), DOT("."), ELLIPSIS("..."), + COLONASSIGN(":="), EQ("="), GT(">"), LT("<"),