changeset 57819:4a076215a664 patterns-deconstruction

Automatic merge with records-and-sealed
author mcimadamore
date Fri, 06 Sep 2019 18:01:45 +0000
parents 71e01dab5d42 16aa4bd64e80
children d058b932abb6
files src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java
diffstat 4 files changed, 69 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Thu Sep 05 18:47:59 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Sep 06 18:01:45 2019 +0000
@@ -1936,17 +1936,21 @@
 
         /** Check that trackable variable is initialized.
          */
-        void checkInit(DiagnosticPosition pos, VarSymbol sym) {
-            checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
+        boolean checkInit(DiagnosticPosition pos, VarSymbol sym, boolean compactConstructor) {
+            return checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym), compactConstructor);
         }
 
-        void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
+        boolean checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey, boolean compactConstructor) {
             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
                 trackable(sym) &&
                 !inits.isMember(sym.adr)) {
-                log.error(pos, errkey);
+                if (sym.owner.kind != TYP || !compactConstructor || !uninits.isMember(sym.adr)) {
+                    log.error(pos, errkey);
+                }
                 inits.incl(sym.adr);
+                return false;
             }
+            return true;
         }
 
         /** Utility method to reset several Bits instances.
@@ -2164,23 +2168,26 @@
                     // leave caught unchanged.
                     scan(tree.body);
 
+                    boolean isCompactConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0;
                     if (isInitialConstructor) {
                         boolean isSynthesized = (tree.sym.flags() &
                                                  GENERATEDCONSTR) != 0;
-                        boolean isRecord = (tree.sym.owner.flags() & Flags.RECORD) != 0;
-                        // skip record as they are generated by the compiler and guaranteed to be correct
-                        if (!isRecord || !isSynthesized) {
-                            for (int i = firstadr; i < nextadr; i++) {
-                                JCVariableDecl vardecl = vardecls[i];
-                                VarSymbol var = vardecl.sym;
-                                if (var.owner == classDef.sym) {
-                                    // choose the diagnostic position based on whether
-                                    // the ctor is default(synthesized) or not
-                                    if (isSynthesized) {
-                                        checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
-                                            var, Errors.VarNotInitializedInDefaultConstructor(var));
-                                    } else {
-                                        checkInit(TreeInfo.diagEndPos(tree.body), var);
+                        for (int i = firstadr; i < nextadr; i++) {
+                            JCVariableDecl vardecl = vardecls[i];
+                            VarSymbol var = vardecl.sym;
+                            if (var.owner == classDef.sym) {
+                                // choose the diagnostic position based on whether
+                                // the ctor is default(synthesized) or not
+                                if (isSynthesized && !isCompactConstructor) {
+                                    checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
+                                        var, Errors.VarNotInitializedInDefaultConstructor(var), isCompactConstructor);
+                                } else {
+                                    boolean wasInitialized = checkInit(TreeInfo.diagEndPos(tree.body), var, isCompactConstructor);
+                                    if (!wasInitialized && var.owner.kind == TYP && isCompactConstructor && uninits.isMember(var.adr)) {
+                                        /*  this way we indicate Lower that it should generate an initialization for this field
+                                         *  in the compact constructor
+                                         */
+                                        var.flags_field |= COMPACT_RECORD_CONSTRUCTOR;
                                     }
                                 }
                             }
@@ -2198,7 +2205,7 @@
                             Assert.check(exit instanceof AssignPendingExit);
                             inits.assign(((AssignPendingExit) exit).exit_inits);
                             for (int i = firstadr; i < nextadr; i++) {
-                                checkInit(exit.tree.pos(), vardecls[i].sym);
+                                checkInit(exit.tree.pos(), vardecls[i].sym, isCompactConstructor);
                             }
                         }
                     }
@@ -2740,7 +2747,7 @@
             super.visitSelect(tree);
             if (TreeInfo.isThisQualifier(tree.selected) &&
                 tree.sym.kind == VAR) {
-                checkInit(tree.pos(), (VarSymbol)tree.sym);
+                checkInit(tree.pos(), (VarSymbol)tree.sym, false);
             }
         }
 
@@ -2801,7 +2808,7 @@
 
         public void visitIdent(JCIdent tree) {
             if (tree.sym.kind == VAR) {
-                checkInit(tree.pos(), (VarSymbol)tree.sym);
+                checkInit(tree.pos(), (VarSymbol)tree.sym, false);
                 referenced(tree.sym);
             }
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Thu Sep 05 18:47:59 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Sep 06 18:01:45 2019 +0000
@@ -2781,6 +2781,27 @@
                 lambdaTranslationMap = prevLambdaTranslationMap;
             }
         }
