changeset 14267:6321fbe0cf50

7192245: Add parser support for default methods Summary: Add support for 'default' keyword in modifier position Reviewed-by: jjg
author mcimadamore
date Wed, 17 Oct 2012 16:43:26 +0100
parents 69453558960d
children 27d36231d705 faf9cde2817b
files langtools/src/share/classes/com/sun/tools/javac/code/Flags.java langtools/src/share/classes/com/sun/tools/javac/code/Source.java langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java langtools/src/share/classes/com/sun/tools/javac/comp/Check.java langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java langtools/test/tools/javac/defaultMethods/syntax/TestDefaultMethodsSyntax.java langtools/test/tools/javac/diags/examples/DefaultMethodNotSupported.java
diffstat 10 files changed, 391 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java	Tue Oct 16 21:03:36 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java	Wed Oct 17 16:43:26 2012 +0100
@@ -67,6 +67,7 @@
         if ((mask&NATIVE) != 0) flags.add(Flag.NATIVE);
         if ((mask&INTERFACE) != 0) flags.add(Flag.INTERFACE);
         if ((mask&ABSTRACT) != 0) flags.add(Flag.ABSTRACT);
+        if ((mask&DEFAULT) != 0) flags.add(Flag.DEFAULT);
         if ((mask&STRICTFP) != 0) flags.add(Flag.STRICTFP);
         if ((mask&BRIDGE) != 0) flags.add(Flag.BRIDGE);
         if ((mask&SYNTHETIC) != 0) flags.add(Flag.SYNTHETIC);
@@ -252,6 +253,11 @@
      */
     public static final long CLASH = 1L<<42;
 
+    /**
+     * Flag that marks either a default method or an interface containing default methods
+     */
+    public static final long DEFAULT = 1L<<43;
+
     /** Modifier masks.
      */
     public static final int
@@ -267,7 +273,10 @@
         MethodFlags           = AccessFlags | ABSTRACT | STATIC | NATIVE |
                                 SYNCHRONIZED | FINAL | STRICTFP;
     public static final long
-        LocalVarFlags         = FINAL | PARAMETER;
+        ExtendedStandardFlags       = (long)StandardFlags | DEFAULT,
+        InterfaceDefaultMethodMask  = ABSTRACT | PUBLIC | STRICTFP | SYNCHRONIZED | DEFAULT,
+        LocalVarFlags               = FINAL | PARAMETER;
+
 
     public static Set<Modifier> asModifierSet(long flags) {
         Set<Modifier> modifiers = modifierSets.get(flags);
@@ -320,6 +329,7 @@
         NATIVE("native"),
         INTERFACE("interface"),
         ABSTRACT("abstract"),
+        DEFAULT("default"),
         STRICTFP("strictfp"),
         BRIDGE("bridge"),
         SYNTHETIC("synthetic"),
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Tue Oct 16 21:03:36 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Wed Oct 17 16:43:26 2012 +0100
@@ -203,6 +203,9 @@
     public boolean allowMethodReferences() {
         return compareTo(JDK1_8) >= 0;
     }
+    public boolean allowDefaultMethods() {
+        return compareTo(JDK1_8) >= 0;
+    }
     public boolean allowEffectivelyFinalInInnerClasses() {
         return compareTo(JDK1_8) >= 0;
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Oct 16 21:03:36 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Oct 17 16:43:26 2012 +0100
@@ -873,6 +873,7 @@
 
     public void visitMethodDef(JCMethodDecl tree) {
         MethodSymbol m = tree.sym;
+        boolean isDefaultMethod = (m.flags() & DEFAULT) != 0;
 
         Lint lint = env.info.lint.augment(m.annotations, m.flags());
         Lint prevLint = chk.setLint(lint);
@@ -952,8 +953,8 @@
                 // Empty bodies are only allowed for
                 // abstract, native, or interface methods, or for methods
                 // in a retrofit signature class.
-                if ((owner.flags() & INTERFACE) == 0 &&
-                    (tree.mods.flags & (ABSTRACT | NATIVE)) == 0 &&
+                if (isDefaultMethod || ((owner.flags() & INTERFACE) == 0 &&
+                    (tree.mods.flags & (ABSTRACT | NATIVE)) == 0) &&
                     !relax)
                     log.error(tree.pos(), "missing.meth.body.or.decl.abstract");
                 if (tree.defaultValue != null) {
@@ -961,7 +962,7 @@
                         log.error(tree.pos(),
                                   "default.allowed.in.intf.annotation.member");
                 }
-            } else if ((owner.flags() & INTERFACE) != 0) {
+            } else if ((owner.flags() & INTERFACE) != 0 && !isDefaultMethod) {
                 log.error(tree.body.pos(), "intf.meth.cant.have.body");
             } else if ((tree.mods.flags & ABSTRACT) != 0) {
                 log.error(tree.pos(), "abstract.meth.cant.have.body");
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Oct 16 21:03:36 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Wed Oct 17 16:43:26 2012 +0100
@@ -1121,8 +1121,14 @@
                     mask = PRIVATE;
                 } else
                     mask = ConstructorFlags;
-            }  else if ((sym.owner.flags_field & INTERFACE) != 0)
-                mask = implicit = InterfaceMethodFlags;
+            }  else if ((sym.owner.flags_field & INTERFACE) != 0) {
+                if ((flags & DEFAULT) != 0) {
+                    mask = InterfaceDefaultMethodMask;
+                    implicit = PUBLIC;
+                } else {
+                    mask = implicit = InterfaceMethodFlags;
+                }
+            }
             else {
                 mask = MethodFlags;
             }
@@ -1169,7 +1175,7 @@
         default:
             throw new AssertionError();
         }
