OpenJDK / amber / amber
changeset 58318:35114ceea341 lambda-leftovers
Automatic merge with default
author | mcimadamore |
---|---|
date | Tue, 15 Oct 2019 05:10:57 +0000 |
parents | 9e3829305823 2d9a265926ac |
children | bfc5a6e98ffd |
files | src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java |
diffstat | 12 files changed, 573 insertions(+), 287 deletions(-) [+] |
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Tue Oct 15 05:10:57 2019 +0000 @@ -978,6 +978,10 @@ } public void visitMethodDef(JCMethodDecl tree) { + boolean isLocal = env.info.scope.owner.kind == MTH; + if (isLocal) { + memberEnter.memberEnter(tree, env); + } MethodSymbol m = tree.sym; boolean isDefaultMethod = (m.flags() & DEFAULT) != 0; @@ -991,22 +995,26 @@ // Create a new environment with local scope // for attributing the method. - Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env); + Env<AttrContext> localEnv = isLocal ? + localMethodEnv(tree, env) : + memberEnter.methodEnv(tree, env); localEnv.info.lint = lint; attribStats(tree.typarams, localEnv); - // If we override any other methods, check that we do so properly. - // JLS ??? - if (m.isStatic()) { - chk.checkHideClashes(tree.pos(), env.enclClass.type, m); - } else { - chk.checkOverrideClashes(tree.pos(), env.enclClass.type, m); - } - chk.checkOverride(env, tree, m); - - if (isDefaultMethod && types.overridesObjectMethod(m.enclClass(), m)) { - log.error(tree, Errors.DefaultOverridesObjectMember(m.name, Kinds.kindName(m.location()), m.location())); + if (!isLocal) { + // If we override any other methods, check that we do so properly. + // JLS ??? + if (m.isStatic()) { + chk.checkHideClashes(tree.pos(), env.enclClass.type, m); + } else { + chk.checkOverrideClashes(tree.pos(), env.enclClass.type, m); + } + chk.checkOverride(env, tree, m); + + if (isDefaultMethod && types.overridesObjectMethod(m.enclClass(), m)) { + log.error(tree, Errors.DefaultOverridesObjectMember(m.name, Kinds.kindName(m.location()), m.location())); + } } // Enter all type parameters into the local method scope. @@ -3070,7 +3078,7 @@ * - an instance field, we use the first constructor. * - a static field, we create a fake clinit method. */ - public Env<AttrContext> lambdaEnv(JCLambda that, Env<AttrContext> env) { + public Env<AttrContext> lambdaEnv(JCTree that, Env<AttrContext> env) { Env<AttrContext> lambdaEnv; Symbol owner = env.info.scope.owner; ClassSymbol enclClass = owner.enclClass(); @@ -3120,6 +3128,16 @@ return lambdaEnv; } + public Env<AttrContext> localMethodEnv(JCMethodDecl that, Env<AttrContext> env) { + Env<AttrContext> localMethodEnv = lambdaEnv(that, env); + if (that.sym.type != null) { + //when this is called in the enter stage, there's no type to be set + localMethodEnv.info.returnResult = new ResultInfo(KindSelector.VAL, that.sym.type.getReturnType()); + } + return localMethodEnv; + } + + @Override public void visitReference(final JCMemberReference that) { if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Tue Oct 15 05:10:57 2019 +0000 @@ -335,20 +335,34 @@ * duplicate declaration checking *************************************************************************/ - /** Check that variable does not hide variable with same name in - * immediately enclosing local scope. + /** Check that variable (resp. local method) does not hide variable (resp. local method) with same + * name in immediately enclosing local scope. * @param pos Position for error reporting. - * @param v The symbol. + * @param byName The symbol. * @param s The scope. */ - void checkTransparentVar(DiagnosticPosition pos, VarSymbol v, Scope s) { - for (Symbol sym : s.getSymbolsByName(v.name)) { - if (sym.owner != v.owner) break; - if (sym.kind == VAR && - sym.owner.kind.matches(KindSelector.VAL_MTH) && - v.name != names.error) { - duplicateError(pos, sym); - return; + void checkTransparent(DiagnosticPosition pos, Symbol byName, Scope s) { + for (Symbol sym : s.getSymbolsByName(byName.name)) { + if (sym.owner != byName.owner) break; + checkDuplicateSymbol(pos, byName, sym); + } + } + + private void checkDuplicateSymbol(DiagnosticPosition pos, Symbol s1, Symbol s2) { + if (s1 != s2 && + (s2.flags() & CLASH) == 0 && + s1.kind == s2.kind && + s1.name != names.error && + (s1.kind != MTH || + types.hasSameArgs(s1.type, s2.type) || + types.hasSameArgs(types.erasure(s1.type), types.erasure(s2.type)))) { + if (s1.kind == MTH && (s1.flags() & VARARGS) != (s2.flags() & VARARGS)) { + varargsDuplicateError(pos, s1, s2); + } else if (s1.kind == MTH && !types.hasSameArgs(s1.type, s2.type, false)) { + duplicateErasureError(pos, s1, s2); + s1.flags_field |= CLASH; + } else { + duplicateError(pos, s2); } } } @@ -3435,26 +3449,7 @@ return true; if (sym.owner.name == names.any) return false; for (Symbol byName : s.getSymbolsByName(sym.name, NON_RECURSIVE)) { - if (sym != byName && - (byName.flags() & CLASH) == 0 && - sym.kind == byName.kind && - sym.name != names.error && - (sym.kind != MTH || - types.hasSameArgs(sym.type, byName.type) || - types.hasSameArgs(types.erasure(sym.type), types.erasure(byName.type)))) { - if ((sym.flags() & VARARGS) != (byName.flags() & VARARGS)) { - sym.flags_field |= CLASH; - varargsDuplicateError(pos, sym, byName); - return true; - } else if (sym.kind == MTH && !types.hasSameArgs(sym.type, byName.type, false)) { - duplicateErasureError(pos, sym, byName); - sym.flags_field |= CLASH; - return true; - } else { - duplicateError(pos, byName); - return false; - } - } + checkDuplicateSymbol(pos, sym, byName); } return true; }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Tue Oct 15 05:10:57 2019 +0000 @@ -2712,6 +2712,7 @@ } break; } + case METHODDEF: case LAMBDA: if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) { reportEffectivelyFinalError(pos, sym); @@ -2735,6 +2736,7 @@ reportInnerClsNeedsFinalError(tree, sym); break; } + case METHODDEF: case LAMBDA: reportEffectivelyFinalError(tree, sym); } @@ -2743,8 +2745,14 @@ } void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) { - String subKey = currentTree.hasTag(LAMBDA) ? - "lambda" : "inner.cls"; + String subKey; + switch (currentTree.getTag()) { + case LAMBDA: subKey = "lambda"; break; + case CLASSDEF: subKey = "inner.cls"; break; + case METHODDEF: subKey = "local.meth"; break; + default: + throw new AssertionError(); + } log.error(pos, Errors.CantRefNonEffectivelyFinalVar(sym, diags.fragment(subKey))); } @@ -2781,6 +2789,22 @@ } @Override + public void visitMethodDef(JCMethodDecl tree) { + if (tree.sym.owner.kind == MTH) { + //local method! + JCTree prevTree = currentTree; + try { + currentTree = tree; + super.visitMethodDef(tree); + } finally { + currentTree = prevTree; + } + } else { + super.visitMethodDef(tree); + } + } + + @Override public void visitIdent(JCIdent tree) { if (tree.sym.kind == VAR) { checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue Oct 15 05:10:57 2019 +0000 @@ -438,7 +438,7 @@ List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev); //convert to an invokedynamic call - result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args); + result = makeMetafactoryIndyCall(localContext, sym.asHandle(), indy_args); } // where @@ -464,6 +464,43 @@ } } + @Override + public void visitMethodDef(JCMethodDecl tree) { + TranslationContext<?> localContext = context; + if (localContext != null && localContext.tree == tree) { + MethodSymbol sym = localContext.translatedSym; + MethodType localMethodType = (MethodType)sym.type; + + //create a desugared (non-local) method + JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field), + sym.name, + make.QualIdent(localMethodType.getReturnType().tsym), + List.nil(), + localContext.syntheticParams, + localMethodType.getThrownTypes() == null ? + List.<JCExpression>nil() : + make.Types(localMethodType.getThrownTypes()), + null, + null); + lambdaDecl.sym = sym; + lambdaDecl.type = localMethodType; + + //As the local method body is translated, all references to parameters, + //captured variables, enclosing members are adjusted accordingly + //to refer to the static method parameters (rather than i.e. acessing to + //captured members directly). + lambdaDecl.body = translate(tree.body); + + //Add the method to the list of methods to be added to this class. + kInfo.addMethod(lambdaDecl); + + //omit this declaration from the enclosing body! + result = make.Skip(); + } else { + super.visitMethodDef(tree); + } + } + private JCIdent makeThis(Type type, Symbol owner) { VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC, names._this, @@ -520,6 +557,36 @@ result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args); } + @Override + public void visitApply(JCMethodInvocation tree) { + Symbol m = TreeInfo.symbol(tree.meth); + Optional<TranslationContext<?>> optContext = contextMap.values().stream() + .filter(c -> c.tree.hasTag(METHODDEF) && ((JCMethodDecl)c.tree).sym == m) + .findFirst(); + if (optContext.isPresent()) { + TranslationContext<?> localContext = optContext.get(); + Symbol sym = localContext.translatedSym; + ListBuffer<JCExpression> syntheticInits = new ListBuffer<>(); + + //add captured locals + for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) { + JCTree captured_local = make.Ident(fv).setType(fv.type); + syntheticInits.append((JCExpression)captured_local); + } + // add captured outer this instances (used only when `this' capture itself is illegal) + for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) { + JCTree captured_local = make.QualThis(fv.type); + syntheticInits.append((JCExpression)captured_local); + } + + //then, determine the arguments to the indy call + List<JCExpression> args = translate(tree.args.prependList(syntheticInits.toList()), localContext.prev); + result = make.Apply(List.nil(), make.Ident(sym), args).setType(tree.type); + } else { + super.visitApply(tree); + } + } + /** * Translate identifiers within a lambda to the mapped identifier * @param tree @@ -533,7 +600,7 @@ try { make.at(tree); - LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; + TranslationContext<?> lambdaContext = context; JCTree ltree = lambdaContext.translate(tree); if (ltree != null) { result = ltree; @@ -561,7 +628,7 @@ try { make.at(tree); - LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; + TranslationContext<?> lambdaContext = context; JCTree ltree = lambdaContext.translate(tree); if (ltree != null) { result = ltree; @@ -598,7 +665,7 @@ @Override public void visitVarDef(JCVariableDecl tree) { - LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context; + TranslationContext<?> lambdaContext = context; if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { tree.init = translate(tree.init); tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym); @@ -1086,7 +1153,7 @@ /** * Generate an indy method call to the meta factory */ - private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context, + private JCExpression makeMetafactoryIndyCall(FunctionalTranslationContext<?> context, MethodHandleSymbol refSym, List<JCExpression> indy_args) { JCFunctionalExpression tree = context.tree; //determine the static bsm args @@ -1322,8 +1389,7 @@ if (localContext.tree.hasTag(LAMBDA)) { JCTree block = capturedDecl(localContext.depth, outerInstanceSymbol); if (block == null) break; - ((LambdaTranslationContext)localContext) - .addSymbol(outerInstanceSymbol, CAPTURED_THIS); + localContext.addSymbol(outerInstanceSymbol, CAPTURED_THIS); } localContext = localContext.prev; } @@ -1349,25 +1415,23 @@ tree.type.constValue() == null) { TranslationContext<?> localContext = context(); while (localContext != null) { - if (localContext.tree.getTag() == LAMBDA) { + if (localContext.tree.getTag() == LAMBDA || localContext.tree.hasTag(METHODDEF)) { JCTree block = capturedDecl(localContext.depth, tree.sym); if (block == null) break; - ((LambdaTranslationContext)localContext) - .addSymbol(tree.sym, CAPTURED_VAR); + localContext.addSymbol(tree.sym, CAPTURED_VAR); } localContext = localContext.prev; } } else if (tree.sym.owner.kind == TYP) { TranslationContext<?> localContext = context(); while (localContext != null && !localContext.owner.isStatic()) { - if (localContext.tree.hasTag(LAMBDA)) { + if (localContext.tree.hasTag(LAMBDA) || localContext.tree.hasTag(METHODDEF)) { JCTree block = capturedDecl(localContext.depth, tree.sym); if (block == null) break; switch (block.getTag()) { case CLASSDEF: JCClassDecl cdecl = (JCClassDecl)block; - ((LambdaTranslationContext)localContext) - .addSymbol(cdecl.sym, CAPTURED_THIS); + localContext.addSymbol(cdecl.sym, CAPTURED_THIS); break; default: Assert.error("bad block kind"); @@ -1420,8 +1484,21 @@ public void visitMethodDef(JCMethodDecl tree) { List<Frame> prevStack = frameStack; try { - frameStack = frameStack.prepend(new Frame(tree)); - super.visitMethodDef(tree); + if (tree.sym.owner.kind == MTH) { + //local method + LocalMethodTranslationContext context = new LocalMethodTranslationContext(tree); + frameStack = frameStack.prepend(new Frame(tree)); + for (JCVariableDecl param : tree.params) { + context.addSymbol(param.sym, PARAM); + frameStack.head.addLocal(param.sym); + } + contextMap.put(tree, context); + super.visitMethodDef(tree); + context.complete(); + } else { + frameStack = frameStack.prepend(new Frame(tree)); + super.visitMethodDef(tree); + } } finally { frameStack = prevStack; @@ -1442,20 +1519,19 @@ JCTree block = capturedDecl(localContext.depth, outerInstanceSymbol); if (block == null) break; } - ((LambdaTranslationContext)localContext) - .addSymbol(outerInstanceSymbol, CAPTURED_THIS); + localContext.addSymbol(outerInstanceSymbol, CAPTURED_THIS); } localContext = localContext.prev; } } if (context() != null && !inReferencedClass && isLocal) { - LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context(); + TranslationContext<?> lambdaContext = context(); captureLocalClassDefs(def, lambdaContext); } super.visitNewClass(tree); } //where - void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) { + void captureLocalClassDefs(Symbol csym, final TranslationContext<?> lambdaContext) { JCClassDecl localCDef = localClassDefs.get(csym); if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) { BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() { @@ -1473,7 +1549,7 @@ if (localContext.tree.getTag() == LAMBDA) { JCTree block = capturedDecl(localContext.depth, sym); if (block == null) break; - ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR); + localContext.addSymbol(sym, CAPTURED_VAR); } localContext = localContext.prev; } @@ -1533,10 +1609,10 @@ // we much have an instance context TranslationContext<?> localContext = context(); while (localContext != null && !localContext.owner.isStatic()) { - if (localContext.tree.hasTag(LAMBDA)) { + if (localContext.tree.hasTag(LAMBDA) || localContext.tree.hasTag(METHODDEF)) { JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym); if (clazz == null) break; - ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS); + localContext.addSymbol(clazz.sym, CAPTURED_THIS); } localContext = localContext.prev; } @@ -1546,10 +1622,7 @@ @Override public void visitVarDef(JCVariableDecl tree) { - TranslationContext<?> context = context(); - LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)? - (LambdaTranslationContext)context : - null; + TranslationContext<?> ltc = context(); if (ltc != null) { if (frameStack.head.tree.hasTag(LAMBDA)) { ltc.addSymbol(tree.sym, LOCAL_VAR); @@ -1730,9 +1803,10 @@ return null; } - private TranslationContext<?> context() { + @SuppressWarnings("unchecked") + private <T extends JCTree, Z extends TranslationContext<T>> Z context() { for (Frame frame : frameStack) { - TranslationContext<?> context = contextMap.get(frame.tree); + Z context = (Z)contextMap.get(frame.tree); if (context != null) { return context; } @@ -1756,14 +1830,11 @@ * set of nodes that select `this' (qualified this) */ private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) { - LambdaTranslationContext lambdaContext = - context instanceof LambdaTranslationContext ? - (LambdaTranslationContext) context : null; - return lambdaContext != null + return context != null && !fAccess.sym.isStatic() && fAccess.name == names._this && (fAccess.sym.owner.kind == TYP) - && !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty(); + && !context.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty(); } /** @@ -1806,10 +1877,10 @@ } /** - * This class is used to store important information regarding translation of - * lambda expression/method references (see subclasses). + * This class is the common root for modelling the translation context associated with + * constructs handled by LambdaToMethod (lambdas, method references, local methods). */ - abstract class TranslationContext<T extends JCFunctionalExpression> { + abstract class TranslationContext<T extends JCTree> { /** the underlying (untranslated) tree */ final T tree; @@ -1822,109 +1893,26 @@ /** the enclosing translation context (set for nested lambdas/mref) */ final TranslationContext<?> prev; + /** + * to prevent recursion, track local classes processed + */ + final Set<Symbol> freeVarProcessedLocalClasses; - /** list of methods to be bridged by the meta-factory */ - final List<Symbol> bridges; + + Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols; + /** the synthetic symbol for the method hoisting the translated lambda */ + MethodSymbol translatedSym; + List<JCVariableDecl> syntheticParams; + TranslationContext(T tree) { this.tree = tree; this.owner = owner(true); this.depth = frameStack.size() - 1; this.prev = context(); - ClassSymbol csym = - types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE); - this.bridges = types.functionalInterfaceBridges(csym); - } - /** does this functional expression need to be created using alternate metafactory? */ - boolean needsAltMetafactory() { - return tree.target.isIntersection() || - isSerializable() || - bridges.length() > 1; - } - - /** does this functional expression require serialization support? */ - boolean isSerializable() { - if (forceSerializable) { - return true; - } - return types.asSuper(tree.target, syms.serializableType.tsym) != null; - } - - /** - * @return Name of the enclosing method to be folded into synthetic - * method name - */ - String enclosingMethodName() { - return syntheticMethodNameComponent(owner.name); - } - - /** - * @return Method name in a form that can be folded into a - * component of a synthetic method name - */ - String syntheticMethodNameComponent(Name name) { - if (name == null) { - return "null"; - } - String methodName = name.toString(); - if (methodName.equals("<clinit>")) { - methodName = "static"; - } else if (methodName.equals("<init>")) { - methodName = "new"; - } - return methodName; - } - } - - /** - * This class retains all the useful information about a lambda expression; - * the contents of this class are filled by the LambdaAnalyzer visitor, - * and the used by the main translation routines in order to adjust references - * to captured locals/members, etc. - */ - class LambdaTranslationContext extends TranslationContext<JCLambda> { - - /** variable in the enclosing context to which this lambda is assigned */ - final Symbol self; - - /** variable in the enclosing context to which this lambda is assigned */ - final Symbol assignedTo; - - Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols; - - /** the synthetic symbol for the method hoisting the translated lambda */ - MethodSymbol translatedSym; - - List<JCVariableDecl> syntheticParams; - - /** - * to prevent recursion, track local classes processed - */ - final Set<Symbol> freeVarProcessedLocalClasses; - - /** - * For method references converted to lambdas. The method - * reference receiver expression. Must be treated like a captured - * variable. - */ - JCExpression methodReferenceReceiver; - - LambdaTranslationContext(JCLambda tree) { - super(tree); - Frame frame = frameStack.head; - switch (frame.tree.getTag()) { - case VARDEF: - assignedTo = self = ((JCVariableDecl) frame.tree).sym; - break; - case ASSIGN: - self = null; - assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable()); - break; - default: - assignedTo = self = null; - break; - } + freeVarProcessedLocalClasses = new HashSet<>(); + translatedSymbols = new EnumMap<>(LambdaSymbolKind.class); // This symbol will be filled-in in complete if (owner.kind == MTH) { @@ -1938,93 +1926,12 @@ } else { this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass()); } - translatedSymbols = new EnumMap<>(LambdaSymbolKind.class); translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>()); translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>()); translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>()); translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>()); translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>()); - - freeVarProcessedLocalClasses = new HashSet<>(); - } - - /** - * For a serializable lambda, generate a disambiguating string - * which maximizes stability across deserialization. - * - * @return String to differentiate synthetic lambda method names - */ - private String serializedLambdaDisambiguation() { - StringBuilder buf = new StringBuilder(); - // Append the enclosing method signature to differentiate - // overloaded enclosing methods. For lambdas enclosed in - // lambdas, the generated lambda method will not have type yet, - // but the enclosing method's name will have been generated - // with this same method, so it will be unique and never be - // overloaded. - Assert.check( - owner.type != null || - directlyEnclosingLambda() != null); - if (owner.type != null) { - buf.append(typeSig(owner.type, true)); - buf.append(":"); - } - - // Add target type info - buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName()); - buf.append(" "); - - // Add variable assigned to - if (assignedTo != null) { - buf.append(assignedTo.flatName()); - buf.append("="); - } - //add captured locals info: type, name, order - for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) { - if (fv != self) { - buf.append(typeSig(fv.type, true)); - buf.append(" "); - buf.append(fv.flatName()); - buf.append(","); - } - } - - return buf.toString(); - } - - /** - * For a non-serializable lambda, generate a simple method. - * - * @return Name to use for the synthetic lambda method name - */ - private Name lambdaName() { - return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++)); - } - - /** - * For a serializable lambda, generate a method name which maximizes - * name stability across deserialization. - * - * @return Name to use for the synthetic lambda method name - */ - private Name serializedLambdaName() { - StringBuilder buf = new StringBuilder(); - buf.append(names.lambda); - // Append the name of the method enclosing the lambda. - buf.append(enclosingMethodName()); - buf.append('$'); - // Append a hash of the disambiguating string : enclosing method - // signature, etc. - String disam = serializedLambdaDisambiguation(); - buf.append(Integer.toHexString(disam.hashCode())); - buf.append('$'); - // The above appended name components may not be unique, append - // a count based on the above name components. - buf.append(syntheticMethodNameCounts.getIndex(buf)); - String result = buf.toString(); - //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam); - return names.fromString(result); } /** @@ -2156,6 +2063,32 @@ } /** + * @return Name of the enclosing method to be folded into synthetic + * method name + */ + String enclosingMethodName() { + return syntheticMethodNameComponent(owner.name); + } + + /** + * @return Method name in a form that can be folded into a + * component of a synthetic method name + */ + String syntheticMethodNameComponent(Name name) { + if (name == null) { + return "null"; + } + String methodName = name.toString(); + if (methodName.equals("<clinit>")) { + methodName = "static"; + } else if (methodName.equals("<init>")) { + methodName = "new"; + } + return methodName; + } + + + /** * The translatedSym is not complete/accurate until the analysis is * finished. Once the analysis is finished, the translatedSym is * "completed" -- updated with type information, access modifiers, @@ -2173,7 +2106,7 @@ // Lambda methods are private synthetic. // Inherit ACC_STRICT from the enclosing method, or, for clinit, // from the class. - translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD | + translatedSym.flags_field = SYNTHETIC | extraFlags() | owner.flags_field & STRICTFP | owner.owner.flags_field & STRICTFP | PRIVATE | @@ -2205,19 +2138,211 @@ translatedSym.params = parameterSymbols.toList(); // Compute and set the lambda name - translatedSym.name = isSerializable() - ? serializedLambdaName() - : lambdaName(); + translatedSym.name = generatedName(); //prepend synthetic args to translated lambda method signature translatedSym.type = types.createMethodTypeWithParameters( - generatedLambdaSig(), + generatedSig(), TreeInfo.types(syntheticParams)); } - Type generatedLambdaSig() { + abstract Type generatedSig(); + + abstract Name generatedName(); + + long extraFlags() { return 0; } + } + + /** + * This class is used to store important information regarding translation of + * lambda expression/method references (see subclasses). + */ + abstract class FunctionalTranslationContext<T extends JCFunctionalExpression> extends TranslationContext<T> { + + /** list of methods to be bridged by the meta-factory */ + final List<Symbol> bridges; + + FunctionalTranslationContext(T tree) { + super(tree); + ClassSymbol csym = + types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE); + this.bridges = types.functionalInterfaceBridges(csym); + } + + /** does this functional expression need to be created using alternate metafactory? */ + boolean needsAltMetafactory() { + return tree.target.isIntersection() || + isSerializable() || + bridges.length() > 1; + } + + /** does this functional expression require serialization support? */ + boolean isSerializable() { + if (forceSerializable) { + return true; + } + return types.asSuper(tree.target, syms.serializableType.tsym) != null; + } + + /** + * @return Name of the enclosing method to be folded into synthetic + * method name + */ + String enclosingMethodName() { + return syntheticMethodNameComponent(owner.name); + } + + /** + * @return Method name in a form that can be folded into a + * component of a synthetic method name + */ + String syntheticMethodNameComponent(Name name) { + if (name == null) { + return "null"; + } + String methodName = name.toString(); + if (methodName.equals("<clinit>")) { + methodName = "static"; + } else if (methodName.equals("<init>")) { + methodName = "new"; + } + return methodName; + } + } + + /** + * This class retains all the useful information about a lambda expression; + * the contents of this class are filled by the LambdaAnalyzer visitor, + * and the used by the main translation routines in order to adjust references + * to captured locals/members, etc. + */ + class LambdaTranslationContext extends FunctionalTranslationContext<JCLambda> { + + /** variable in the enclosing context to which this lambda is assigned */ + final Symbol self; + + /** variable in the enclosing context to which this lambda is assigned */ + final Symbol assignedTo; + + /** + * For method references converted to lambdas. The method + * reference receiver expression. Must be treated like a captured + * variable. + */ + JCExpression methodReferenceReceiver; + + LambdaTranslationContext(JCLambda tree) { + super(tree); + Frame frame = frameStack.head; + switch (frame.tree.getTag()) { + case VARDEF: + assignedTo = self = ((JCVariableDecl) frame.tree).sym; + break; + case ASSIGN: + self = null; + assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable()); + break; + default: + assignedTo = self = null; + break; + } + } + + /** + * For a serializable lambda, generate a disambiguating string + * which maximizes stability across deserialization. + * + * @return String to differentiate synthetic lambda method names + */ + private String serializedLambdaDisambiguation() { + StringBuilder buf = new StringBuilder(); + // Append the enclosing method signature to differentiate + // overloaded enclosing methods. For lambdas enclosed in + // lambdas, the generated lambda method will not have type yet, + // but the enclosing method's name will have been generated + // with this same method, so it will be unique and never be + // overloaded. + Assert.check( + owner.type != null || + directlyEnclosingLambda() != null); + if (owner.type != null) { + buf.append(typeSig(owner.type)); + buf.append(":"); + } + + // Add target type info + buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName()); + buf.append(" "); + + // Add variable assigned to + if (assignedTo != null) { + buf.append(assignedTo.flatName()); + buf.append("="); + } + //add captured locals info: type, name, order + for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) { + if (fv != self) { + buf.append(typeSig(fv.type)); + buf.append(" "); + buf.append(fv.flatName()); + buf.append(","); + } + } + + return buf.toString(); + } + + /** + * For a non-serializable lambda, generate a simple method. + * + * @return Name to use for the synthetic lambda method name + */ + private Name lambdaName() { + return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++)); + } + + /** + * For a serializable lambda, generate a method name which maximizes + * name stability across deserialization. + * + * @return Name to use for the synthetic lambda method name + */ + private Name serializedLambdaName() { + StringBuilder buf = new StringBuilder(); + buf.append(names.lambda); + // Append the name of the method enclosing the lambda. + buf.append(enclosingMethodName()); + buf.append('$'); + // Append a hash of the disambiguating string : enclosing method + // signature, etc. + String disam = serializedLambdaDisambiguation(); + buf.append(Integer.toHexString(disam.hashCode())); + buf.append('$'); + // The above appended name components may not be unique, append + // a count based on the above name components. + buf.append(syntheticMethodNameCounts.getIndex(buf)); + String result = buf.toString(); + //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam); + return names.fromString(result); + } + + @Override + Name generatedName() { + return isSerializable() ? + serializedLambdaName() : + lambdaName(); + } + + @Override + Type generatedSig() { return types.erasure(tree.getDescriptorType(types)); } + + @Override + long extraFlags() { + return LAMBDA_METHOD; + } + } /** @@ -2226,7 +2351,7 @@ * and the used by the main translation routines in order to adjust method * references (i.e. in case a bridge is needed) */ - final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> { + final class ReferenceTranslationContext extends FunctionalTranslationContext<JCMemberReference> { final boolean isSuper; @@ -2320,7 +2445,43 @@ Type bridgedRefSig() { return types.erasure(types.findDescriptorSymbol(tree.target.tsym).type); } + + + @Override + void complete() { + Assert.error(); + } + + @Override + Name generatedName() { + Assert.error(); + return null; + } + + @Override + Type generatedSig() { + Assert.error(); + return null; + } } + + class LocalMethodTranslationContext extends TranslationContext<JCMethodDecl> { + + public LocalMethodTranslationContext(JCMethodDecl tree) { + super(tree); + } + + @Override + Name generatedName() { + return names.local.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++)); + } + + @Override + Type generatedSig() { + return tree.type; + } + + } } // </editor-fold>
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Tue Oct 15 05:10:57 2019 +0000 @@ -2532,7 +2532,7 @@ lambdaTranslationMap; try { lambdaTranslationMap = (tree.sym.flags() & SYNTHETIC) != 0 && - tree.sym.name.startsWith(names.lambda) ? + (tree.sym.name.startsWith(names.lambda) || tree.sym.name.startsWith(names.local)) ? makeTranslationMap(tree) : null; super.visitMethodDef(tree); } finally {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Tue Oct 15 05:10:57 2019 +0000 @@ -176,7 +176,10 @@ } public void visitMethodDef(JCMethodDecl tree) { - WriteableScope enclScope = enter.enterScope(env); + boolean isLocal = env.info.scope.owner.kind == MTH; + WriteableScope enclScope = isLocal ? + env.info.scope : + enter.enterScope(env); MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner); m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree); tree.sym = m; @@ -186,7 +189,7 @@ m.owner.flags_field |= DEFAULT; } - Env<AttrContext> localEnv = methodEnv(tree, env); + Env<AttrContext> localEnv = isLocal ? attr.localMethodEnv(tree, env) : methodEnv(tree, env); DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos()); try { // Compute the method type @@ -217,7 +220,10 @@ localEnv.info.scope.leave(); if (chk.checkUnique(tree.pos(), m, enclScope)) { - enclScope.enter(m); + if (isLocal) { + chk.checkTransparent(tree.pos(), m, enclScope); + } + enclScope.enter(m); } annotate.annotateLater(tree.mods.annotations, localEnv, m, tree.pos()); @@ -297,7 +303,7 @@ } } if (chk.checkUnique(tree.pos(), v, enclScope)) { - chk.checkTransparentVar(tree.pos(), v, enclScope); + chk.checkTransparent(tree.pos(), v, enclScope); enclScope.enter(v); } else if (v.owner.kind == MTH) { enclScope.enter(v);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Tue Oct 15 05:10:57 2019 +0000 @@ -1553,8 +1553,9 @@ Symbol bestSoFar, boolean allowBoxing, boolean useVarargs) { + boolean isLocalMethod = sym.owner.kind == MTH; if (sym.kind == ERR || - (site.tsym != sym.owner && !sym.isInheritedIn(site.tsym, types)) || + (site.tsym != sym.owner && (!isLocalMethod && !sym.isInheritedIn(site.tsym, types))) || !notOverriddenIn(site, sym)) { return bestSoFar; } else if (useVarargs && (sym.flags() & VARARGS) == 0) { @@ -1579,7 +1580,7 @@ return bestSoFar; } } - if (!isAccessible(env, site, sym)) { + if (!isLocalMethod && !isAccessible(env, site, sym)) { return (bestSoFar.kind == ABSENT_MTH) ? new AccessError(env, site, sym) : bestSoFar; @@ -1612,6 +1613,9 @@ boolean m2SignatureMoreSpecific = signatureMoreSpecific(argtypes, env, site, m2, m1, useVarargs); if (m1SignatureMoreSpecific && m2SignatureMoreSpecific) { + if (m1.owner.kind == MTH || m2.owner.kind == MTH) { + return ambiguityError(m1, m2); + } Type mt1 = types.memberType(site, m1); Type mt2 = types.memberType(site, m2); if (!types.overrideEquivalent(mt1, mt2)) @@ -1935,8 +1939,13 @@ Assert.check(env1.info.preferredTreeForDiagnostics == null); env1.info.preferredTreeForDiagnostics = env.tree; try { - Symbol sym = findMethod( - env1, env1.enclClass.sym.type, name, argtypes, typeargtypes, + Symbol sym = findMethodInScope(env1, env1.enclClass.type, name, argtypes, typeargtypes, + env1.info.scope, bestSoFar, allowBoxing, useVarargs, true); + if (sym.exists()) { + return sym; + } + sym = findMethod( + env1, env1.enclClass.sym.type, name, argtypes, typeargtypes, allowBoxing, useVarargs); if (sym.exists()) { if (staticOnly &&
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Oct 15 05:10:57 2019 +0000 @@ -1474,7 +1474,8 @@ */ class ScanNested extends TreeScanner { Set<Env<AttrContext>> dependencies = new LinkedHashSet<>(); - protected boolean hasLambdas; + protected boolean needsLambdaToMethod; + protected boolean inMethod; @Override public void visitClassDef(JCClassDecl node) { Type st = types.supertype(node.sym.type); @@ -1484,17 +1485,17 @@ Env<AttrContext> stEnv = enter.getEnv(c); if (stEnv != null && env != stEnv) { if (dependencies.add(stEnv)) { - boolean prevHasLambdas = hasLambdas; + boolean prevHasLambdas = needsLambdaToMethod; try { scan(stEnv.tree); } finally { /* - * ignore any updates to hasLambdas made during + * ignore any updates to needsLambdaToMethod made during * the nested scan, this ensures an initalized * LambdaToMethod is available only to those * classes that contain lambdas */ - hasLambdas = prevHasLambdas; + needsLambdaToMethod = prevHasLambdas; } } envForSuperTypeFound = true; @@ -1505,12 +1506,27 @@ } @Override public void visitLambda(JCLambda tree) { - hasLambdas = true; + needsLambdaToMethod = true; super.visitLambda(tree); } + + @Override + public void visitMethodDef(JCMethodDecl tree) { + if (inMethod) { + needsLambdaToMethod = true; + } + boolean prevInMethod = inMethod; + try { + inMethod = true; + super.visitMethodDef(tree); + } finally { + inMethod = prevInMethod; + } + } + @Override public void visitReference(JCMemberReference tree) { - hasLambdas = true; + needsLambdaToMethod = true; super.visitReference(tree); } } @@ -1558,7 +1574,7 @@ env.tree = transTypes.translateTopLevelClass(env.tree, localMake); compileStates.put(env, CompileState.TRANSTYPES); - if (Feature.LAMBDA.allowedInSource(source) && scanner.hasLambdas) { + if (Feature.LAMBDA.allowedInSource(source) && scanner.needsLambdaToMethod) { if (shouldStop(CompileState.UNLAMBDA)) return;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Tue Oct 15 05:10:57 2019 +0000 @@ -2584,6 +2584,28 @@ log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.LocalEnum); dc = token.comment(CommentStyle.JAVADOC); return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc)); + case LT: + if (isExplicitConstructorCall()) { + JCExpression t = term(EXPR | TYPE); + t = checkExprStat(t); + accept(SEMI); + JCExpressionStatement expr = toP(F.at(pos).Exec(t)); + return List.<JCStatement>of(expr); + } + case VOID: { + List<JCTypeParameter> params = typeParametersOpt(); + JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); + JCExpression returnType = null; + if (token.kind == VOID) { + accept(VOID); + } else { + returnType = term(EXPR | TYPE); + } + ListBuffer<JCStatement> stats = new ListBuffer<>(); + stats.add(methodDeclaratorRest(pos, mods, returnType, ident(), params, false, returnType == null, null)); + storeEnd(stats.last(), S.prevToken().endPos); + return stats.toList(); + } case IDENTIFIER: if (token.name() == names.yield && allowYieldStatement) { Token next = S.token(1); @@ -2653,14 +2675,44 @@ } //where private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) { - ListBuffer<JCStatement> stats = - variableDeclarators(mods, type, new ListBuffer<>(), true); - // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon - accept(SEMI); + ListBuffer<JCStatement> stats; + if (peekToken(LPAREN)) { + stats = new ListBuffer<>(); + stats.add(methodDeclaratorRest(token.pos, mods, type, ident(), List.nil(), false, false, null)); + } else { + stats = variableDeclarators(mods, type, new ListBuffer<JCStatement>(), true); + // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon + accept(SEMI); + } storeEnd(stats.last(), S.prevToken().endPos); return stats.toList(); } + boolean isExplicitConstructorCall() { + int depth = 0; + for (int lookahead = 0 ; ; lookahead++) { + TokenKind tk = S.token(lookahead).kind; + switch (tk) { + case LT: + depth++; + break; + case GT: + depth--; + break; + case GTGT: + depth -= 2; + break; + case GTGTGT: + depth -= 3; + break; + } + if (depth == 0) { + Token name = S.token(lookahead + 1); + return name.kind == SUPER || name.kind == THIS; + } + } + } + /** Statement = * Block * | IF ParExpression Statement [ELSE Statement] @@ -4085,7 +4137,7 @@ * ConstructorDeclaratorRest = * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody */ - protected JCTree methodDeclaratorRest(int pos, + protected JCStatement methodDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Oct 15 05:10:57 2019 +0000 @@ -351,6 +351,9 @@ compiler.misc.inner.cls=\ an inner class +compiler.misc.local.meth=\ + a local method + # 0: type compiler.err.cant.deref=\ {0} cannot be dereferenced
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Tue Oct 15 05:10:57 2019 +0000 @@ -827,7 +827,7 @@ /** * A method definition. */ - public static class JCMethodDecl extends JCTree implements MethodTree { + public static class JCMethodDecl extends JCStatement implements MethodTree { /** method modifiers */ public JCModifiers mods; /** method name */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java Fri Oct 11 20:56:57 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java Tue Oct 15 05:10:57 2019 +0000 @@ -187,6 +187,7 @@ public final Name metafactory; public final Name altMetafactory; public final Name dollarThis; + public final Name local; // string concat public final Name makeConcat; @@ -338,6 +339,7 @@ lambda = fromString("lambda$"); metafactory = fromString("metafactory"); altMetafactory = fromString("altMetafactory"); + local = fromString("local$"); // string concat makeConcat = fromString("makeConcat");