+        if (tree.name == names.init && (tree.sym.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
+            // lets find out if there is any field waiting to be initialized
+            ListBuffer<VarSymbol> fields = new ListBuffer<>();
+            for (Symbol sym : currentClass.getEnclosedElements()) {
+                if (sym.kind == Kinds.Kind.VAR && ((sym.flags() & RECORD) != 0))
+                    fields.append((VarSymbol) sym);
+            }
+            for (VarSymbol field: fields) {
+                if ((field.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
+                    VarSymbol param = tree.params.stream().filter(p -> p.name == field.name).findFirst().get().sym;
+                    make.at(tree.pos);
+                    tree.body.stats = tree.body.stats.append(
+                            make.Exec(
+                                    make.Assign(
+                                            make.Select(make.This(field.owner.erasure(types)), field),
+                                            make.Ident(param)).setType(field.erasure(types))));
+                    // we don't need the flag at the field anymore
+                    field.flags_field &= ~Flags.COMPACT_RECORD_CONSTRUCTOR;
+                }
+            }
+        }
         result = tree;
     }
     //where
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Thu Sep 05 18:47:59 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Fri Sep 06 18:01:45 2019 +0000
@@ -969,7 +969,6 @@
                                     TreeInfo.getConstructorInvocationName(((JCMethodDecl)def).body.stats, names, true);
                             if (constructorInvocationName == names.empty ||
                                     constructorInvocationName == names._super) {
-                                RecordConstructorHelper helper = new RecordConstructorHelper(sym, TreeInfo.recordFields(tree));
                                 JCMethodDecl methDecl = (JCMethodDecl)def;
                                 if ((methDecl.mods.flags & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
                                     if (constructorInvocationName == names.empty) {
@@ -977,19 +976,6 @@
                                                 make.Ident(names._super), List.nil()));
                                         methDecl.body.stats = methDecl.body.stats.prepend(supCall);
                                     }
-                                    ListBuffer<JCStatement> initializations = new ListBuffer<>();
-                                    List<Name> inits = helper.inits();
-                                    InitializationFinder initFinder = new InitializationFinder(inits);
-                                    initFinder.scan(methDecl.body.stats);
-                                    List<Name> found = initFinder.found.toList();
-                                    inits = inits.diff(found);
-                                    if (!inits.isEmpty()) {
-                                        for (Name initName : inits) {
-                                            initializations.add(make.Exec(make.Assign(make.Select(make.Ident(names._this),
-                                                    initName), make.Ident(initName))));
-                                        }
-                                        methDecl.body.stats = methDecl.body.stats.appendList(initializations.toList());
-                                    }
                                 }
                             }
                         }
@@ -1025,29 +1011,6 @@
             }
         }
 
-        class InitializationFinder extends TreeScanner {
-            List<Name> fieldNames;
-            ListBuffer<Name> found = new ListBuffer<>();
-
-            public InitializationFinder(List<Name> fieldNames) {
-                this.fieldNames = fieldNames;
-            }
-
-            @Override
-            public void visitAssign(JCAssign tree) {
-                super.visitAssign(tree);
-                if (tree.lhs.hasTag(SELECT)) {
-                    JCFieldAccess select = (JCFieldAccess)tree.lhs;
-                    if ((select.selected.hasTag(IDENT)) &&
-                            ((JCIdent)select.selected).name == names._this) {
-                        if (fieldNames.contains(select.name)) {
-                            found.add(select.name);
-                        }
-                    }
-                }
-            }
-        }
-
         /** Enter members for a class.
          */
         void finishClass(JCClassDecl tree, Env<AttrContext> env, boolean defaultConstructorGenerated) {
@@ -1462,7 +1425,6 @@
        Type enclosingType();
        TypeSymbol owner();
        List<Name> superArgs();
-       List<Name> inits();
        default JCMethodDecl finalAdjustment(JCMethodDecl md) { return md; }
     }
 
@@ -1518,11 +1480,6 @@
         public List<Name> superArgs() {
             return List.nil();
         }
-
-        @Override
-        public List<Name> inits() {
-            return List.nil();
-        }
     }
 
     class AnonClassConstructorHelper extends BasicConstructorHelper {
@@ -1609,6 +1566,9 @@
         @Override
         public MethodSymbol constructorSymbol() {
             MethodSymbol csym = super.constructorSymbol();
+            // if we have to generate a default constructor for records we will treat it as the compact one
+            // to trigger field initialization later on
+            csym.flags_field |= Flags.COMPACT_RECORD_CONSTRUCTOR;
             ListBuffer<VarSymbol> params = new ListBuffer<>();
             for (VarSymbol p : recordFieldSymbols) {
                 params.add(new VarSymbol(MANDATED | PARAMETER | RECORD | ((p.flags_field & Flags.ORIGINALLY_VARARGS) != 0 ? Flags.VARARGS : 0), p.name, p.type, csym));
@@ -1619,11 +1579,6 @@
         }
 
         @Override
-        public List<Name> inits() {
-            return recordFieldSymbols.map(v -> v.name);
-        }
-
-        @Override
         public JCMethodDecl finalAdjustment(JCMethodDecl md) {
             List<JCVariableDecl> tmpRecordFieldDecls = recordFieldDecls;
             for (JCVariableDecl arg : md.params) {
@@ -1650,9 +1605,6 @@
             JCStatement superCall = make.Exec(make.Apply(typeargs, meth, helper.superArgs().map(make::Ident)));
             stats.add(superCall);
         }
-        helper.inits().forEach((initName) -> {
-            stats.add(make.Exec(make.Assign(make.Select(make.Ident(names._this), initName), make.Ident(initName))));
-        });
         JCMethodDecl result = make.MethodDef(initSym, make.Block(0, stats.toList()));
         return helper.finalAdjustment(result);
     }
--- a/test/langtools/tools/javac/records/RecordCompilationTests.java	Thu Sep 05 18:47:59 2019 +0000
+++ b/test/langtools/tools/javac/records/RecordCompilationTests.java	Fri Sep 06 18:01:45 2019 +0000
@@ -401,4 +401,21 @@
                    "    }\n" +
                    "}");
     }
+
+    public void testCompactDADU() {
+        // trivial cases
+        assertOK("record R() { public R {} }");
+        assertOK("record R(int x) { public R {} }");
+
+        // cases with an instance initializers
+        assertOK("record R(int x) { { this.x = 0; } }");
+        assertOK("record R(int x) { { this.x = 0; } public R {} }");
+
+        // dead code
+        assertOK("record R(int x) { { this.x = 0; } public R { if (false) { this.x = x; }} }");
+
+        // x is not DA nor DU in the body of the constructor hence error
+        assertFail("compiler.err.var.might.not.have.been.initialized", "record R(int x) { # }",
+                "public R { if (x < 0) { this.x = -x; } }");
+    }
 }