-        long illegal = flags & StandardFlags & ~mask;
+        long illegal = flags & ExtendedStandardFlags & ~mask;
         if (illegal != 0) {
             if ((illegal & INTERFACE) != 0) {
                 log.error(pos, "intf.not.allowed.here");
@@ -1185,7 +1191,7 @@
                   // in the presence of inner classes. Should it be deleted here?
                   checkDisjoint(pos, flags,
                                 ABSTRACT,
-                                PRIVATE | STATIC))
+                                PRIVATE | STATIC | DEFAULT))
                  &&
                  checkDisjoint(pos, flags,
                                ABSTRACT | INTERFACE,
@@ -1209,7 +1215,7 @@
                                 STRICTFP))) {
             // skip
         }
-        return flags & (mask | ~StandardFlags) | implicit;
+        return flags & (mask | ~ExtendedStandardFlags) | implicit;
     }
 
 
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Oct 16 21:03:36 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Oct 17 16:43:26 2012 +0100
@@ -116,6 +116,8 @@
                 fac.options.isSet("allowLambda"); //pre-lambda guard
         this.allowMethodReferences = source.allowMethodReferences() &&
                 fac.options.isSet("allowMethodReferences"); //pre-lambda guard
+        this.allowDefaultMethods = source.allowDefaultMethods() &&
+                fac.options.isSet("allowDefaultMethods"); //pre-lambda guard
         this.keepDocComments = keepDocComments;
         docComments = newDocCommentTable(keepDocComments);
         this.keepLineMap = keepLineMap;
@@ -185,6 +187,10 @@
      */
     boolean allowMethodReferences;
 
+    /** Switch: should we allow default methods in interfaces?
+     */
+    boolean allowDefaultMethods;
+
     /** Switch: should we keep docComments?
      */
     boolean keepDocComments;
@@ -2311,6 +2317,7 @@
             case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
             case STRICTFP    : flag = Flags.STRICTFP; break;
             case MONKEYS_AT  : flag = Flags.ANNOTATION; break;
+            case DEFAULT     : checkDefaultMethods(); flag = Flags.DEFAULT; break;
             case ERROR       : flag = 0; nextToken(); break;
             default: break loop;
             }
@@ -3361,6 +3368,12 @@
             allowMethodReferences = true;
         }
     }
+    void checkDefaultMethods() {
+        if (!allowDefaultMethods) {
+            log.error(token.pos, "default.methods.not.supported.in.source", source.name);
+            allowDefaultMethods = true;
+        }
+    }
 
     /*
      * a functional source tree and end position mappings
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Oct 16 21:03:36 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Oct 17 16:43:26 2012 +0100
@@ -2174,6 +2174,11 @@
     method references are not supported in -source {0}\n\
     (use -source 8 or higher to enable method references)
 
+# 0: string
+compiler.err.default.methods.not.supported.in.source=\
+    default methods are not supported in -source {0}\n\
+    (use -source 8 or higher to enable default methods)
+
 ########################################
 # Diagnostics for verbose resolution
 # used by Resolve (debug only)
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Tue Oct 16 21:03:36 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Wed Oct 17 16:43:26 2012 +0100
@@ -248,7 +248,7 @@
     public void printFlags(long flags) throws IOException {
         if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ ");
         print(TreeInfo.flagNames(flags));
-        if ((flags & StandardFlags) != 0) print(" ");
+        if ((flags & ExtendedStandardFlags) != 0) print(" ");
         if ((flags & ANNOTATION) != 0) print("@");
     }
 
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Tue Oct 16 21:03:36 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Oct 17 16:43:26 2012 +0100
@@ -790,8 +790,8 @@
      *  pre: flags != 0
      */
     public static long firstFlag(long flags) {
-        int flag = 1;
-        while ((flag & StandardFlags) != 0 && (flag & flags) == 0)
+        long flag = 1;
+        while ((flag & flags & ExtendedStandardFlags) == 0)
             flag = flag << 1;
         return flag;
     }
@@ -799,7 +799,7 @@
     /** Return flags as a string, separated by " ".
      */
     public static String flagNames(long flags) {
-        return Flags.toString(flags & StandardFlags).trim();
+        return Flags.toString(flags & ExtendedStandardFlags).trim();
     }
 
     /** Operator precedences values.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/defaultMethods/syntax/TestDefaultMethodsSyntax.java	Wed Oct 17 16:43:26 2012 +0100
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7192245
+ * @summary Automatic test for checking set of allowed modifiers on interface methods
+ */
+
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+
+public class TestDefaultMethodsSyntax {
+
+    static int checkCount = 0;
+
+    enum VersionKind {
+        PRE_LAMBDA("7"),
+        LAMBDA("8");
+
+        String versionString;
+
+        VersionKind(String versionString) {
+            this.versionString = versionString;
+        }
+
+        List<String> getOptions() {
+            return Arrays.asList("-XDallowDefaultMethods", "-source", versionString);
+        }
+    }
+
+    enum ModifierKind {
+        NONE(""),
+        PUBLIC("public"),
+        PROTECTED("protected"),
+        PRIVATE("private"),
+        ABSTRACT("abstract"),
+        STATIC("static"),
+        NATIVE("native"),
+        SYNCHRONIZED("synchronized"),
+        FINAL("final"),
+        STRICTFP("strictfp"),
+        DEFAULT("default");
+
+        String modStr;
+
+        private ModifierKind(String modStr) {
+            this.modStr = modStr;
+        }
+
+        boolean isAllowed(EnclosingKind ek, ModifierKind otherMod) {
+            if (this == otherMod) return false;
+            switch (this) {
+                case NONE:
+                    return true;
+                case ABSTRACT:
+                    return otherMod != PRIVATE;
+                case NATIVE:
+                    return otherMod != ABSTRACT &&
+                            otherMod != STRICTFP;
+                case FINAL:
+                case STATIC:
+                case SYNCHRONIZED:
+                case STRICTFP:
+                     return otherMod != ABSTRACT;
+                case PUBLIC:
+                    return true;
+                case PROTECTED:
+                    return ek == EnclosingKind.ABSTRACT_CLASS;
+                case DEFAULT:
+                    return otherMod != ABSTRACT;
+                default:
+                    return true;
+            }
+        }
+
+        static boolean intersect(ModifierKind mk, ModifierKind... mks) {
+            for (ModifierKind mk2 : mks) {
+                if (mk == mk2) return true;
+            }
+            return false;
+        }
+
+        static boolean compatible(MethodKind mk, ModifierKind mod1, ModifierKind mod2, EnclosingKind ek) {
+            if (intersect(ABSTRACT, mod1, mod2) || intersect(NATIVE, mod1, mod2)) {
+                return mk == MethodKind.NO_BODY;
+            } else if (intersect(DEFAULT, mod1, mod2)) {
+                return mk == MethodKind.BODY;
+            } else {
+                return ek == EnclosingKind.INTERFACE ?
+                        mk == MethodKind.NO_BODY : mk == MethodKind.BODY;
+            }
+        }
+
+        boolean compatible(EnclosingKind ek) {
+            switch (this) {
+                case STATIC:
+                case PRIVATE:
+                case PROTECTED:
+                    return ek != EnclosingKind.INTERFACE;
+                default:
+                    return true;
+            }
+        }
+
+        static boolean compatible(ModifierKind m1, ModifierKind m2, EnclosingKind ek) {
+            Result res1 = allowedModifierPairs[m1.ordinal()][m2.ordinal()];
+            Result res2 = allowedModifierPairs[m2.ordinal()][m1.ordinal()];
+            if (res1 != res2) {
+                throw new AssertionError(String.format("Ill-formed table: [%s,%s] != [%s,%s]", m1, m2, m2, m1));
+            } else {
+                return res1.compatible(ek, m1, m2);
+            }
+        }
+
+        interface Result {
+            boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2);
+        }
+
+        static final Result T = new Result() {
+            @Override
+            public boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2) {
+                return true;
+            }
+        };
+
+        static final Result F = new Result() {
+            @Override
+            public boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2) {
+                return false;
+            }
+        };
+
+        static final Result C = new Result() {
+            @Override
+            public boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2) {
+                return ek != EnclosingKind.INTERFACE;
+            }
+        };
+
+        static final Result I = new Result() {
+            @Override
+            public boolean compatible(EnclosingKind ek, ModifierKind m1, ModifierKind m2) {
+                return ek == EnclosingKind.INTERFACE;
+            }
+        };
+
+        static Result[][] allowedModifierPairs = {
+            /*                     NONE  PUBLIC  PROTECTED  PRIVATE  ABSTRACT  STATIC  NATIVE  SYNCHRONIZED  FINAL  STRICTFP  DEFAULT */
+            /* NONE */           { T   , T    , C        , C       , T       , C     , C     , C           , C    , C       , I   },
+            /* PUBLIC */         { T   , F    , F        , F       , T       , C     , C     , C           , C    , C       , I   },
+            /* PROTECTED */      { C   , F    , F        , F       , C       , C     , C     , C           , C    , C       , F   },
+            /* PRIVATE */        { C   , F    , F        , F       , F       , C     , C     , C           , C    , C       , F   },
+            /* ABSTRACT */       { T   , T    , C        , F       , F       , F     , F     , F           , F    , F       , F   },
+            /* STATIC */         { C   , C    , C        , C       , F       , F     , C     , C           , C    , C       , F   },
+            /* NATIVE */         { C   , C    , C        , C       , F       , C     , F     , C           , C    , F       , F   },
+            /* SYNCHRONIZED */   { C   , C    , C        , C       , F       , C     , C     , F           , C    , C       , I   },
+            /* FINAL */          { C   , C    , C        , C       , F       , C     , C     , C           , F    , C       , F   },
+            /* STRICTFP */       { C   , C    , C        , C       , F       , C     , F     , C           , C    , F       , I   },
+            /* DEFAULT */        { I   , I    , F        , F       , F       , F     , F     , I           , F    , I       , F   }};
+    }
+
+    enum MethodKind {
+        NO_BODY("void m();"),
+        BODY("void m() { }");
+
+        String methStr;
+
+        private MethodKind(String methStr) {
+            this.methStr = methStr;
+        }
+    }
+
+    enum EnclosingKind {
+        ABSTRACT_CLASS("abstract class Test "),
+        INTERFACE("interface Test ");
+
+        String enclStr;
+
+        EnclosingKind(String enclStr) {
+            this.enclStr = enclStr;
+        }
+    }
+
+    public static void main(String... args) throws Exception {
+
+        //create default shared JavaCompiler - reused across multiple compilations
+        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+        for (VersionKind vk : VersionKind.values()) {
+            for (EnclosingKind ek : EnclosingKind.values()) {
+                for (MethodKind mk : MethodKind.values()) {
+                    for (ModifierKind modk1 : ModifierKind.values()) {
+                        for (ModifierKind modk2 : ModifierKind.values()) {
+                            new TestDefaultMethodsSyntax(vk, ek, mk, modk1, modk2).run(comp, fm);
+                        }
+                    }
+                }
+            }
+        }
+        System.out.println("Total check executed: " + checkCount);
+    }
+
+    VersionKind vk;
+    EnclosingKind ek;
+    MethodKind mk;
+    ModifierKind modk1, modk2;
+    JavaSource source;
+    DiagnosticChecker diagChecker;
+
+    TestDefaultMethodsSyntax(VersionKind vk, EnclosingKind ek, MethodKind mk, ModifierKind modk1, ModifierKind modk2) {
+        this.vk = vk;
+        this.ek = ek;
+        this.mk = mk;
+        this.modk1 = modk1;
+        this.modk2 = modk2;
+        this.source = new JavaSource();
+        this.diagChecker = new DiagnosticChecker();
+    }
+
+    class JavaSource extends SimpleJavaFileObject {
+
+        String template = "#EK {\n" +
+                          "   #MOD1 #MOD2 #METH\n" +
+                          "}\n";
+
+        String source;
+
+        public JavaSource() {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            source = template.replaceAll("#EK", ek.enclStr)
+                    .replaceAll("#MOD1", modk1.modStr)
+                    .replaceAll("#MOD2", modk2.modStr)
+                    .replaceAll("#METH", mk.methStr);
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+
+    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
+        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
+                vk.getOptions(), null, Arrays.asList(source));
+        try {
+            ct.analyze();
+        } catch (Throwable ex) {
+            throw new AssertionError("Error thrown when analyzing the following source:\n" + source.getCharContent(true));
+        }
+        check();
+    }
+
+    void check() {
+        boolean errorExpected = !ModifierKind.compatible(modk1, modk2, ek);
+
+        errorExpected |= !ModifierKind.compatible(mk, modk1, modk2, ek);
+
+        errorExpected |= !modk1.compatible(ek) || !modk2.compatible(ek);
+
+        errorExpected |= ModifierKind.intersect(ModifierKind.DEFAULT, modk1, modk2) &&
+                vk == VersionKind.PRE_LAMBDA;
+
+        checkCount++;
+        if (diagChecker.errorFound != errorExpected) {
+            throw new AssertionError("Problem when compiling source:\n" + source.getCharContent(true) +
+                    "\nfound error: " + diagChecker.errorFound);
+        }
+    }
+
+    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+        boolean errorFound;
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+                errorFound = true;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/DefaultMethodNotSupported.java	Wed Oct 17 16:43:26 2012 +0100
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.default.methods.not.supported.in.source
+// options: -source 7 -Xlint:-options
+
+interface DefaultMethodNotSupported {
+    default void m() { }
+}