From 07e9c8cf275c9a58c686ea09bb705f672d1dd67c Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Wed, 21 Nov 2012 18:40:45 +0000 Subject: [PATCH 01/10] 7190862: javap shows an incorrect type for operands if the 'wide' prefix is used 7109747: (javap) classfile not treating iinc_w correctly Reviewed-by: jjg, mcimadamore --- .../com/sun/tools/classfile/Instruction.java | 14 +- .../com/sun/tools/classfile/Opcode.java | 26 +-- langtools/test/tools/javap/T7190862.java | 157 ++++++++++++++++++ 3 files changed, 183 insertions(+), 14 deletions(-) create mode 100644 langtools/test/tools/javap/T7190862.java diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java b/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java index aafb9861994..855cc781aa3 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java @@ -71,11 +71,16 @@ public class Instruction { SHORT(3), /** Wide opcode is not followed by any operands. */ WIDE_NO_OPERANDS(2), + /** Wide opcode is followed by a 2-byte index into the local variables array. */ + WIDE_LOCAL(4), /** Wide opcode is followed by a 2-byte index into the constant pool. */ WIDE_CPREF_W(4), /** Wide opcode is followed by a 2-byte index into the constant pool, * and a signed short value. */ WIDE_CPREF_W_SHORT(6), + /** Wide opcode is followed by a 2-byte reference to a local variable, + * and a signed short value. */ + WIDE_LOCAL_SHORT(6), /** Opcode was not recognized. */ UNKNOWN(1); @@ -101,7 +106,7 @@ public class Instruction { R visitConstantPoolRef(Instruction instr, int index, P p); /** See {@link Kind#CPREF_W_UBYTE}, {@link Kind#CPREF_W_UBYTE_ZERO}, {@link Kind#WIDE_CPREF_W_SHORT}. */ R visitConstantPoolRefAndValue(Instruction instr, int index, int value, P p); - /** See {@link Kind#LOCAL}. */ + /** See {@link Kind#LOCAL}, {@link Kind#WIDE_LOCAL}. */ R visitLocal(Instruction instr, int index, P p); /** See {@link Kind#LOCAL_BYTE}. */ R visitLocalAndValue(Instruction instr, int index, int value, P p); @@ -315,6 +320,9 @@ public class Instruction { case WIDE_NO_OPERANDS: return visitor.visitNoOperands(this, p); + case WIDE_LOCAL: + return visitor.visitLocal(this, getUnsignedShort(2), p); + case WIDE_CPREF_W: return visitor.visitConstantPoolRef(this, getUnsignedShort(2), p); @@ -322,6 +330,10 @@ public class Instruction { return visitor.visitConstantPoolRefAndValue( this, getUnsignedShort(2), getUnsignedByte(4), p); + case WIDE_LOCAL_SHORT: + return visitor.visitLocalAndValue( + this, getUnsignedShort(2), getShort(4), p); + case UNKNOWN: return visitor.visitUnknown(this, p); diff --git a/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java b/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java index 9f27645093e..7ecf4979228 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -246,18 +246,18 @@ public enum Opcode { // impdep 0xff: Picojava priv // wide opcodes - ILOAD_W(0xc415, WIDE_CPREF_W), - LLOAD_W(0xc416, WIDE_CPREF_W), - FLOAD_W(0xc417, WIDE_CPREF_W), - DLOAD_W(0xc418, WIDE_CPREF_W), - ALOAD_W(0xc419, WIDE_CPREF_W), - ISTORE_W(0xc436, WIDE_CPREF_W), - LSTORE_W(0xc437, WIDE_CPREF_W), - FSTORE_W(0xc438, WIDE_CPREF_W), - DSTORE_W(0xc439, WIDE_CPREF_W), - ASTORE_W(0xc43a, WIDE_CPREF_W), - IINC_W(0xc484, WIDE_CPREF_W_SHORT), - RET_W(0xc4a9, WIDE_CPREF_W), + ILOAD_W(0xc415, WIDE_LOCAL), + LLOAD_W(0xc416, WIDE_LOCAL), + FLOAD_W(0xc417, WIDE_LOCAL), + DLOAD_W(0xc418, WIDE_LOCAL), + ALOAD_W(0xc419, WIDE_LOCAL), + ISTORE_W(0xc436, WIDE_LOCAL), + LSTORE_W(0xc437, WIDE_LOCAL), + FSTORE_W(0xc438, WIDE_LOCAL), + DSTORE_W(0xc439, WIDE_LOCAL), + ASTORE_W(0xc43a, WIDE_LOCAL), + IINC_W(0xc484, WIDE_LOCAL_SHORT), + RET_W(0xc4a9, WIDE_LOCAL), // PicoJava nonpriv instructions LOAD_UBYTE(PICOJAVA, 0xfe00), diff --git a/langtools/test/tools/javap/T7190862.java b/langtools/test/tools/javap/T7190862.java new file mode 100644 index 00000000000..b7b57daa2f7 --- /dev/null +++ b/langtools/test/tools/javap/T7190862.java @@ -0,0 +1,157 @@ + +/* + * @test /nodynamiccopyright/ + * @bug 7190862 7109747 + * @summary javap shows an incorrect type for operands if the 'wide' prefix is used + */ + +import com.sun.source.util.JavacTask; +import com.sun.tools.javap.JavapFileManager; +import com.sun.tools.javap.JavapTask; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +public class T7190862 { + + enum TypeWideInstructionMap { + INT("int", new String[]{"istore_w", "iload_w"}), + LONG("long", new String[]{"lstore_w", "lload_w"}), + FLOAT("float", new String[]{"fstore_w", "fload_w"}), + DOUBLE("double", new String[]{"dstore_w", "dload_w"}), + OBJECT("Object", new String[]{"astore_w", "aload_w"}); + + String type; + String[] instructions; + + TypeWideInstructionMap(String type, String[] instructions) { + this.type = type; + this.instructions = instructions; + } + } + + JavaSource source; + + public static void main(String[] args) { + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + new T7190862().run(comp); + } + + private void run(JavaCompiler comp) { + String code; + for (TypeWideInstructionMap typeInstructionMap: TypeWideInstructionMap.values()) { + if (typeInstructionMap != TypeWideInstructionMap.OBJECT) { + code = createWideLocalSource(typeInstructionMap.type, 300); + } else { + code = createWideLocalSourceForObject(300); + } + source = new JavaSource(code); + compile(comp); + check(typeInstructionMap.instructions); + } + + //an extra test for the iinc instruction + code = createIincSource(); + source = new JavaSource(code); + compile(comp); + check(new String[]{"iinc_w"}); + } + + private void compile(JavaCompiler comp) { + JavacTask ct = (JavacTask)comp.getTask(null, null, null, null, null, Arrays.asList(source)); + try { + if (!ct.call()) { + throw new AssertionError("Error thrown when compiling the following source:\n" + source.getCharContent(true)); + } + } catch (Throwable ex) { + throw new AssertionError("Error thrown when compiling the following source:\n" + source.getCharContent(true)); + } + } + + private void check(String[] instructions) { + String out = javap(Arrays.asList("-c"), Arrays.asList("Test.class")); + for (String line: out.split(System.getProperty("line.separator"))) { + line = line.trim(); + for (String instruction: instructions) { + if (line.contains(instruction) && line.contains("#")) { + throw new Error("incorrect type for operands for instruction " + instruction); + } + } + } + } + + private String javap(List args, List classes) { + DiagnosticCollector dc = new DiagnosticCollector(); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + JavaFileManager fm = JavapFileManager.create(dc, pw); + JavapTask t = new JavapTask(pw, fm, dc, args, classes); + boolean ok = t.run(); + if (!ok) + throw new Error("javap failed unexpectedly"); + + List> diags = dc.getDiagnostics(); + for (Diagnostic d: diags) { + if (d.getKind() == Diagnostic.Kind.ERROR) + throw new Error(d.getMessage(Locale.ENGLISH)); + } + return sw.toString(); + + } + + private String createWideLocalSource(String type, int numberOfVars) { + String result = " " + type + " x0 = 0;\n"; + for (int i = 1; i < numberOfVars; i++) { + result += " " + type + " x" + i + " = x" + (i - 1) + " + 1;\n"; + } + return result; + } + + private String createWideLocalSourceForObject(int numberOfVars) { + String result = " Object x0 = new Object();\n"; + for (int i = 1; i < numberOfVars; i++) { + result += " Object x" + i + " = x0;\n"; + } + return result; + } + + private String createIincSource() { + return " int i = 0;\n" + + " i += 1;\n" + + " i += 51;\n" + + " i += 101;\n" + + " i += 151;\n"; + } + + class JavaSource extends SimpleJavaFileObject { + + String template = "class Test {\n" + + " public static void main(String[] args)\n" + + " {\n" + + " #C" + + " }\n" + + "}"; + + String source; + + public JavaSource(String code) { + super(URI.create("Test.java"), JavaFileObject.Kind.SOURCE); + source = template.replaceAll("#C", code); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } +} From 1d4cbc27ff4d531b023f33c50fe9214eac9fa45b Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Wed, 21 Nov 2012 19:09:39 +0000 Subject: [PATCH 02/10] 6574624: javax.tools.JavaCompiler spec contains errors in sample code Reviewed-by: jjg, mcimadamore --- langtools/src/share/classes/javax/tools/JavaCompiler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/langtools/src/share/classes/javax/tools/JavaCompiler.java b/langtools/src/share/classes/javax/tools/JavaCompiler.java index 36d86cfe8f3..5588c80d428 100644 --- a/langtools/src/share/classes/javax/tools/JavaCompiler.java +++ b/langtools/src/share/classes/javax/tools/JavaCompiler.java @@ -108,8 +108,8 @@ import javax.annotation.processing.Processor; * example a recommended coding pattern: * *
- *       Files[] files1 = ... ; // input for first compilation task
- *       Files[] files2 = ... ; // input for second compilation task
+ *       File[] files1 = ... ; // input for first compilation task
+ *       File[] files2 = ... ; // input for second compilation task
  *
  *       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
  *       StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
@@ -165,7 +165,7 @@ import javax.annotation.processing.Processor;
  *       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
  *       StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, null, null);
  *       JavaFileManager fileManager = new ForwardingJavaFileManager(stdFileManager) {
- *           public void flush() {
+ *           public void flush() throws IOException {
  *               logger.entering(StandardJavaFileManager.class.getName(), "flush");
  *               super.flush();
  *               logger.exiting(StandardJavaFileManager.class.getName(), "flush");

From 7fb8379371e72df7829b3379bf9b5e40b9e08a24 Mon Sep 17 00:00:00 2001
From: Eric Caspole 
Date: Tue, 27 Nov 2012 13:55:10 -0800
Subject: [PATCH 03/10] 8004068: Fix build problems caused by on-demand imports

Reviewed-by: jjg
---
 .../src/share/classes/com/sun/tools/javac/code/Types.java | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
index 22063dcbf16..1b91e85f74f 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
@@ -26,7 +26,13 @@
 package com.sun.tools.javac.code;
 
 import java.lang.ref.SoftReference;
-import java.util.*;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
 
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 import com.sun.tools.javac.code.Lint.LintCategory;

From 9bbd89281829c3fd293f71914a207b199aaa69fc Mon Sep 17 00:00:00 2001
From: Vicente Romero 
Date: Fri, 23 Nov 2012 15:13:45 +0000
Subject: [PATCH 04/10] 7144981: javac should ignore ignorable characters in
 input

Reviewed-by: jjg, mcimadamore
---
 .../sun/tools/javac/parser/JavaTokenizer.java | 27 ++++--
 .../IgnoreIgnorableCharactersInInput.java     | 92 +++++++++++++++++++
 2 files changed, 110 insertions(+), 9 deletions(-)
 create mode 100644 langtools/test/tools/javac/7144981/IgnoreIgnorableCharactersInInput.java

diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
index 2048c1cd48a..20d3f4b93cd 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
@@ -348,8 +348,8 @@ public class JavaTokenizer {
     private void scanIdent() {
         boolean isJavaIdentifierPart;
         char high;
+        reader.putChar(true);
         do {
-            reader.putChar(true);
             switch (reader.ch) {
             case 'A': case 'B': case 'C': case 'D': case 'E':
             case 'F': case 'G': case 'H': case 'I': case 'J':
@@ -366,6 +366,7 @@ public class JavaTokenizer {
             case '$': case '_':
             case '0': case '1': case '2': case '3': case '4':
             case '5': case '6': case '7': case '8': case '9':
+                break;
             case '\u0000': case '\u0001': case '\u0002': case '\u0003':
             case '\u0004': case '\u0005': case '\u0006': case '\u0007':
             case '\u0008': case '\u000E': case '\u000F': case '\u0010':
@@ -373,26 +374,33 @@ public class JavaTokenizer {
             case '\u0015': case '\u0016': case '\u0017':
             case '\u0018': case '\u0019': case '\u001B':
             case '\u007F':
-                break;
+                reader.scanChar();
+                continue;
             case '\u001A': // EOI is also a legal identifier part
                 if (reader.bp >= reader.buflen) {
                     name = reader.name();
                     tk = tokens.lookupKind(name);
                     return;
                 }
-                break;
+                reader.scanChar();
+                continue;
             default:
                 if (reader.ch < '\u0080') {
                     // all ASCII range chars already handled, above
                     isJavaIdentifierPart = false;
                 } else {
-                    high = reader.scanSurrogates();
-                    if (high != 0) {
-                        reader.putChar(high);
-                        isJavaIdentifierPart = Character.isJavaIdentifierPart(
-                            Character.toCodePoint(high, reader.ch));
+                    if (Character.isIdentifierIgnorable(reader.ch)) {
+                        reader.scanChar();
+                        continue;
                     } else {
-                        isJavaIdentifierPart = Character.isJavaIdentifierPart(reader.ch);
+                        high = reader.scanSurrogates();
+                        if (high != 0) {
+                            reader.putChar(high);
+                            isJavaIdentifierPart = Character.isJavaIdentifierPart(
+                                Character.toCodePoint(high, reader.ch));
+                        } else {
+                            isJavaIdentifierPart = Character.isJavaIdentifierPart(reader.ch);
+                        }
                     }
                 }
                 if (!isJavaIdentifierPart) {
@@ -401,6 +409,7 @@ public class JavaTokenizer {
                     return;
                 }
             }
+            reader.putChar(true);
         } while (true);
     }
 
diff --git a/langtools/test/tools/javac/7144981/IgnoreIgnorableCharactersInInput.java b/langtools/test/tools/javac/7144981/IgnoreIgnorableCharactersInInput.java
new file mode 100644
index 00000000000..95bce2a3716
--- /dev/null
+++ b/langtools/test/tools/javac/7144981/IgnoreIgnorableCharactersInInput.java
@@ -0,0 +1,92 @@
+
+/*
+ * @test  /nodynamiccopyright/
+ * @bug 7144981
+ * @summary javac should ignore ignorable characters in input
+ * @run main IgnoreIgnorableCharactersInInput
+ */
+
+import com.sun.source.util.JavacTask;
+import java.io.File;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public class IgnoreIgnorableCharactersInInput {
+
+    public static void main(String... args) throws Exception {
+        new IgnoreIgnorableCharactersInInput().run();
+    }
+
+    void run() throws Exception {
+        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        File classesDir = new File(System.getProperty("user.dir"), "classes");
+        classesDir.mkdirs();
+        JavaSource[] sources = new JavaSource[]{
+            new JavaSource("TestOneIgnorableChar", "AA\\u0000BB"),
+            new JavaSource("TestMultipleIgnorableChar", "AA\\u0000\\u0000\\u0000BB")};
+        JavacTask ct = (JavacTask)comp.getTask(null, null, null,
+                Arrays.asList("-d", classesDir.getPath()),
+                null, Arrays.asList(sources));
+        try {
+            if (!ct.call()) {
+                throw new AssertionError("Error thrown when compiling test cases");
+            }
+        } catch (Throwable ex) {
+            throw new AssertionError("Error thrown when compiling test cases");
+        }
+        check(classesDir,
+                "TestOneIgnorableChar.class",
+                "TestOneIgnorableChar$AABB.class",
+                "TestMultipleIgnorableChar.class",
+                "TestMultipleIgnorableChar$AABB.class");
+        if (errors > 0)
+            throw new AssertionError("There are some errors in the test check the error output");
+    }
+
+    /**
+     *  Check that a directory contains the expected files.
+     */
+    void check(File dir, String... paths) {
+        Set found = new TreeSet(Arrays.asList(dir.list()));
+        Set expect = new TreeSet(Arrays.asList(paths));
+        if (found.equals(expect))
+            return;
+        for (String f: found) {
+            if (!expect.contains(f))
+                error("Unexpected file found: " + f);
+        }
+        for (String e: expect) {
+            if (!found.contains(e))
+                error("Expected file not found: " + e);
+        }
+    }
+
+    int errors;
+
+    void error(String msg) {
+        System.err.println(msg);
+        errors++;
+    }
+
+    class JavaSource extends SimpleJavaFileObject {
+
+        String internalSource =
+            "public class #O {public class #I {} }";
+        public JavaSource(String outerClassName, String innerClassName) {
+            super(URI.create(outerClassName + ".java"), JavaFileObject.Kind.SOURCE);
+            internalSource =
+                    internalSource.replace("#O", outerClassName).replace("#I", innerClassName);
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return internalSource;
+        }
+    }
+}

From ba3ae37ef0e41c18ac13ac6d20a109bf9073a61c Mon Sep 17 00:00:00 2001
From: Vicente Romero 
Date: Thu, 29 Nov 2012 09:41:48 +0000
Subject: [PATCH 05/10] 7153958: add constant pool reference to class
 containing inlined constants

Reviewed-by: jjg, mcimadamore
---
 .../com/sun/tools/javac/comp/Lower.java       |  36 +++--
 .../classes/com/sun/tools/javac/jvm/Gen.java  |  69 +++++++++
 .../CPoolRefClassContainingInlinedCts.java    | 134 ++++++++++++++++++
 .../pkg/ClassToBeStaticallyImported.java      |  29 ++++
 4 files changed, 259 insertions(+), 9 deletions(-)
 create mode 100644 langtools/test/tools/javac/7153958/CPoolRefClassContainingInlinedCts.java
 create mode 100644 langtools/test/tools/javac/7153958/pkg/ClassToBeStaticallyImported.java

diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
index 828e7fbbe1f..4005a25887a 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
@@ -138,6 +138,10 @@ public class Lower extends TreeTranslator {
      */
     Map classdefs;
 
+    /** A hash table mapping local classes to a list of pruned trees.
+     */
+    public Map> prunedTree = new WeakHashMap>();
+
     /** A hash table mapping virtual accessed symbols in outer subclasses
      *  to the actually referred symbol in superclasses.
      */
@@ -1039,6 +1043,12 @@ public class Lower extends TreeTranslator {
         }
     }
 
+    private void addPrunedInfo(JCTree tree) {
+        List infoList = prunedTree.get(currentClass);
+        infoList = (infoList == null) ? List.of(tree) : infoList.prepend(tree);
+        prunedTree.put(currentClass, infoList);
+    }
+
     /** Ensure that identifier is accessible, return tree accessing the identifier.
      *  @param sym      The accessed symbol.
      *  @param tree     The tree referring to the symbol.
@@ -1111,7 +1121,10 @@ public class Lower extends TreeTranslator {
                     // Constants are replaced by their constant value.
                     if (sym.kind == VAR) {
                         Object cv = ((VarSymbol)sym).getConstValue();
-                        if (cv != null) return makeLit(sym.type, cv);
+                        if (cv != null) {
+                            addPrunedInfo(tree);
+                            return makeLit(sym.type, cv);
+                        }
                     }
 
                     // Private variables and methods are replaced by calls
@@ -2746,12 +2759,15 @@ public class Lower extends TreeTranslator {
 
     /** Visitor method for conditional expressions.
      */
+    @Override
     public void visitConditional(JCConditional tree) {
         JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
         if (cond.type.isTrue()) {
             result = convert(translate(tree.truepart, tree.type), tree.type);
+            addPrunedInfo(cond);
         } else if (cond.type.isFalse()) {
             result = convert(translate(tree.falsepart, tree.type), tree.type);
+            addPrunedInfo(cond);
         } else {
             // Condition is not a compile-time constant.
             tree.truepart = translate(tree.truepart, tree.type);
@@ -2760,14 +2776,14 @@ public class Lower extends TreeTranslator {
         }
     }
 //where
-        private JCTree convert(JCTree tree, Type pt) {
-            if (tree.type == pt || tree.type.hasTag(BOT))
-                return tree;
-            JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
-            result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
-                                                           : pt;
-            return result;
-        }
+    private JCTree convert(JCTree tree, Type pt) {
+        if (tree.type == pt || tree.type.hasTag(BOT))
+            return tree;
+        JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
+        result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
+                                                       : pt;
+        return result;
+    }
 
     /** Visitor method for if statements.
      */
@@ -2775,12 +2791,14 @@ public class Lower extends TreeTranslator {
         JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
         if (cond.type.isTrue()) {
             result = translate(tree.thenpart);
+            addPrunedInfo(cond);
         } else if (cond.type.isFalse()) {
             if (tree.elsepart != null) {
                 result = translate(tree.elsepart);
             } else {
                 result = make.Skip();
             }
+            addPrunedInfo(cond);
         } else {
             // Condition is not a compile-time constant.
             tree.thenpart = translate(tree.thenpart);
diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java
index 4bbab1eb709..d54208b5723 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java
@@ -71,6 +71,7 @@ public class Gen extends JCTree.Visitor {
     private final Map stringBufferAppend;
     private Name accessDollar;
     private final Types types;
+    private final Lower lower;
 
     /** Switch: GJ mode?
      */
@@ -112,6 +113,7 @@ public class Gen extends JCTree.Visitor {
         stringBufferAppend = new HashMap();
         accessDollar = names.
             fromString("access" + target.syntheticNameChar());
+        lower = Lower.instance(context);
 
         Options options = Options.instance(context);
         lineDebugInfo =
@@ -816,6 +818,62 @@ public class Gen extends JCTree.Visitor {
         }
     }
 
+    /** Visitor class for expressions which might be constant expressions.
+     *  This class is a subset of TreeScanner. Intended to visit trees pruned by
+     *  Lower as long as constant expressions looking for references to any
+     *  ClassSymbol. Any such reference will be added to the constant pool so
+     *  automated tools can detect class dependencies better.
+     */
+    class ClassReferenceVisitor extends JCTree.Visitor {
+
+        @Override
+        public void visitTree(JCTree tree) {}
+
+        @Override
+        public void visitBinary(JCBinary tree) {
+            tree.lhs.accept(this);
+            tree.rhs.accept(this);
+        }
+
+        @Override
+        public void visitSelect(JCFieldAccess tree) {
+            if (tree.selected.type.hasTag(CLASS)) {
+                makeRef(tree.selected.pos(), tree.selected.type);
+            }
+        }
+
+        @Override
+        public void visitIdent(JCIdent tree) {
+            if (tree.sym.owner instanceof ClassSymbol) {
+                pool.put(tree.sym.owner);
+            }
+        }
+
+        @Override
+        public void visitConditional(JCConditional tree) {
+            tree.cond.accept(this);
+            tree.truepart.accept(this);
+            tree.falsepart.accept(this);
+        }
+
+        @Override
+        public void visitUnary(JCUnary tree) {
+            tree.arg.accept(this);
+        }
+
+        @Override
+        public void visitParens(JCParens tree) {
+            tree.expr.accept(this);
+        }
+
+        @Override
+        public void visitTypeCast(JCTypeCast tree) {
+            tree.expr.accept(this);
+        }
+    }
+
+    private ClassReferenceVisitor classReferenceVisitor = new ClassReferenceVisitor();
+
     /** Visitor method: generate code for an expression, catching and reporting
      *  any completion failures.
      *  @param tree    The expression to be visited.
@@ -826,6 +884,7 @@ public class Gen extends JCTree.Visitor {
         try {
             if (tree.type.constValue() != null) {
                 // Short circuit any expressions which are constants
+                tree.accept(classReferenceVisitor);
                 checkStringConstant(tree.pos(), tree.type.constValue());
                 result = items.makeImmediateItem(tree.type, tree.type.constValue());
             } else {
@@ -2205,6 +2264,15 @@ public class Gen extends JCTree.Visitor {
         code.endScopes(limit);
     }
 
+    private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) {
+        List prunedInfo = lower.prunedTree.get(classSymbol);
+        if (prunedInfo != null) {
+            for (JCTree prunedTree: prunedInfo) {
+                prunedTree.accept(classReferenceVisitor);
+            }
+        }
+    }
+
 /* ************************************************************************
  * main method
  *************************************************************************/
@@ -2232,6 +2300,7 @@ public class Gen extends JCTree.Visitor {
             cdef.defs = normalizeDefs(cdef.defs, c);
             c.pool = pool;
             pool.reset();
+            generateReferencesToPrunedTree(c, pool);
             Env localEnv =
                 new Env(cdef, new GenContext());
             localEnv.toplevel = env.toplevel;
diff --git a/langtools/test/tools/javac/7153958/CPoolRefClassContainingInlinedCts.java b/langtools/test/tools/javac/7153958/CPoolRefClassContainingInlinedCts.java
new file mode 100644
index 00000000000..e518df8d3fc
--- /dev/null
+++ b/langtools/test/tools/javac/7153958/CPoolRefClassContainingInlinedCts.java
@@ -0,0 +1,134 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 7153958
+ * @summary add constant pool reference to class containing inlined constants
+ * @compile pkg/ClassToBeStaticallyImported.java
+ * @run main CPoolRefClassContainingInlinedCts
+ */
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
+import com.sun.tools.classfile.ConstantPool.CPInfo;
+import com.sun.tools.classfile.ConstantPoolException;
+import java.io.File;
+import java.io.IOException;
+
+import static pkg.ClassToBeStaticallyImported.staticField;
+
+public class CPoolRefClassContainingInlinedCts {
+
+    public static void main(String args[]) throws Exception {
+        new CPoolRefClassContainingInlinedCts().run();
+    }
+
+    void run() throws Exception {
+        checkReferences();
+    }
+
+    int numberOfReferencedClassesToBeChecked = 0;
+
+    void checkClassName(String className) {
+        switch (className) {
+            case "SimpleAssignClass" : case "BinaryExpClass":
+            case "UnaryExpClass" : case "CastClass":
+            case "ParensClass" : case "CondClass":
+            case "IfClass" : case "pkg/ClassToBeStaticallyImported":
+                numberOfReferencedClassesToBeChecked++;
+        }
+    }
+
+    void checkReferences() throws IOException, ConstantPoolException {
+        File testClasses = new File(System.getProperty("test.classes"));
+        File file = new File(testClasses,
+                CPoolRefClassContainingInlinedCts.class.getName() + ".class");
+        ClassFile classFile = ClassFile.read(file);
+        int i = 1;
+        CPInfo cpInfo;
+        while (i < classFile.constant_pool.size()) {
+            cpInfo = classFile.constant_pool.get(i);
+            if (cpInfo instanceof CONSTANT_Class_info) {
+                checkClassName(((CONSTANT_Class_info)cpInfo).getName());
+            }
+            i += cpInfo.size();
+        }
+        if (numberOfReferencedClassesToBeChecked != 8) {
+            throw new AssertionError("Class reference missing in the constant pool");
+        }
+    }
+
+    private int assign = SimpleAssignClass.x;
+    private int binary = BinaryExpClass.x + 1;
+    private int unary = -UnaryExpClass.x;
+    private int cast = (int)CastClass.x;
+    private int parens = (ParensClass.x);
+    private int cond = (CondClass.x == 1) ? 1 : 2;
+    private static int ifConstant;
+    private static int importStatic;
+    static {
+        if (IfClass.x == 1) {
+            ifConstant = 1;
+        } else {
+            ifConstant = 2;
+        }
+    }
+    static {
+        if (staticField == 1) {
+            importStatic = 1;
+        } else {
+            importStatic = 2;
+        }
+    }
+}
+
+class SimpleAssignClass {
+    public static final int x = 1;
+}
+
+class BinaryExpClass {
+    public static final int x = 1;
+}
+
+class UnaryExpClass {
+    public static final int x = 1;
+}
+
+class CastClass {
+    public static final int x = 1;
+}
+
+class ParensClass {
+    public static final int x = 1;
+}
+
+class CondClass {
+    public static final int x = 1;
+}
+
+class IfClass {
+    public static final int x = 1;
+}
diff --git a/langtools/test/tools/javac/7153958/pkg/ClassToBeStaticallyImported.java b/langtools/test/tools/javac/7153958/pkg/ClassToBeStaticallyImported.java
new file mode 100644
index 00000000000..801098d0293
--- /dev/null
+++ b/langtools/test/tools/javac/7153958/pkg/ClassToBeStaticallyImported.java
@@ -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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package pkg;
+
+public class ClassToBeStaticallyImported {
+    public static final int staticField = 1;
+}

From 684271da34466a81e56ffb18574de21c725c2694 Mon Sep 17 00:00:00 2001
From: Maurizio Cimadamore 
Date: Fri, 30 Nov 2012 15:14:12 +0000
Subject: [PATCH 06/10] 8004105: Expression statement lambdas should be
 void-compatible

Fix lambda compatibility rules as per latest EDR

Reviewed-by: jjg
---
 .../com/sun/tools/javac/comp/Attr.java        | 30 ++++++++++++++++---
 .../sun/tools/javac/parser/JavacParser.java   | 15 ++--------
 .../com/sun/tools/javac/tree/TreeInfo.java    | 19 ++++++++++++
 .../test/tools/javac/lambda/LambdaConv21.java |  2 +-
 .../test/tools/javac/lambda/LambdaConv21.out  |  3 +-
 .../tools/javac/lambda/VoidCompatibility.out  |  3 +-
 6 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
index 0d743da7be4..d7791f5a1d9 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -2244,9 +2244,13 @@ public class Attr extends JCTree.Visitor {
             //with the target-type, it will be recovered anyway in Attr.checkId
             needsRecovery = false;
 
+            FunctionalReturnContext funcContext = that.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
+                    new ExpressionLambdaReturnContext((JCExpression)that.getBody(), resultInfo.checkContext) :
+                    new FunctionalReturnContext(resultInfo.checkContext);
+
             ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ?
                 recoveryInfo :
-                new ResultInfo(VAL, lambdaType.getReturnType(), new LambdaReturnContext(resultInfo.checkContext));
+                new ResultInfo(VAL, lambdaType.getReturnType(), funcContext);
             localEnv.info.returnResult = bodyResultInfo;
 
             if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
@@ -2327,8 +2331,9 @@ public class Attr extends JCTree.Visitor {
          * type according to both the inherited context and the assignment
          * context.
          */
-        class LambdaReturnContext extends Check.NestedCheckContext {
-            public LambdaReturnContext(CheckContext enclosingContext) {
+        class FunctionalReturnContext extends Check.NestedCheckContext {
+
+            FunctionalReturnContext(CheckContext enclosingContext) {
                 super(enclosingContext);
             }
 
@@ -2344,6 +2349,23 @@ public class Attr extends JCTree.Visitor {
             }
         }
 
+        class ExpressionLambdaReturnContext extends FunctionalReturnContext {
+
+            JCExpression expr;
+
+            ExpressionLambdaReturnContext(JCExpression expr, CheckContext enclosingContext) {
+                super(enclosingContext);
+                this.expr = expr;
+            }
+
+            @Override
+            public boolean compatible(Type found, Type req, Warner warn) {
+                //a void return is compatible with an expression statement lambda
+                return TreeInfo.isExpressionStatement(expr) && req.hasTag(VOID) ||
+                        super.compatible(found, req, warn);
+            }
+        }
+
         /**
         * Lambda compatibility. Check that given return types, thrown types, parameter types
         * are compatible with the expected functional interface descriptor. This means that:
@@ -2560,7 +2582,7 @@ public class Attr extends JCTree.Visitor {
 
         if (!returnType.hasTag(VOID) && !resType.hasTag(VOID)) {
             if (resType.isErroneous() ||
-                    new LambdaReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) {
+                    new FunctionalReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) {
                 incompatibleReturnType = null;
             }
         }
diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
index 35fa62915bb..24e439e6694 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
@@ -3171,21 +3171,12 @@ public class JavacParser implements Parser {
     /** Check that given tree is a legal expression statement.
      */
     protected JCExpression checkExprStat(JCExpression t) {
-        switch(t.getTag()) {
-        case PREINC: case PREDEC:
-        case POSTINC: case POSTDEC:
-        case ASSIGN:
-        case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
-        case SL_ASG: case SR_ASG: case USR_ASG:
-        case PLUS_ASG: case MINUS_ASG:
-        case MUL_ASG: case DIV_ASG: case MOD_ASG:
-        case APPLY: case NEWCLASS:
-        case ERRONEOUS:
-            return t;
-        default:
+        if (!TreeInfo.isExpressionStatement(t)) {
             JCExpression ret = F.at(t.pos).Erroneous(List.of(t));
             error(ret, "not.stmt");
             return ret;
+        } else {
+            return t;
         }
     }
 
diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java
index a68c719a7dc..9b1c85227d9 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java
@@ -267,6 +267,25 @@ public class TreeInfo {
         return lambda.params.isEmpty() ||
                 lambda.params.head.vartype != null;
     }
+
+    /** Return true if the tree corresponds to an expression statement */
+    public static boolean isExpressionStatement(JCExpression tree) {
+        switch(tree.getTag()) {
+            case PREINC: case PREDEC:
+            case POSTINC: case POSTDEC:
+            case ASSIGN:
+            case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
+            case SL_ASG: case SR_ASG: case USR_ASG:
+            case PLUS_ASG: case MINUS_ASG:
+            case MUL_ASG: case DIV_ASG: case MOD_ASG:
+            case APPLY: case NEWCLASS:
+            case ERRONEOUS:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     /**
      * Return true if the AST corresponds to a static select of the kind A.B
      */
diff --git a/langtools/test/tools/javac/lambda/LambdaConv21.java b/langtools/test/tools/javac/lambda/LambdaConv21.java
index ecc45931588..d4ac403cbbb 100644
--- a/langtools/test/tools/javac/lambda/LambdaConv21.java
+++ b/langtools/test/tools/javac/lambda/LambdaConv21.java
@@ -23,7 +23,7 @@ class LambdaConv21 {
     static void testExpressionLambda() {
         SAM_void s1 = ()->m_void(); //ok
         SAM_java_lang_Void s2 = ()->m_void(); //no - incompatible target
-        SAM_void s3 = ()->m_java_lang_Void(); //no - incompatible target
+        SAM_void s3 = ()->m_java_lang_Void(); //ok - expression statement lambda is compatible with void
         SAM_java_lang_Void s4 = ()->m_java_lang_Void(); //ok
     }
 
diff --git a/langtools/test/tools/javac/lambda/LambdaConv21.out b/langtools/test/tools/javac/lambda/LambdaConv21.out
index 1ddf803701b..9976d9c7438 100644
--- a/langtools/test/tools/javac/lambda/LambdaConv21.out
+++ b/langtools/test/tools/javac/lambda/LambdaConv21.out
@@ -1,6 +1,5 @@
 LambdaConv21.java:25:43: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: void, java.lang.Void))
-LambdaConv21.java:26:43: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Void, void))
 LambdaConv21.java:32:33: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val: java.lang.Void))
 LambdaConv21.java:33:53: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val))
 LambdaConv21.java:36:33: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val: java.lang.Void))
-5 errors
+4 errors
diff --git a/langtools/test/tools/javac/lambda/VoidCompatibility.out b/langtools/test/tools/javac/lambda/VoidCompatibility.out
index 7686554c58e..0d3a8e809b9 100644
--- a/langtools/test/tools/javac/lambda/VoidCompatibility.out
+++ b/langtools/test/tools/javac/lambda/VoidCompatibility.out
@@ -1,2 +1,3 @@
+VoidCompatibility.java:17:9: compiler.err.ref.ambiguous: schedule, kindname.method, schedule(VoidCompatibility.Runnable), VoidCompatibility, kindname.method, schedule(VoidCompatibility.Thunk), VoidCompatibility
 VoidCompatibility.java:23:9: compiler.err.ref.ambiguous: schedule, kindname.method, schedule(VoidCompatibility.Runnable), VoidCompatibility, kindname.method, schedule(VoidCompatibility.Thunk), VoidCompatibility
-1 error
+2 errors

From 0db60b7bb2840c0c77416af7df6fe068223d6f16 Mon Sep 17 00:00:00 2001
From: Maurizio Cimadamore 
Date: Fri, 30 Nov 2012 15:14:25 +0000
Subject: [PATCH 07/10] 8004102: Add support for generic functional descriptors

Method references are allowed to have a generic functional interface descriptor target

Reviewed-by: jjg
---
 .../com/sun/tools/javac/code/Types.java       | 17 +---
 .../com/sun/tools/javac/comp/Attr.java        |  8 ++
 .../tools/javac/resources/compiler.properties |  5 +-
 ...e.java => InvalidGenericLambdaTarget.java} |  4 +-
 ...=> FunctionalInterfaceConversionTest.java} | 84 +++++++++++++------
 .../tools/javac/lambda/MethodReference57.java | 41 +++++++++
 .../tools/javac/lambda/MethodReference58.java | 46 ++++++++++
 .../tools/javac/lambda/MethodReference58.out  |  2 +
 8 files changed, 162 insertions(+), 45 deletions(-)
 rename langtools/test/tools/javac/diags/examples/{InvalidGenericDescInFunctionalInterface.java => InvalidGenericLambdaTarget.java} (91%)
 rename langtools/test/tools/javac/lambda/{LambdaConversionTest.java => FunctionalInterfaceConversionTest.java} (68%)
 create mode 100644 langtools/test/tools/javac/lambda/MethodReference57.java
 create mode 100644 langtools/test/tools/javac/lambda/MethodReference58.java
 create mode 100644 langtools/test/tools/javac/lambda/MethodReference58.out

diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
index 1b91e85f74f..b591063199d 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
@@ -437,23 +437,8 @@ public class Types {
                 throw failure("not.a.functional.intf.1",
                             diags.fragment("no.abstracts", Kinds.kindName(origin), origin));
             } else if (abstracts.size() == 1) {
-                if (abstracts.first().type.tag == FORALL) {
-                    throw failure("invalid.generic.desc.in.functional.intf",
-                            abstracts.first(),
-                            Kinds.kindName(origin),
-                            origin);
-                } else {
-                    return new FunctionDescriptor(abstracts.first());
-                }
+                return new FunctionDescriptor(abstracts.first());
             } else { // size > 1
-                for (Symbol msym : abstracts) {
-                    if (msym.type.tag == FORALL) {
-                        throw failure("invalid.generic.desc.in.functional.intf",
-                                abstracts.first(),
-                                Kinds.kindName(origin),
-                                origin);
-                    }
-                }
                 FunctionDescriptor descRes = mergeDescriptors(origin, abstracts.toList());
                 if (descRes == null) {
                     //we can get here if the functional interface is ill-formed
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
index d7791f5a1d9..3c577f0e9c0 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -2204,6 +2204,14 @@ public class Attr extends JCTree.Visitor {
                 lambdaType = fallbackDescriptorType(that);
             }
 
+            if (lambdaType.hasTag(FORALL)) {
+                //lambda expression target desc cannot be a generic method
+                resultInfo.checkContext.report(that, diags.fragment("invalid.generic.lambda.target",
+                        lambdaType, kindName(target.tsym), target.tsym));
+                result = that.type = types.createErrorType(pt());
+                return;
+            }
+
             if (!TreeInfo.isExplicitLambda(that)) {
                 //add param type info in the AST
                 List actuals = lambdaType.getParameterTypes();
diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
index 2ac10a97658..1e5cc21b42a 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
@@ -187,8 +187,9 @@ compiler.misc.not.a.functional.intf.1=\
     {0}
 
 # 0: symbol, 1: symbol kind, 2: symbol
-compiler.misc.invalid.generic.desc.in.functional.intf=\
-    invalid functional descriptor: method {0} in {1} {2} is generic
+compiler.misc.invalid.generic.lambda.target=\
+    invalid functional descriptor for lambda expression\n\
+    method {0} in {1} {2} is generic
 
 # 0: symbol kind, 1: symbol
 compiler.misc.incompatible.descs.in.functional.intf=\
diff --git a/langtools/test/tools/javac/diags/examples/InvalidGenericDescInFunctionalInterface.java b/langtools/test/tools/javac/diags/examples/InvalidGenericLambdaTarget.java
similarity index 91%
rename from langtools/test/tools/javac/diags/examples/InvalidGenericDescInFunctionalInterface.java
rename to langtools/test/tools/javac/diags/examples/InvalidGenericLambdaTarget.java
index a43795ea1dc..225b5f3cde1 100644
--- a/langtools/test/tools/javac/diags/examples/InvalidGenericDescInFunctionalInterface.java
+++ b/langtools/test/tools/javac/diags/examples/InvalidGenericLambdaTarget.java
@@ -22,9 +22,9 @@
  */
 
 // key: compiler.err.prob.found.req
-// key: compiler.misc.invalid.generic.desc.in.functional.intf
+// key: compiler.misc.invalid.generic.lambda.target
 
-class InvalidGenericDescInFunctionalIntf {
+class InvalidGenericLambdaTarget {
 
     interface SAM {
          void m();
diff --git a/langtools/test/tools/javac/lambda/LambdaConversionTest.java b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java
similarity index 68%
rename from langtools/test/tools/javac/lambda/LambdaConversionTest.java
rename to langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java
index 0db2904e665..add4cd2def5 100644
--- a/langtools/test/tools/javac/lambda/LambdaConversionTest.java
+++ b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,11 +23,11 @@
 
 /**
  * @test
- * @bug 8003280
+ * @bug 8003280 8004102
  * @summary Add lambda tests
  *  perform several automated checks in lambda conversion, esp. around accessibility
  * @author  Maurizio Cimadamore
- * @run main LambdaConversionTest
+ * @run main FunctionalInterfaceConversionTest
  */
 
 import com.sun.source.util.JavacTask;
@@ -37,9 +37,10 @@ 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 LambdaConversionTest {
+public class FunctionalInterfaceConversionTest {
 
     enum PackageKind {
         NO_PKG(""),
@@ -108,10 +109,21 @@ public class LambdaConversionTest {
         }
     }
 
+    enum ExprKind {
+        LAMBDA("x -> null"),
+        MREF("this::m");
+
+        String exprStr;
+
+        private ExprKind(String exprStr) {
+            this.exprStr = exprStr;
+        }
+    }
+
     enum MethodKind {
         NONE(""),
-        NON_GENERIC("public #R m(#ARG s) throws #T;"),
-        GENERIC("public  #R m(#ARG s) throws #T;");
+        NON_GENERIC("public abstract #R m(#ARG s) throws #T;"),
+        GENERIC("public abstract  #R m(#ARG s) throws #T;");
 
         String methodTemplate;
 
@@ -127,15 +139,21 @@ public class LambdaConversionTest {
     }
 
     public static void main(String[] args) throws Exception {
+        final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
         for (PackageKind samPkg : PackageKind.values()) {
             for (ModifierKind modKind : ModifierKind.values()) {
                 for (SamKind samKind : SamKind.values()) {
-                    for (MethodKind meth : MethodKind.values()) {
-                        for (TypeKind retType : TypeKind.values()) {
-                            for (TypeKind argType : TypeKind.values()) {
-                                for (TypeKind thrownType : TypeKind.values()) {
-                                    new LambdaConversionTest(samPkg, modKind, samKind,
-                                            meth, retType, argType, thrownType).test();
+                    for (MethodKind samMeth : MethodKind.values()) {
+                        for (MethodKind clientMeth : MethodKind.values()) {
+                            for (TypeKind retType : TypeKind.values()) {
+                                for (TypeKind argType : TypeKind.values()) {
+                                    for (TypeKind thrownType : TypeKind.values()) {
+                                        for (ExprKind exprKind : ExprKind.values()) {
+                                            new FunctionalInterfaceConversionTest(samPkg, modKind, samKind,
+                                                    samMeth, clientMeth, retType, argType, thrownType, exprKind).test(comp, fm);
+                                        }
+                                    }
                                 }
                             }
                         }
@@ -148,15 +166,18 @@ public class LambdaConversionTest {
     PackageKind samPkg;
     ModifierKind modKind;
     SamKind samKind;
-    MethodKind meth;
+    MethodKind samMeth;
+    MethodKind clientMeth;
     TypeKind retType;
     TypeKind argType;
     TypeKind thrownType;
+    ExprKind exprKind;
+    DiagnosticChecker dc;
 
     SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") {
         public String toString() {
             return template.replaceAll("#P", samPkg.getPkgDecl()).
-                    replaceAll("#C", samKind.getSam(meth.getMethod(retType, argType, thrownType)));
+                    replaceAll("#C", samKind.getSam(samMeth.getMethod(retType, argType, thrownType)));
         }
     };
 
@@ -169,27 +190,33 @@ public class LambdaConversionTest {
     };
 
     SourceFile clientSourceFile = new SourceFile("Client.java",
-                                                 "#I\n class Client { Sam s = x -> null; }") {
+                                                 "#I\n abstract class Client { \n" +
+                                                 "  Sam s = #E;\n" +
+                                                 "  #M \n }") {
         public String toString() {
-            return template.replaceAll("#I", samPkg.getImportStat());
+            return template.replaceAll("#I", samPkg.getImportStat())
+                    .replaceAll("#E", exprKind.exprStr)
+                    .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType));
         }
     };
 
-    LambdaConversionTest(PackageKind samPkg, ModifierKind modKind, SamKind samKind,
-            MethodKind meth, TypeKind retType, TypeKind argType, TypeKind thrownType) {
+    FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind, SamKind samKind,
+            MethodKind samMeth, MethodKind clientMeth, TypeKind retType, TypeKind argType,
+            TypeKind thrownType, ExprKind exprKind) {
         this.samPkg = samPkg;
         this.modKind = modKind;
         this.samKind = samKind;
-        this.meth = meth;
+        this.samMeth = samMeth;
+        this.clientMeth = clientMeth;
         this.retType = retType;
         this.argType = argType;
         this.thrownType = thrownType;
+        this.exprKind = exprKind;
+        this.dc = new DiagnosticChecker();
     }
 
-    void test() throws Exception {
-        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
-        DiagnosticChecker dc = new DiagnosticChecker();
-        JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
+    void test(JavaCompiler comp, StandardJavaFileManager fm) throws Exception {
+        JavacTask ct = (JavacTask)comp.getTask(null, fm, dc,
                 null, null, Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile));
         ct.analyze();
         if (dc.errorFound == checkSamConversion()) {
@@ -201,8 +228,15 @@ public class LambdaConversionTest {
         if (samKind != SamKind.INTERFACE) {
             //sam type must be an interface
             return false;
-        } else if (meth != MethodKind.NON_GENERIC) {
-            //target method must be non-generic
+        } else if (samMeth == MethodKind.NONE) {
+            //interface must have at least a method
+            return false;
+        } else if (exprKind == ExprKind.LAMBDA &&
+                samMeth != MethodKind.NON_GENERIC) {
+            //target method for lambda must be non-generic
+            return false;
+        } else if (exprKind == ExprKind.MREF &&
+                clientMeth == MethodKind.NONE) {
             return false;
         } else if (samPkg != PackageKind.NO_PKG &&
                 modKind != ModifierKind.PUBLIC &&
diff --git a/langtools/test/tools/javac/lambda/MethodReference57.java b/langtools/test/tools/javac/lambda/MethodReference57.java
new file mode 100644
index 00000000000..b24749fb2bc
--- /dev/null
+++ b/langtools/test/tools/javac/lambda/MethodReference57.java
@@ -0,0 +1,41 @@
+/*
+ * 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 8004102
+ * @summary Add support for generic functional descriptors
+ * @compile MethodReference57.java
+ */
+class MethodReference57 {
+
+    interface F {
+         void m();
+    }
+
+    void test() {
+        F f = this::g; //ok
+    }
+
+    void g() { }
+}
diff --git a/langtools/test/tools/javac/lambda/MethodReference58.java b/langtools/test/tools/javac/lambda/MethodReference58.java
new file mode 100644
index 00000000000..02652da68f0
--- /dev/null
+++ b/langtools/test/tools/javac/lambda/MethodReference58.java
@@ -0,0 +1,46 @@
+/*
+ * 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 8004102
+ * @summary Add support for generic functional descriptors
+ * @compile/fail/ref=MethodReference58.out -XDrawDiagnostics MethodReference58.java
+ */
+class MethodReference58 {
+
+    interface F_Object {
+         void m(X x);
+    }
+
+    interface F_Integer {
+         void m(X x);
+    }
+
+    void test() {
+        F_Object f1 = this::g; //incompatible bounds
+        F_Integer f2 = this::g; //ok
+    }
+
+     void g(Z z) { }
+}
diff --git a/langtools/test/tools/javac/lambda/MethodReference58.out b/langtools/test/tools/javac/lambda/MethodReference58.out
new file mode 100644
index 00000000000..102facb7213
--- /dev/null
+++ b/langtools/test/tools/javac/lambda/MethodReference58.out
@@ -0,0 +1,2 @@
+MethodReference58.java:41:23: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, g, Z, X, kindname.class, MethodReference58, (compiler.misc.inferred.do.not.conform.to.upper.bounds: X, java.lang.Number)))
+1 error

From c76c08e82a1825d7689f71d7c902c2b148acf1c9 Mon Sep 17 00:00:00 2001
From: Maurizio Cimadamore 
Date: Fri, 30 Nov 2012 15:14:36 +0000
Subject: [PATCH 08/10] 8004101: Add checks for method reference
 well-formedness

Bring method reference type-checking in sync with latest EDR

Reviewed-by: jjg
---
 .../com/sun/tools/javac/comp/Attr.java        | 22 ++++++++-
 .../sun/tools/javac/comp/LambdaToMethod.java  | 21 +++------
 .../com/sun/tools/javac/comp/Resolve.java     |  3 +-
 .../tools/javac/resources/compiler.properties |  6 +++
 .../com/sun/tools/javac/tree/JCTree.java      |  2 -
 .../javac/diags/examples/StaticBoundMref.java | 32 +++++++++++++
 .../diags/examples/StaticMrefWithTargs.java   | 32 +++++++++++++
 .../tools/javac/lambda/MethodReference30.java |  2 +-
 .../tools/javac/lambda/MethodReference55.java | 45 +++++++++++++++++++
 .../tools/javac/lambda/MethodReference55.out  |  3 ++
 .../tools/javac/lambda/MethodReference56.java | 45 +++++++++++++++++++
 .../tools/javac/lambda/MethodReference56.out  |  3 ++
 .../lambda/methodReference/MethodRef1.java    |  3 --
 .../lambda/methodReference/SamConversion.java |  9 ----
 .../MethodReferenceTestKinds.java             | 24 ----------
 15 files changed, 195 insertions(+), 57 deletions(-)
 create mode 100644 langtools/test/tools/javac/diags/examples/StaticBoundMref.java
 create mode 100644 langtools/test/tools/javac/diags/examples/StaticMrefWithTargs.java
 create mode 100644 langtools/test/tools/javac/lambda/MethodReference55.java
 create mode 100644 langtools/test/tools/javac/lambda/MethodReference55.out
 create mode 100644 langtools/test/tools/javac/lambda/MethodReference56.java
 create mode 100644 langtools/test/tools/javac/lambda/MethodReference56.out

diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
index 3c577f0e9c0..12929ea20a8 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -2458,7 +2458,7 @@ public class Attr extends JCTree.Visitor {
             }
 
             //attrib type-arguments
-            List typeargtypes = null;
+            List typeargtypes = List.nil();
             if (that.typeargs != null) {
                 typeargtypes = attribTypes(that.typeargs, localEnv);
             }
@@ -2528,6 +2528,26 @@ public class Attr extends JCTree.Visitor {
                 }
             }
 
+            if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
+                if (refSym.isStatic() && TreeInfo.isStaticSelector(that.expr, names) &&
+                        exprType.getTypeArguments().nonEmpty()) {
+                    //static ref with class type-args
+                    log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()),
+                            diags.fragment("static.mref.with.targs"));
+                    result = that.type = types.createErrorType(target);
+                    return;
+                }
+
+                if (refSym.isStatic() && !TreeInfo.isStaticSelector(that.expr, names) &&
+                        !lookupHelper.referenceKind(refSym).isUnbound()) {
+                    //no static bound mrefs
+                    log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()),
+                            diags.fragment("static.bound.mref"));
+                    result = that.type = types.createErrorType(target);
+                    return;
+                }
+            }
+
             if (desc.getReturnType() == Type.recoveryType) {
                 // stop here
                 result = that.type = target;
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
index a4cf5cea3ff..c737c2c36c7 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
@@ -288,21 +288,20 @@ public class LambdaToMethod extends TreeTranslator {
         JCExpression init;
         switch(tree.kind) {
 
-            case IMPLICIT_INNER:    /** Inner # new */
-            case SUPER:             /** super # instMethod */
+            case IMPLICIT_INNER:    /** Inner :: new */
+            case SUPER:             /** super :: instMethod */
                 init = makeThis(
                     localContext.owner.owner.asType(),
                     localContext.owner);
                 break;
 
-            case BOUND:             /** Expr # instMethod */
+            case BOUND:             /** Expr :: instMethod */
                 init = tree.getQualifierExpression();
                 break;
 
-            case STATIC_EVAL:       /** Expr # staticMethod */
-            case UNBOUND:           /** Type # instMethod */
-            case STATIC:            /** Type # staticMethod */
-            case TOPLEVEL:          /** Top level # new */
+            case UNBOUND:           /** Type :: instMethod */
+            case STATIC:            /** Type :: staticMethod */
+            case TOPLEVEL:          /** Top level :: new */
                 init = null;
                 break;
 
@@ -315,14 +314,6 @@ public class LambdaToMethod extends TreeTranslator {
 
         //build a sam instance using an indy call to the meta-factory
         result = makeMetaFactoryIndyCall(tree, tree.targetType, localContext.referenceKind(), refSym, indy_args);
-
-        //if we had a static reference with non-static qualifier, add a let
-        //expression to force the evaluation of the qualifier expr
-        if (tree.hasKind(ReferenceKind.STATIC_EVAL)) {
-            VarSymbol rec = new VarSymbol(0, names.fromString("rec$"), tree.getQualifierExpression().type, localContext.owner);
-            JCVariableDecl recDef = make.VarDef(rec, tree.getQualifierExpression());
-            result = make.LetExpr(recDef, result).setType(tree.type);
-        }
     }
 
     /**
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
index 5ca35ca7e69..df783a26a69 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
@@ -2617,8 +2617,7 @@ public class Resolve {
         @Override
         ReferenceKind referenceKind(Symbol sym) {
             if (sym.isStatic()) {
-                return TreeInfo.isStaticSelector(referenceTree.expr, names) ?
-                        ReferenceKind.STATIC : ReferenceKind.STATIC_EVAL;
+                return ReferenceKind.STATIC;
             } else {
                 Name selName = TreeInfo.name(referenceTree.getQualifierExpression());
                 return selName != null && selName == names._super ?
diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
index 1e5cc21b42a..b7d9378b8c2 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
@@ -215,6 +215,12 @@ compiler.err.invalid.mref=\
 compiler.misc.invalid.mref=\
     invalid {0} reference; {1}
 
+compiler.misc.static.mref.with.targs=\
+    parameterized qualifier on static method reference
+
+compiler.misc.static.bound.mref=\
+    static bound method reference
+
 # 0: symbol
 compiler.err.cant.assign.val.to.final.var=\
     cannot assign a value to final variable {0}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
index 22926654a00..dc7cf22a118 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
@@ -1829,8 +1829,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
             STATIC(ReferenceMode.INVOKE, false),
             /** Expr # instMethod */
             BOUND(ReferenceMode.INVOKE, false),
-            /** Expr # staticMethod */
-            STATIC_EVAL(ReferenceMode.INVOKE, false),
             /** Inner # new */
             IMPLICIT_INNER(ReferenceMode.NEW, false),
             /** Toplevel # new */
diff --git a/langtools/test/tools/javac/diags/examples/StaticBoundMref.java b/langtools/test/tools/javac/diags/examples/StaticBoundMref.java
new file mode 100644
index 00000000000..e53ce7d6b6a
--- /dev/null
+++ b/langtools/test/tools/javac/diags/examples/StaticBoundMref.java
@@ -0,0 +1,32 @@
+/*
+ * 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.invalid.mref
+// key: compiler.misc.static.bound.mref
+
+class StaticBoundMref {
+
+    Runnable r = new StaticBoundMref()::m;
+
+    static void m() { }
+}
diff --git a/langtools/test/tools/javac/diags/examples/StaticMrefWithTargs.java b/langtools/test/tools/javac/diags/examples/StaticMrefWithTargs.java
new file mode 100644
index 00000000000..a033291315e
--- /dev/null
+++ b/langtools/test/tools/javac/diags/examples/StaticMrefWithTargs.java
@@ -0,0 +1,32 @@
+/*
+ * 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.invalid.mref
+// key: compiler.misc.static.mref.with.targs
+
+class StaticMrefWithTargs {
+
+    Runnable r = StaticMrefWithTargs::m;
+
+    static void m() { }
+}
diff --git a/langtools/test/tools/javac/lambda/MethodReference30.java b/langtools/test/tools/javac/lambda/MethodReference30.java
index dec31d00e98..81945c6ec01 100644
--- a/langtools/test/tools/javac/lambda/MethodReference30.java
+++ b/langtools/test/tools/javac/lambda/MethodReference30.java
@@ -46,7 +46,7 @@ public class MethodReference30 {
         assertTrue(true);
     }
 
-   static void m() { }
+   void m() { }
 
    public static void main(String[] args) {
       SAM s = new MethodReference30()::m;
diff --git a/langtools/test/tools/javac/lambda/MethodReference55.java b/langtools/test/tools/javac/lambda/MethodReference55.java
new file mode 100644
index 00000000000..e21bf3e7f4a
--- /dev/null
+++ b/langtools/test/tools/javac/lambda/MethodReference55.java
@@ -0,0 +1,45 @@
+/*
+ * 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 8004101
+ * @summary Add checks for method reference well-formedness
+ * @compile/fail/ref=MethodReference55.out -XDrawDiagnostics MethodReference55.java
+ */
+class MethodReference55 {
+
+    interface V {
+        void m(Object o);
+    }
+
+    V v = new MethodReference55()::m;
+
+    void test() {
+        g(new MethodReference55()::m);
+    }
+
+    void g(V v) { }
+
+    static void m(Object o) { };
+}
diff --git a/langtools/test/tools/javac/lambda/MethodReference55.out b/langtools/test/tools/javac/lambda/MethodReference55.out
new file mode 100644
index 00000000000..8488a28b229
--- /dev/null
+++ b/langtools/test/tools/javac/lambda/MethodReference55.out
@@ -0,0 +1,3 @@
+MethodReference55.java:36:11: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.bound.mref)
+MethodReference55.java:39:11: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.bound.mref)
+2 errors
diff --git a/langtools/test/tools/javac/lambda/MethodReference56.java b/langtools/test/tools/javac/lambda/MethodReference56.java
new file mode 100644
index 00000000000..9e79fab6cc0
--- /dev/null
+++ b/langtools/test/tools/javac/lambda/MethodReference56.java
@@ -0,0 +1,45 @@
+/*
+ * 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 8004101
+ * @summary Add checks for method reference well-formedness
+ * @compile/fail/ref=MethodReference56.out -XDrawDiagnostics MethodReference56.java
+ */
+class MethodReference56 {
+
+    interface V {
+        void m(Object o);
+    }
+
+    V v = MethodReference56::m;
+
+    void test() {
+        g(MethodReference56::m);
+    }
+
+    void g(V v) { }
+
+    static void m(Object o) { };
+}
diff --git a/langtools/test/tools/javac/lambda/MethodReference56.out b/langtools/test/tools/javac/lambda/MethodReference56.out
new file mode 100644
index 00000000000..34ccd15956d
--- /dev/null
+++ b/langtools/test/tools/javac/lambda/MethodReference56.out
@@ -0,0 +1,3 @@
+MethodReference56.java:36:28: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.mref.with.targs)
+MethodReference56.java:39:28: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.mref.with.targs)
+2 errors
diff --git a/langtools/test/tools/javac/lambda/methodReference/MethodRef1.java b/langtools/test/tools/javac/lambda/methodReference/MethodRef1.java
index 2f79439fbd2..bfccad87526 100644
--- a/langtools/test/tools/javac/lambda/methodReference/MethodRef1.java
+++ b/langtools/test/tools/javac/lambda/methodReference/MethodRef1.java
@@ -70,9 +70,6 @@ public class MethodRef1 {
         b = MethodRef1::foo; //static reference to foo(int)
         b.m(1);
 
-        b = new MethodRef1()::foo; //instance reference to static methods, supported for now
-        b.m(1);
-
         b = MethodRef1::bar; //static reference to bar(int)
         b.m(2);
 
diff --git a/langtools/test/tools/javac/lambda/methodReference/SamConversion.java b/langtools/test/tools/javac/lambda/methodReference/SamConversion.java
index fbbbb0f80bb..afe24fb7bd4 100644
--- a/langtools/test/tools/javac/lambda/methodReference/SamConversion.java
+++ b/langtools/test/tools/javac/lambda/methodReference/SamConversion.java
@@ -133,15 +133,6 @@ public class SamConversion {
         } catch (Exception e) {
             assertTrue(false);
         }
-
-        bar = new A()::method6;
-        try {
-            bar.m(1);
-            assertTrue(false);
-        } catch (MyException e) {
-        } catch (Exception e) {
-            assertTrue(false);
-        }
     }
 
     /**
diff --git a/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestKinds.java b/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestKinds.java
index c8f1aa1a0db..5ae83fa3a5e 100644
--- a/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestKinds.java
+++ b/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestKinds.java
@@ -119,20 +119,6 @@ public class MethodReferenceTestKinds extends MethodReferenceTestKindsSup {
         assertEquals(var.get(inst("arg")), "SM:1-MethodReferenceTestKinds(arg)");
     }
 
-    public void testMRStaticEval() {
-        MethodReferenceTestKinds evalCheck;
-        S0 var = (evalCheck = inst("discard"))::staticMethod0;
-        assertEquals(evalCheck.toString(), "MethodReferenceTestKinds(discard)");
-        assertEquals(var.get(), "SM:0");
-    }
-
-    public void testMRStaticEvalArg() {
-        MethodReferenceTestKinds evalCheck;
-        S1 var = (evalCheck = inst("discard"))::staticMethod1;
-        assertEquals(evalCheck.toString(), "MethodReferenceTestKinds(discard)");
-        assertEquals(var.get(inst("arg")), "SM:1-MethodReferenceTestKinds(arg)");
-    }
-
     public void testMRTopLevel() {
         SN0 var = MethodReferenceTestKindsBase::new;
         assertEquals(var.make().toString(), "MethodReferenceTestKindsBase(blank)");
@@ -142,17 +128,7 @@ public class MethodReferenceTestKinds extends MethodReferenceTestKindsSup {
         SN1 var = MethodReferenceTestKindsBase::new;
         assertEquals(var.make("name").toString(), "MethodReferenceTestKindsBase(name)");
     }
-/* unbound inner case not supported anymore (dropped by EG)
-    public void testMRUnboundInner() {
-        SXN0 var = MethodReferenceTestKinds.In::new;
-        assertEquals(var.make(inst("out")).toString(), "In(blank)");
-    }
 
-   public void testMRUnboundInnerArg() {
-        SXN1 var = MethodReferenceTestKinds.In::new;
-        assertEquals(var.make(inst("out"), "name").toString(), "In(name)");
-    }
-*/
     public void testMRImplicitInner() {
         SN0 var = MethodReferenceTestKinds.In::new;
         assertEquals(var.make().toString(), "In(blank)");

From d7884e5ae26b8ecb881acdf96cc32e7f126539c4 Mon Sep 17 00:00:00 2001
From: Maurizio Cimadamore 
Date: Fri, 30 Nov 2012 15:14:48 +0000
Subject: [PATCH 09/10] 8002099: Add support for intersection types in cast
 expression

Add parser and type-checking support for intersection types in cast expressions

Reviewed-by: jjg
---
 .../sun/source/tree/IntersectionTypeTree.java |  39 +++
 .../classes/com/sun/source/tree/Tree.java     |   5 +
 .../com/sun/source/tree/TreeVisitor.java      |   1 +
 .../sun/source/util/SimpleTreeVisitor.java    |   4 +
 .../com/sun/source/util/TreeScanner.java      |   4 +
 .../com/sun/tools/javac/code/Source.java      |   3 +
 .../com/sun/tools/javac/code/Type.java        |  43 +++
 .../com/sun/tools/javac/code/Types.java       | 171 +++++----
 .../com/sun/tools/javac/comp/Attr.java        | 137 +++++---
 .../com/sun/tools/javac/comp/TransTypes.java  |   8 +
 .../com/sun/tools/javac/jvm/ClassReader.java  |   6 +-
 .../com/sun/tools/javac/model/JavacTypes.java |   1 +
 .../sun/tools/javac/parser/JavacParser.java   | 295 ++++++++++------
 .../tools/javac/resources/compiler.properties |   9 +
 .../com/sun/tools/javac/tree/JCTree.java      |  33 ++
 .../com/sun/tools/javac/tree/Pretty.java      |   8 +
 .../com/sun/tools/javac/tree/TreeCopier.java  |   6 +
 .../com/sun/tools/javac/tree/TreeMaker.java   |   6 +
 .../com/sun/tools/javac/tree/TreeScanner.java |   4 +
 .../sun/tools/javac/tree/TreeTranslator.java  |   5 +
 .../lang/model/type/IntersectionType.java     |  47 +++
 .../javax/lang/model/type/TypeKind.java       |   9 +-
 .../javax/lang/model/type/TypeVisitor.java    |  10 +
 .../lang/model/util/AbstractTypeVisitor6.java |  14 +
 .../lang/model/util/AbstractTypeVisitor8.java |   9 +
 .../IntersectionTypeCastTest.java             | 330 ++++++++++++++++++
 .../IntersectionTypeParserTest.java           | 191 ++++++++++
 .../javac/cast/intersection/model/Check.java  |  27 ++
 .../model/IntersectionTypeInfo.java           |  29 ++
 .../javac/cast/intersection/model/Member.java |  31 ++
 .../cast/intersection/model/Model01.java      |  52 +++
 .../cast/intersection/model/ModelChecker.java | 153 ++++++++
 .../IntersectionTypesInCastNotSupported.java  |  29 ++
 .../SecondaryBoundMustBeMarkerIntf.java       |  30 ++
 .../tools/javac/lambda/Intersection01.java    |  42 +++
 .../tools/javac/lambda/Intersection01.out     |   3 +
 .../tools/javac/lambda/LambdaParserTest.java  |  14 +-
 .../IntersectionTargetTypeTest.java           | 294 ++++++++++++++++
 38 files changed, 1873 insertions(+), 229 deletions(-)
 create mode 100644 langtools/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java
 create mode 100644 langtools/src/share/classes/javax/lang/model/type/IntersectionType.java
 create mode 100644 langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java
 create mode 100644 langtools/test/tools/javac/cast/intersection/IntersectionTypeParserTest.java
 create mode 100644 langtools/test/tools/javac/cast/intersection/model/Check.java
 create mode 100644 langtools/test/tools/javac/cast/intersection/model/IntersectionTypeInfo.java
 create mode 100644 langtools/test/tools/javac/cast/intersection/model/Member.java
 create mode 100644 langtools/test/tools/javac/cast/intersection/model/Model01.java
 create mode 100644 langtools/test/tools/javac/cast/intersection/model/ModelChecker.java
 create mode 100644 langtools/test/tools/javac/diags/examples/IntersectionTypesInCastNotSupported.java
 create mode 100644 langtools/test/tools/javac/diags/examples/SecondaryBoundMustBeMarkerIntf.java
 create mode 100644 langtools/test/tools/javac/lambda/Intersection01.java
 create mode 100644 langtools/test/tools/javac/lambda/Intersection01.out
 create mode 100644 langtools/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java

diff --git a/langtools/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java b/langtools/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java
new file mode 100644
index 00000000000..09404699dac
--- /dev/null
+++ b/langtools/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java
@@ -0,0 +1,39 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+/**
+ * A tree node for an intersection type in a cast expression.
+ *
+ * @author Maurizio Cimadamore
+ *
+ * @since 1.8
+ */
+public interface IntersectionTypeTree extends Tree {
+    List getBounds();
+}
diff --git a/langtools/src/share/classes/com/sun/source/tree/Tree.java b/langtools/src/share/classes/com/sun/source/tree/Tree.java
index 4693b84b52b..6ede0373a79 100644
--- a/langtools/src/share/classes/com/sun/source/tree/Tree.java
+++ b/langtools/src/share/classes/com/sun/source/tree/Tree.java
@@ -246,6 +246,11 @@ public interface Tree {
          */
         UNION_TYPE(UnionTypeTree.class),
 
+        /**
+         * Used for instances of {@link IntersectionTypeTree}.
+         */
+        INTERSECTION_TYPE(IntersectionTypeTree.class),
+
         /**
          * Used for instances of {@link TypeCastTree}.
          */
diff --git a/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java b/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java
index dd3cfcbf699..40d311e3126 100644
--- a/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java
+++ b/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java
@@ -98,6 +98,7 @@ public interface TreeVisitor {
     R visitTry(TryTree node, P p);
     R visitParameterizedType(ParameterizedTypeTree node, P p);
     R visitUnionType(UnionTypeTree node, P p);
+    R visitIntersectionType(IntersectionTypeTree node, P p);
     R visitArrayType(ArrayTypeTree node, P p);
     R visitTypeCast(TypeCastTree node, P p);
     R visitPrimitiveType(PrimitiveTypeTree node, P p);
diff --git a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java
index 04e69161b4e..2d9079748bc 100644
--- a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java
+++ b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java
@@ -240,6 +240,10 @@ public class SimpleTreeVisitor  implements TreeVisitor {
         return defaultAction(node, p);
     }
 
+    public R visitIntersectionType(IntersectionTypeTree node, P p) {
+        return defaultAction(node, p);
+    }
+
     public R visitTypeParameter(TypeParameterTree node, P p) {
         return defaultAction(node, p);
     }
diff --git a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java
index 0fcdf825fd4..e3baf6b1d21 100644
--- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java
+++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java
@@ -371,6 +371,10 @@ public class TreeScanner implements TreeVisitor {
         return scan(node.getTypeAlternatives(), p);
     }
 
+    public R visitIntersectionType(IntersectionTypeTree node, P p) {
+        return scan(node.getBounds(), p);
+    }
+
     public R visitTypeParameter(TypeParameterTree node, P p) {
         R r = scan(node.getBounds(), p);
         return r;
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java
index afa1c437d0a..8066ea1be2c 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java
@@ -215,6 +215,9 @@ public enum Source {
     public boolean allowRepeatedAnnotations() {
         return compareTo(JDK1_8) >= 0;
     }
+    public boolean allowIntersectionTypesInCast() {
+        return compareTo(JDK1_8) >= 0;
+    }
     public static SourceVersion toSourceVersion(Source source) {
         switch(source) {
         case JDK1_2:
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
index f75bbf3e8b6..80aabeeb9ba 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
@@ -839,6 +839,49 @@ public class Type implements PrimitiveType {
         }
     }
 
+    // a clone of a ClassType that knows about the bounds of an intersection type.
+    public static class IntersectionClassType extends ClassType implements IntersectionType {
+
+        public boolean allInterfaces;
+
+        public enum IntersectionKind {
+            EXPLICIT,
+            IMPLICT;
+        }
+
+        public IntersectionKind intersectionKind;
+
+        public IntersectionClassType(List bounds, ClassSymbol csym, boolean allInterfaces) {
+            super(Type.noType, List.nil(), csym);
+            this.allInterfaces = allInterfaces;
+            Assert.check((csym.flags() & COMPOUND) != 0);
+            supertype_field = bounds.head;
+            interfaces_field = bounds.tail;
+            Assert.check(supertype_field.tsym.completer != null ||
+                    !supertype_field.isInterface(), supertype_field);
+        }
+
+        public java.util.List getBounds() {
+            return Collections.unmodifiableList(getComponents());
+        }
+
+        public List getComponents() {
+            return interfaces_field.prepend(supertype_field);
+        }
+
+        @Override
+        public TypeKind getKind() {
+            return TypeKind.INTERSECTION;
+        }
+
+        @Override
+        public  R accept(TypeVisitor v, P p) {
+            return intersectionKind == IntersectionKind.EXPLICIT ?
+                v.visitIntersection(this, p) :
+                v.visitDeclared(this, p);
+        }
+    }
+
     public static class ArrayType extends Type
             implements javax.lang.model.type.ArrayType {
 
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
index b591063199d..342aeb986b3 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
@@ -388,28 +388,6 @@ public class Types {
             }
         }
 
-        /**
-         * Scope filter used to skip methods that should be ignored during
-         * function interface conversion (such as methods overridden by
-         * j.l.Object)
-         */
-        class DescriptorFilter implements Filter {
-
-            TypeSymbol origin;
-
-            DescriptorFilter(TypeSymbol origin) {
-                this.origin = origin;
-            }
-
-            @Override
-            public boolean accepts(Symbol sym) {
-                return sym.kind == Kinds.MTH &&
-                        (sym.flags() & (ABSTRACT | DEFAULT)) == ABSTRACT &&
-                        !overridesObjectMethod(origin, sym) &&
-                        (interfaceCandidates(origin.type, (MethodSymbol)sym).head.flags() & DEFAULT) == 0;
-            }
-        };
-
         /**
          * Compute the function descriptor associated with a given functional interface
          */
@@ -577,6 +555,85 @@ public class Types {
     }
     // 
 
+   /**
+    * Scope filter used to skip methods that should be ignored (such as methods
+    * overridden by j.l.Object) during function interface conversion/marker interface checks
+    */
+    class DescriptorFilter implements Filter {
+
+       TypeSymbol origin;
+
+       DescriptorFilter(TypeSymbol origin) {
+           this.origin = origin;
+       }
+
+       @Override
+       public boolean accepts(Symbol sym) {
+           return sym.kind == Kinds.MTH &&
+                   (sym.flags() & (ABSTRACT | DEFAULT)) == ABSTRACT &&
+                   !overridesObjectMethod(origin, sym) &&
+                   (interfaceCandidates(origin.type, (MethodSymbol)sym).head.flags() & DEFAULT) == 0;
+       }
+    };
+
+    // 
+
+    /**
+     * A cache that keeps track of marker interfaces
+     */
+    class MarkerCache {
+
+        private WeakHashMap _map = new WeakHashMap();
+
+        class Entry {
+            final boolean isMarkerIntf;
+            final int prevMark;
+
+            public Entry(boolean isMarkerIntf,
+                    int prevMark) {
+                this.isMarkerIntf = isMarkerIntf;
+                this.prevMark = prevMark;
+            }
+
+            boolean matches(int mark) {
+                return  this.prevMark == mark;
+            }
+        }
+
+        boolean get(TypeSymbol origin) throws FunctionDescriptorLookupError {
+            Entry e = _map.get(origin);
+            CompoundScope members = membersClosure(origin.type, false);
+            if (e == null ||
+                    !e.matches(members.getMark())) {
+                boolean isMarkerIntf = isMarkerInterfaceInternal(origin, members);
+                _map.put(origin, new Entry(isMarkerIntf, members.getMark()));
+                return isMarkerIntf;
+            }
+            else {
+                return e.isMarkerIntf;
+            }
+        }
+
+        /**
+         * Is given symbol a marker interface
+         */
+        public boolean isMarkerInterfaceInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError {
+            return !origin.isInterface() ?
+                    false :
+                    !membersCache.getElements(new DescriptorFilter(origin)).iterator().hasNext();
+        }
+    }
+
+    private MarkerCache markerCache = new MarkerCache();
+
+    /**
+     * Is given type a marker interface?
+     */
+    public boolean isMarkerInterface(Type site) {
+        return markerCache.get(site.tsym);
+    }
+    // 
+
     // 
     /**
      * Is t an unchecked subtype of s?
@@ -1955,45 +2012,28 @@ public class Types {
      * @param supertype         is objectType if all bounds are interfaces,
      *                          null otherwise.
      */
-    public Type makeCompoundType(List bounds,
-                                 Type supertype) {
+    public Type makeCompoundType(List bounds) {
+        return makeCompoundType(bounds, bounds.head.tsym.isInterface());
+    }
+    public Type makeCompoundType(List bounds, boolean allInterfaces) {
+        Assert.check(bounds.nonEmpty());
+        Type firstExplicitBound = bounds.head;
+        if (allInterfaces) {
+            bounds = bounds.prepend(syms.objectType);
+        }
         ClassSymbol bc =
             new ClassSymbol(ABSTRACT|PUBLIC|SYNTHETIC|COMPOUND|ACYCLIC,
                             Type.moreInfo
                                 ? names.fromString(bounds.toString())
                                 : names.empty,
+                            null,
                             syms.noSymbol);
-        if (bounds.head.tag == TYPEVAR)
-            // error condition, recover
-                bc.erasure_field = syms.objectType;
-            else
-                bc.erasure_field = erasure(bounds.head);
-            bc.members_field = new Scope(bc);
-        ClassType bt = (ClassType)bc.type;
-        bt.allparams_field = List.nil();
-        if (supertype != null) {
-            bt.supertype_field = supertype;
-            bt.interfaces_field = bounds;
-        } else {
-            bt.supertype_field = bounds.head;
-            bt.interfaces_field = bounds.tail;
-        }
-        Assert.check(bt.supertype_field.tsym.completer != null
-                || !bt.supertype_field.isInterface(),
-            bt.supertype_field);
-        return bt;
-    }
-
-    /**
-     * Same as {@link #makeCompoundType(List,Type)}, except that the
-     * second parameter is computed directly. Note that this might
-     * cause a symbol completion.  Hence, this version of
-     * makeCompoundType may not be called during a classfile read.
-     */
-    public Type makeCompoundType(List bounds) {
-        Type supertype = (bounds.head.tsym.flags() & INTERFACE) != 0 ?
-            supertype(bounds.head) : null;
-        return makeCompoundType(bounds, supertype);
+        bc.type = new IntersectionClassType(bounds, bc, allInterfaces);
+        bc.erasure_field = (bounds.head.tag == TYPEVAR) ?
+                syms.objectType : // error condition, recover
+                erasure(firstExplicitBound);
+        bc.members_field = new Scope(bc);
+        return bc.type;
     }
 
     /**
@@ -2183,12 +2223,8 @@ public class Types {
      * @param supertype         is objectType if all bounds are interfaces,
      *                          null otherwise.
      */
-    public void setBounds(TypeVar t, List bounds, Type supertype) {
-        if (bounds.tail.isEmpty())
-            t.bound = bounds.head;
-        else
-            t.bound = makeCompoundType(bounds, supertype);
-        t.rank_field = -1;
+    public void setBounds(TypeVar t, List bounds) {
+        setBounds(t, bounds, bounds.head.tsym.isInterface());
     }
 
     /**
@@ -2200,10 +2236,10 @@ public class Types {
      * Note that this check might cause a symbol completion. Hence, this version of
      * setBounds may not be called during a classfile read.
      */
-    public void setBounds(TypeVar t, List bounds) {
-        Type supertype = (bounds.head.tsym.flags() & INTERFACE) != 0 ?
-            syms.objectType : null;
-        setBounds(t, bounds, supertype);
+    public void setBounds(TypeVar t, List bounds, boolean allInterfaces) {
+        t.bound = bounds.tail.isEmpty() ?
+                bounds.head :
+                makeCompoundType(bounds, allInterfaces);
         t.rank_field = -1;
     }
     // 
@@ -2213,7 +2249,7 @@ public class Types {
      * Return list of bounds of the given type variable.
      */
     public List getBounds(TypeVar t) {
-                if (t.bound.hasTag(NONE))
+        if (t.bound.hasTag(NONE))
             return List.nil();
         else if (t.bound.isErroneous() || !t.bound.isCompound())
             return List.of(t.bound);
@@ -3312,8 +3348,7 @@ public class Types {
                     if (arraySuperType == null) {
                         // JLS 10.8: all arrays implement Cloneable and Serializable.
                         arraySuperType = makeCompoundType(List.of(syms.serializableType,
-                                                                  syms.cloneableType),
-                                                          syms.objectType);
+                                                                  syms.cloneableType), true);
                     }
                 }
             }
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
index 12929ea20a8..23fe35ec421 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -716,21 +716,8 @@ public class Attr extends JCTree.Visitor {
             }
             a.tsym.flags_field &= ~UNATTRIBUTED;
         }
-        for (JCTypeParameter tvar : typarams)
+        for (JCTypeParameter tvar : typarams) {
             chk.checkNonCyclic(tvar.pos(), (TypeVar)tvar.type);
-        attribStats(typarams, env);
-    }
-
-    void attribBounds(List typarams) {
-        for (JCTypeParameter typaram : typarams) {
-            Type bound = typaram.type.getUpperBound();
-            if (bound != null && bound.tsym instanceof ClassSymbol) {
-                ClassSymbol c = (ClassSymbol)bound.tsym;
-                if ((c.flags_field & COMPOUND) != 0) {
-                    Assert.check((c.flags_field & UNATTRIBUTED) != 0, c);
-                    attribClass(typaram.pos(), c);
-                }
-            }
         }
     }
 
@@ -892,7 +879,12 @@ public class Attr extends JCTree.Visitor {
             deferredLintHandler.flush(tree.pos());
             chk.checkDeprecatedAnnotation(tree.pos(), m);
 
-            attribBounds(tree.typarams);
+            // Create a new environment with local scope
+            // for attributing the method.
+            Env localEnv = 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 ???
@@ -903,12 +895,6 @@ public class Attr extends JCTree.Visitor {
             }
             chk.checkOverride(tree, m);
 
-            // Create a new environment with local scope
-            // for attributing the method.
-            Env localEnv = memberEnter.methodEnv(tree, env);
-
-            localEnv.info.lint = lint;
-
             if (isDefaultMethod && types.overridesObjectMethod(m.enclClass(), m)) {
                 log.error(tree, "default.overrides.object.member", m.name, Kinds.kindName(m.location()), m.location());
             }
@@ -2196,7 +2182,7 @@ public class Attr extends JCTree.Visitor {
             Type target;
             Type lambdaType;
             if (pt() != Type.recoveryType) {
-                target = infer.instantiateFunctionalInterface(that, pt(), explicitParamTypes, resultInfo.checkContext);
+                target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), explicitParamTypes, resultInfo.checkContext);
                 lambdaType = types.findDescriptorType(target);
                 chk.checkFunctionalInterface(that, target);
             } else {
@@ -2294,6 +2280,26 @@ public class Attr extends JCTree.Visitor {
             }
         }
     }
+
+    private Type checkIntersectionTarget(DiagnosticPosition pos, ResultInfo resultInfo) {
+        Type pt = resultInfo.pt;
+        if (pt != Type.recoveryType && pt.isCompound()) {
+            IntersectionClassType ict = (IntersectionClassType)pt;
+            List bounds = ict.allInterfaces ?
+                    ict.getComponents().tail :
+                    ict.getComponents();
+            types.findDescriptorType(bounds.head); //propagate exception outwards!
+            for (Type bound : bounds.tail) {
+                if (!types.isMarkerInterface(bound)) {
+                    resultInfo.checkContext.report(pos, diags.fragment("secondary.bound.must.be.marker.intf", bound));
+                }
+            }
+            //for now (translation doesn't support intersection types)
+            return bounds.head;
+        } else {
+            return pt;
+        }
+    }
     //where
         private Type fallbackDescriptorType(JCExpression tree) {
             switch (tree.getTag()) {
@@ -2466,7 +2472,7 @@ public class Attr extends JCTree.Visitor {
             Type target;
             Type desc;
             if (pt() != Type.recoveryType) {
-                target = infer.instantiateFunctionalInterface(that, pt(), null, resultInfo.checkContext);
+                target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), null, resultInfo.checkContext);
                 desc = types.findDescriptorType(target);
                 chk.checkFunctionalInterface(that, target);
             } else {
@@ -3575,63 +3581,79 @@ public class Attr extends JCTree.Visitor {
         tree.type = result = t;
     }
 
-    public void visitTypeParameter(JCTypeParameter tree) {
-        TypeVar a = (TypeVar)tree.type;
+    public void visitTypeIntersection(JCTypeIntersection tree) {
+        attribTypes(tree.bounds, env);
+        tree.type = result = checkIntersection(tree, tree.bounds);
+    }
+
+     public void visitTypeParameter(JCTypeParameter tree) {
+        TypeVar typeVar = (TypeVar)tree.type;
+        if (!typeVar.bound.isErroneous()) {
+            //fixup type-parameter bound computed in 'attribTypeVariables'
+            typeVar.bound = checkIntersection(tree, tree.bounds);
+        }
+    }
+
+    Type checkIntersection(JCTree tree, List bounds) {
         Set boundSet = new HashSet();
-        if (a.bound.isErroneous())
-            return;
-        List bs = types.getBounds(a);
-        if (tree.bounds.nonEmpty()) {
+        if (bounds.nonEmpty()) {
             // accept class or interface or typevar as first bound.
-            Type b = checkBase(bs.head, tree.bounds.head, env, false, false, false);
-            boundSet.add(types.erasure(b));
-            if (b.isErroneous()) {
-                a.bound = b;
+            bounds.head.type = checkBase(bounds.head.type, bounds.head, env, false, false, false);
+            boundSet.add(types.erasure(bounds.head.type));
+            if (bounds.head.type.isErroneous()) {
+                return bounds.head.type;
             }
-            else if (b.hasTag(TYPEVAR)) {
+            else if (bounds.head.type.hasTag(TYPEVAR)) {
                 // if first bound was a typevar, do not accept further bounds.
-                if (tree.bounds.tail.nonEmpty()) {
-                    log.error(tree.bounds.tail.head.pos(),
+                if (bounds.tail.nonEmpty()) {
+                    log.error(bounds.tail.head.pos(),
                               "type.var.may.not.be.followed.by.other.bounds");
-                    tree.bounds = List.of(tree.bounds.head);
-                    a.bound = bs.head;
+                    return bounds.head.type;
                 }
             } else {
                 // if first bound was a class or interface, accept only interfaces
                 // as further bounds.
-                for (JCExpression bound : tree.bounds.tail) {
-                    bs = bs.tail;
-                    Type i = checkBase(bs.head, bound, env, false, true, false);
-                    if (i.isErroneous())
-                        a.bound = i;
-                    else if (i.hasTag(CLASS))
-                        chk.checkNotRepeated(bound.pos(), types.erasure(i), boundSet);
+                for (JCExpression bound : bounds.tail) {
+                    bound.type = checkBase(bound.type, bound, env, false, true, false);
+                    if (bound.type.isErroneous()) {
+                        bounds = List.of(bound);
+                    }
+                    else if (bound.type.hasTag(CLASS)) {
+                        chk.checkNotRepeated(bound.pos(), types.erasure(bound.type), boundSet);
+                    }
                 }
             }
         }
-        bs = types.getBounds(a);
 
-        // in case of multiple bounds ...
-        if (bs.length() > 1) {
+        if (bounds.length() == 0) {
+            return syms.objectType;
+        } else if (bounds.length() == 1) {
+            return bounds.head.type;
+        } else {
+            Type owntype = types.makeCompoundType(TreeInfo.types(bounds));
+            if (tree.hasTag(TYPEINTERSECTION)) {
+                ((IntersectionClassType)owntype).intersectionKind =
+                        IntersectionClassType.IntersectionKind.EXPLICIT;
+            }
             // ... the variable's bound is a class type flagged COMPOUND
             // (see comment for TypeVar.bound).
             // In this case, generate a class tree that represents the
             // bound class, ...
             JCExpression extending;
             List implementing;
-            if ((bs.head.tsym.flags() & INTERFACE) == 0) {
-                extending = tree.bounds.head;
-                implementing = tree.bounds.tail;
+            if (!bounds.head.type.isInterface()) {
+                extending = bounds.head;
+                implementing = bounds.tail;
             } else {
                 extending = null;
-                implementing = tree.bounds;
+                implementing = bounds;
             }
-            JCClassDecl cd = make.at(tree.pos).ClassDef(
+            JCClassDecl cd = make.at(tree).ClassDef(
                 make.Modifiers(PUBLIC | ABSTRACT),
-                tree.name, List.nil(),
+                names.empty, List.nil(),
                 extending, implementing, List.nil());
 
-            ClassSymbol c = (ClassSymbol)a.getUpperBound().tsym;
+            ClassSymbol c = (ClassSymbol)owntype.tsym;
             Assert.check((c.flags() & COMPOUND) != 0);
             cd.sym = c;
             c.sourcefile = env.toplevel.sourcefile;
@@ -3640,10 +3662,11 @@ public class Attr extends JCTree.Visitor {
             c.flags_field |= UNATTRIBUTED;
             Env cenv = enter.classEnv(cd, env);
             enter.typeEnvs.put(c, cenv);
+            attribClass(c);
+            return owntype;
         }
     }
 
-
     public void visitWildcard(JCWildcard tree) {
         //- System.err.println("visitWildcard("+tree+");");//DEBUG
         Type type = (tree.kind.kind == BoundKind.UNBOUND)
@@ -3797,7 +3820,7 @@ public class Attr extends JCTree.Visitor {
         chk.validateAnnotations(tree.mods.annotations, c);
 
         // Validate type parameters, supertype and interfaces.
-        attribBounds(tree.typarams);
+        attribStats(tree.typarams, env);
         if (!c.isAnonymous()) {
             //already checked if anonymous
             chk.validate(tree.typarams, env);
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java
index 8b1b7f54c9a..76ca8f68ea2 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java
@@ -551,6 +551,7 @@ public class TransTypes extends TreeTranslator {
             tree.body = translate(tree.body, null);
             //save non-erased target
             tree.targetType = tree.type;
+            Assert.check(!tree.targetType.isCompound(), "Intersection-type targets not supported yet!");
             tree.type = erasure(tree.type);
             result = tree;
         }
@@ -786,6 +787,7 @@ public class TransTypes extends TreeTranslator {
         tree.expr = translate(tree.expr, null);
         //save non-erased target
         tree.targetType = tree.type;
+        Assert.check(!tree.targetType.isCompound(), "Intersection-type targets not supported yet!");
         tree.type = erasure(tree.type);
         result = tree;
     }
@@ -803,6 +805,12 @@ public class TransTypes extends TreeTranslator {
         result = clazz;
     }
 
+    public void visitTypeIntersection(JCTypeIntersection tree) {
+        tree.bounds = translate(tree.bounds, null);
+        tree.type = erasure(tree.type);
+        result = tree;
+    }
+
 /**************************************************************************
  * utility methods
  *************************************************************************/
diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
index 43c65db98b2..602d4226f9c 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
@@ -846,17 +846,17 @@ public class ClassReader implements Completer {
             tvar = (TypeVar)findTypeVar(name);
         }
         List bounds = List.nil();
-        Type st = null;
+        boolean allInterfaces = false;
         if (signature[sigp] == ':' && signature[sigp+1] == ':') {
             sigp++;
-            st = syms.objectType;
+            allInterfaces = true;
         }
         while (signature[sigp] == ':') {
             sigp++;
             bounds = bounds.prepend(sigToType());
         }
         if (!sigEnterPhase) {
-            types.setBounds(tvar, bounds.reverse(), st);
+            types.setBounds(tvar, bounds.reverse(), allInterfaces);
         }
         return tvar;
     }
diff --git a/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java b/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java
index 88406c3fdf1..40a36019214 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java
@@ -74,6 +74,7 @@ public class JavacTypes implements javax.lang.model.util.Types {
     public Element asElement(TypeMirror t) {
         switch (t.getKind()) {
             case DECLARED:
+            case INTERSECTION:
             case ERROR:
             case TYPEVAR:
                 Type type = cast(Type.class, t);
diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
index 24e439e6694..90e384c27d8 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
@@ -124,6 +124,9 @@ public class JavacParser implements Parser {
         this.allowLambda = source.allowLambda();
         this.allowMethodReferences = source.allowMethodReferences();
         this.allowDefaultMethods = source.allowDefaultMethods();
+        this.allowIntersectionTypesInCast =
+                source.allowIntersectionTypesInCast() &&
+                fac.options.isSet("allowIntersectionTypes");
         this.keepDocComments = keepDocComments;
         docComments = newDocCommentTable(keepDocComments, fac);
         this.keepLineMap = keepLineMap;
@@ -197,6 +200,10 @@ public class JavacParser implements Parser {
      */
     boolean allowDefaultMethods;
 
+    /** Switch: should we allow intersection types in cast?
+     */
+    boolean allowIntersectionTypesInCast;
+
     /** Switch: should we keep docComments?
      */
     boolean keepDocComments;
@@ -239,22 +246,38 @@ public class JavacParser implements Parser {
     }
 
     protected boolean peekToken(TokenKind tk) {
-        return S.token(1).kind == tk;
+        return peekToken(0, tk);
+    }
+
+    protected boolean peekToken(int lookahead, TokenKind tk) {
+        return S.token(lookahead + 1).kind == tk;
     }
 
     protected boolean peekToken(TokenKind tk1, TokenKind tk2) {
-        return S.token(1).kind == tk1 &&
-                S.token(2).kind == tk2;
+        return peekToken(0, tk1, tk2);
+    }
+
+    protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2) {
+        return S.token(lookahead + 1).kind == tk1 &&
+                S.token(lookahead + 2).kind == tk2;
     }
 
     protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) {
-        return S.token(1).kind == tk1 &&
-                S.token(2).kind == tk2 &&
-                S.token(3).kind == tk3;
+        return peekToken(0, tk1, tk2, tk3);
+    }
+
+    protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2, TokenKind tk3) {
+        return S.token(lookahead + 1).kind == tk1 &&
+                S.token(lookahead + 2).kind == tk2 &&
+                S.token(lookahead + 3).kind == tk3;
     }
 
     protected boolean peekToken(TokenKind... kinds) {
-        for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) {
+        return peekToken(0, kinds);
+    }
+
+    protected boolean peekToken(int lookahead, TokenKind... kinds) {
+        for (; lookahead < kinds.length ; lookahead++) {
             if (S.token(lookahead + 1).kind != kinds[lookahead]) {
                 return false;
             }
@@ -966,102 +989,40 @@ public class JavacParser implements Parser {
             break;
         case LPAREN:
             if (typeArgs == null && (mode & EXPR) != 0) {
-                if (peekToken(MONKEYS_AT) ||
-                        peekToken(FINAL) ||
-                        peekToken(RPAREN) ||
-                        peekToken(IDENTIFIER, COMMA) ||
-                        peekToken(IDENTIFIER, RPAREN, ARROW)) {
-                    //implicit n-ary lambda
-                    t = lambdaExpressionOrStatement(true, peekToken(MONKEYS_AT) || peekToken(FINAL), pos);
-                    break;
-                } else {
-                    nextToken();
-                    mode = EXPR | TYPE | NOPARAMS;
-                    t = term3();
-                    if ((mode & TYPE) != 0 && token.kind == LT) {
-                        // Could be a cast to a parameterized type
-                        JCTree.Tag op = JCTree.Tag.LT;
-                        int pos1 = token.pos;
-                        nextToken();
-                        mode &= (EXPR | TYPE);
-                        mode |= TYPEARG;
-                        JCExpression t1 = term3();
-                        if ((mode & TYPE) != 0 &&
-                            (token.kind == COMMA || token.kind == GT)) {
-                            mode = TYPE;
-                            ListBuffer args = new ListBuffer();
-                            args.append(t1);
-                            while (token.kind == COMMA) {
-                                nextToken();
-                                args.append(typeArgument());
-                            }
-                            accept(GT);
-                            t = toP(F.at(pos1).TypeApply(t, args.toList()));
-                            checkGenerics();
-                            mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type
-                            t = term3Rest(t, typeArgs);
-                            if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) {
-                                //explicit lambda (w/ generic type)
-                                mode = EXPR;
-                                JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
-                                if (token.kind == ELLIPSIS) {
-                                    mods.flags = Flags.VARARGS;
-                                    t = to(F.at(token.pos).TypeArray(t));
-                                    nextToken();
-                                }
-                                t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
-                                break;
-                            }
-                        } else if ((mode & EXPR) != 0) {
-                            mode = EXPR;
-                            JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
-                            t = F.at(pos1).Binary(op, t, e);
-                            t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
-                        } else {
-                            accept(GT);
-                        }
-                    } else if ((mode & TYPE) != 0 &&
-                            (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
-                        //explicit lambda (w/ non-generic type)
-                        mode = EXPR;
-                        JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
-                        if (token.kind == ELLIPSIS) {
-                            mods.flags = Flags.VARARGS;
-                            t = to(F.at(token.pos).TypeArray(t));
-                            nextToken();
-                        }
-                        t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
+                ParensResult pres = analyzeParens();
+                switch (pres) {
+                    case CAST:
+                       accept(LPAREN);
+                       mode = TYPE;
+                       int pos1 = pos;
+                       List targets = List.of(t = term3());
+                       while (token.kind == AMP) {
+                           checkIntersectionTypesInCast();
+                           accept(AMP);
+                           targets = targets.prepend(term3());
+                       }
+                       if (targets.length() > 1) {
+                           t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
+                       }
+                       accept(RPAREN);
+                       mode = EXPR;
+                       JCExpression t1 = term3();
+                       return F.at(pos).TypeCast(t, t1);
+                    case IMPLICIT_LAMBDA:
+                    case EXPLICIT_LAMBDA:
+                        t = lambdaExpressionOrStatement(true, pres == ParensResult.EXPLICIT_LAMBDA, pos);
+                        break;
+                    default: //PARENS
+                        accept(LPAREN);
+                        mode = EXPR;
+                        t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
+                        accept(RPAREN);
+                        t = toP(F.at(pos).Parens(t));
                         break;
-                    } else {
-                        t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
-                    }
-                }
-
-                accept(RPAREN);
-                lastmode = mode;
-                mode = EXPR;
-                if ((lastmode & EXPR) == 0) {
-                    JCExpression t1 = term3();
-                    return F.at(pos).TypeCast(t, t1);
-                } else if ((lastmode & TYPE) != 0) {
-                    switch (token.kind) {
-                    /*case PLUSPLUS: case SUBSUB: */
-                    case BANG: case TILDE:
-                    case LPAREN: case THIS: case SUPER:
-                    case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
-                    case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
-                    case TRUE: case FALSE: case NULL:
-                        case NEW: case IDENTIFIER: case ASSERT: case ENUM:
-                    case BYTE: case SHORT: case CHAR: case INT:
-                    case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
-                        JCExpression t1 = term3();
-                        return F.at(pos).TypeCast(t, t1);
-                    }
                 }
             } else {
                 return illegal();
             }
-            t = toP(F.at(pos).Parens(t));
             break;
         case THIS:
             if ((mode & EXPR) != 0) {
@@ -1346,6 +1307,138 @@ public class JavacParser implements Parser {
         }
     }
 
+    /**
+     * If we see an identifier followed by a '<' it could be an unbound
+     * method reference or a binary expression. To disambiguate, look for a
+     * matching '>' and see if the subsequent terminal is either '.' or '#'.
+     */
+    @SuppressWarnings("fallthrough")
+    ParensResult analyzeParens() {
+        int depth = 0;
+        boolean type = false;
+        for (int lookahead = 0 ; ; lookahead++) {
+            TokenKind tk = S.token(lookahead).kind;
+            switch (tk) {
+                case EXTENDS: case SUPER: case COMMA:
+                    type = true;
+                case QUES: case DOT: case AMP:
+                    //skip
+                    break;
+                case BYTE: case SHORT: case INT: case LONG: case FLOAT:
+                case DOUBLE: case BOOLEAN: case CHAR:
+                    if (peekToken(lookahead, RPAREN)) {
+                        //Type, ')' -> cast
+                        return ParensResult.CAST;
+                    } else if (peekToken(lookahead, IDENTIFIER)) {
+                        //Type, 'Identifier -> explicit lambda
+                        return ParensResult.EXPLICIT_LAMBDA;
+                    }
+                    break;
+                case LPAREN:
+                    if (lookahead != 0) {
+                        // '(' in a non-starting position -> parens
+                        return ParensResult.PARENS;
+                    } else if (peekToken(lookahead, RPAREN)) {
+                        // '(', ')' -> explicit lambda
+                        return ParensResult.EXPLICIT_LAMBDA;
+                    }
+                    break;
+                case RPAREN:
+                    // if we have seen something that looks like a type,
+                    // then it's a cast expression
+                    if (type) return ParensResult.CAST;
+                    // otherwise, disambiguate cast vs. parenthesized expression
+                    // based on subsequent token.
+                    switch (S.token(lookahead + 1).kind) {
+                        /*case PLUSPLUS: case SUBSUB: */
+                        case BANG: case TILDE:
+                        case LPAREN: case THIS: case SUPER:
+                        case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
+                        case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
+                        case TRUE: case FALSE: case NULL:
+                            case NEW: case IDENTIFIER: case ASSERT: case ENUM:
+                        case BYTE: case SHORT: case CHAR: case INT:
+                        case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
+                            return ParensResult.CAST;
+                        default:
+                            return ParensResult.PARENS;
+                    }
+                case IDENTIFIER:
+                    if (peekToken(lookahead, IDENTIFIER)) {
+                        // Identifier, Identifier -> explicit lambda
+                        return ParensResult.EXPLICIT_LAMBDA;
+                    } else if (peekToken(lookahead, RPAREN, ARROW)) {
+                        // Identifier, ')' '->' -> implicit lambda
+                        return ParensResult.IMPLICIT_LAMBDA;
+                    }
+                    break;
+                case FINAL:
+                case ELLIPSIS:
+                case MONKEYS_AT:
+                    //those can only appear in explicit lambdas
+                    return ParensResult.EXPLICIT_LAMBDA;
+                case LBRACKET:
+                    if (peekToken(lookahead, RBRACKET, IDENTIFIER)) {
+                        // '[', ']', Identifier -> explicit lambda
+                        return ParensResult.EXPLICIT_LAMBDA;
+                    } else if (peekToken(lookahead, RBRACKET, RPAREN) ||
+                            peekToken(lookahead, RBRACKET, AMP)) {
+                        // '[', ']', ')' -> cast
+                        // '[', ']', '&' -> cast (intersection type)
+                        return ParensResult.CAST;
+                    } else if (peekToken(lookahead, RBRACKET)) {
+                        //consume the ']' and skip
+                        type = true;
+                        lookahead++;
+                        break;
+                    } else {
+                        return ParensResult.PARENS;
+                    }
+                case LT:
+                    depth++; break;
+                case GTGTGT:
+                    depth--;
+                case GTGT:
+                    depth--;
+                case GT:
+                    depth--;
+                    if (depth == 0) {
+                        if (peekToken(lookahead, RPAREN) ||
+                                peekToken(lookahead, AMP)) {
+                            // '>', ')' -> cast
+                            // '>', '&' -> cast
+                            return ParensResult.CAST;
+                        } else if (peekToken(lookahead, IDENTIFIER, COMMA) ||
+                                peekToken(lookahead, IDENTIFIER, RPAREN, ARROW) ||
+                                peekToken(lookahead, ELLIPSIS)) {
+                            // '>', Identifier, ',' -> explicit lambda
+                            // '>', Identifier, ')', '->' -> explicit lambda
+                            // '>', '...' -> explicit lambda
+                            return ParensResult.EXPLICIT_LAMBDA;
+                        }
+                        //it looks a type, but could still be (i) a cast to generic type,
+                        //(ii) an unbound method reference or (iii) an explicit lambda
+                        type = true;
+                        break;
+                    } else if (depth < 0) {
+                        //unbalanced '<', '>' - not a generic type
+                        return ParensResult.PARENS;
+                    }
+                    break;
+                default:
+                    //this includes EOF
+                    return ParensResult.PARENS;
+            }
+        }
+    }
+
+    enum ParensResult {
+        CAST,
+        EXPLICIT_LAMBDA,
+        IMPLICIT_LAMBDA,
+        PARENS;
+    }
+
     JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
         ListBuffer params = new ListBuffer();
         params.append(firstParam);
@@ -3386,6 +3479,12 @@ public class JavacParser implements Parser {
             allowDefaultMethods = true;
         }
     }
+    void checkIntersectionTypesInCast() {
+        if (!allowIntersectionTypesInCast) {
+            log.error(token.pos, "intersection.types.in.cast.not.supported.in.source", source.name);
+            allowIntersectionTypesInCast = true;
+        }
+    }
 
     /*
      * a functional source tree and end position mappings
diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
index b7d9378b8c2..900066bb1f1 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
@@ -207,6 +207,10 @@ compiler.misc.descriptor.throws=\
 compiler.misc.no.suitable.functional.intf.inst=\
     cannot infer functional interface descriptor for {0}
 
+# 0: type
+compiler.misc.secondary.bound.must.be.marker.intf=\
+    secondary bound {0} must be a marker interface
+
 # 0: symbol kind, 1: message segment
 compiler.err.invalid.mref=\
     invalid {0} reference; {1}
@@ -2203,6 +2207,11 @@ 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)
 
+# 0: string
+compiler.err.intersection.types.in.cast.not.supported.in.source=\
+    intersection types in cast 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)
diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
index dc7cf22a118..2e65c5dfa46 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
@@ -254,6 +254,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
          */
         TYPEUNION,
 
+        /** Intersection types, of type TypeIntersection
+         */
+        TYPEINTERSECTION,
+
         /** Formal type parameters, of type TypeParameter.
          */
         TYPEPARAMETER,
@@ -2061,6 +2065,34 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
         }
     }
 
+    /**
+     * An intersection type, T1 & T2 & ... Tn (used in cast expressions)
+     */
+    public static class JCTypeIntersection extends JCExpression implements IntersectionTypeTree {
+
+        public List bounds;
+
+        protected JCTypeIntersection(List bounds) {
+            this.bounds = bounds;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeIntersection(this); }
+
+        public Kind getKind() { return Kind.INTERSECTION_TYPE; }
+
+        public List getBounds() {
+            return bounds;
+        }
+        @Override
+        public  R accept(TreeVisitor v, D d) {
+            return v.visitIntersectionType(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return TYPEINTERSECTION;
+        }
+    }
+
     /**
      * A formal class parameter.
      */
@@ -2383,6 +2415,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
         public void visitTypeArray(JCArrayTypeTree that)     { visitTree(that); }
         public void visitTypeApply(JCTypeApply that)         { visitTree(that); }
         public void visitTypeUnion(JCTypeUnion that)         { visitTree(that); }
+        public void visitTypeIntersection(JCTypeIntersection that)  { visitTree(that); }
         public void visitTypeParameter(JCTypeParameter that) { visitTree(that); }
         public void visitWildcard(JCWildcard that)           { visitTree(that); }
         public void visitTypeBoundKind(TypeBoundKind that)   { visitTree(that); }
diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java
index e2f7b89399b..fa021522d95 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java
@@ -1249,6 +1249,14 @@ public class Pretty extends JCTree.Visitor {
         }
     }
 
+    public void visitTypeIntersection(JCTypeIntersection tree) {
+        try {
+            printExprs(tree.bounds, " & ");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
     public void visitTypeParameter(JCTypeParameter tree) {
         try {
             print(tree.name);
diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java
index f8efaa32018..c2e2ef92290 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java
@@ -358,6 +358,12 @@ public class TreeCopier

implements TreeVisitor { return M.at(t.pos).TypeUnion(components); } + public JCTree visitIntersectionType(IntersectionTypeTree node, P p) { + JCTypeIntersection t = (JCTypeIntersection) node; + List bounds = copy(t.bounds, p); + return M.at(t.pos).TypeIntersection(bounds); + } + public JCTree visitArrayType(ArrayTypeTree node, P p) { JCArrayTypeTree t = (JCArrayTypeTree) node; JCExpression elemtype = copy(t.elemtype, p); diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java index 3182d6ed954..ce69edbe3f2 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java @@ -456,6 +456,12 @@ public class TreeMaker implements JCTree.Factory { return tree; } + public JCTypeIntersection TypeIntersection(List components) { + JCTypeIntersection tree = new JCTypeIntersection(components); + tree.pos = pos; + return tree; + } + public JCTypeParameter TypeParameter(Name name, List bounds) { JCTypeParameter tree = new JCTypeParameter(name, bounds); tree.pos = pos; diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java index 9a7c321f368..eff0fe2c617 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java @@ -286,6 +286,10 @@ public class TreeScanner extends Visitor { scan(tree.alternatives); } + public void visitTypeIntersection(JCTypeIntersection tree) { + scan(tree.bounds); + } + public void visitTypeParameter(JCTypeParameter tree) { scan(tree.bounds); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java index 2bc9c7a1290..daf456fa90d 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java @@ -379,6 +379,11 @@ public class TreeTranslator extends JCTree.Visitor { result = tree; } + public void visitTypeIntersection(JCTypeIntersection tree) { + tree.bounds = translate(tree.bounds); + result = tree; + } + public void visitTypeParameter(JCTypeParameter tree) { tree.bounds = translate(tree.bounds); result = tree; diff --git a/langtools/src/share/classes/javax/lang/model/type/IntersectionType.java b/langtools/src/share/classes/javax/lang/model/type/IntersectionType.java new file mode 100644 index 00000000000..80dca497e74 --- /dev/null +++ b/langtools/src/share/classes/javax/lang/model/type/IntersectionType.java @@ -0,0 +1,47 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package javax.lang.model.type; + +import java.util.List; + +/** + * Represents an intersection type. + * + * As of the {@link javax.lang.model.SourceVersion#RELEASE_8 + * RELEASE_8} source version, intersection types can appear as the target type + * of a cast expression. + * + * @since 1.8 + */ +public interface IntersectionType extends TypeMirror { + + /** + * Return the bounds comprising this intersection type. + * + * @return the bounds of this intersection types. + */ + List getBounds(); +} diff --git a/langtools/src/share/classes/javax/lang/model/type/TypeKind.java b/langtools/src/share/classes/javax/lang/model/type/TypeKind.java index 717737649f0..0f67a3ba7b6 100644 --- a/langtools/src/share/classes/javax/lang/model/type/TypeKind.java +++ b/langtools/src/share/classes/javax/lang/model/type/TypeKind.java @@ -144,7 +144,14 @@ public enum TypeKind { * * @since 1.7 */ - UNION; + UNION, + + /** + * An intersection type. + * + * @since 1.8 + */ + INTERSECTION; /** * Returns {@code true} if this kind corresponds to a primitive diff --git a/langtools/src/share/classes/javax/lang/model/type/TypeVisitor.java b/langtools/src/share/classes/javax/lang/model/type/TypeVisitor.java index 58f63637f64..f95af6c87d9 100644 --- a/langtools/src/share/classes/javax/lang/model/type/TypeVisitor.java +++ b/langtools/src/share/classes/javax/lang/model/type/TypeVisitor.java @@ -172,4 +172,14 @@ public interface TypeVisitor { * @since 1.7 */ R visitUnion(UnionType t, P p); + + /** + * Visits an intersection type. + * + * @param t the type to visit + * @param p a visitor-specified parameter + * @return a visitor-specified result + * @since 1.8 + */ + R visitIntersection(IntersectionType t, P p); } diff --git a/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java b/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java index bff7e69b2a7..c36fda3dec9 100644 --- a/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java +++ b/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java @@ -110,6 +110,20 @@ public abstract class AbstractTypeVisitor6 implements TypeVisitor { return visitUnknown(t, p); } + /** + * Visits an {@code IntersectionType} element by calling {@code + * visitUnknown}. + + * @param t {@inheritDoc} + * @param p {@inheritDoc} + * @return the result of {@code visitUnknown} + * + * @since 1.8 + */ + public R visitIntersection(IntersectionType t, P p) { + return visitUnknown(t, p); + } + /** * {@inheritDoc} * diff --git a/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor8.java b/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor8.java index 40a7eea6028..3f038d29e79 100644 --- a/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor8.java +++ b/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor8.java @@ -66,4 +66,13 @@ public abstract class AbstractTypeVisitor8 extends AbstractTypeVisitor7 superInterfaces; + + ClassKind(String declTemplate, String typeStr, InterfaceKind... superInterfaces) { + this.declTemplate = declTemplate; + this.typeStr = typeStr; + this.superInterfaces = List.from(superInterfaces); + } + + String getDecl(ModifierKind mod) { + return declTemplate != null ? + declTemplate.replaceAll("#M", mod.modStr) : + ""; + } + + @Override + public boolean subtypeOf(Type that) { + return this == that || superInterfaces.contains(that) || that == OBJECT; + } + + @Override + public String asString() { + return typeStr; + } + + @Override + public boolean isClass() { + return true; + } + + @Override + public boolean isInterface() { + return false; + } + } + + enum ModifierKind { + NONE(""), + FINAL("final"); + + String modStr; + + ModifierKind(String modStr) { + this.modStr = modStr; + } + } + + enum CastKind { + CLASS("(#C)", 0), + INTERFACE("(#I0)", 1), + INTERSECTION2("(#C & #I0)", 1), + INTERSECTION3("(#C & #I0 & #I1)", 2); + //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3); + + String castTemplate; + int interfaceBounds; + + CastKind(String castTemplate, int interfaceBounds) { + this.castTemplate = castTemplate; + this.interfaceBounds = interfaceBounds; + } + } + + static class CastInfo { + CastKind kind; + Type[] types; + + CastInfo(CastKind kind, Type... types) { + this.kind = kind; + this.types = types; + } + + String getCast() { + String temp = kind.castTemplate.replaceAll("#C", types[0].asString()); + for (int i = 0; i < kind.interfaceBounds ; i++) { + temp = temp.replace(String.format("#I%d", i), types[i + 1].asString()); + } + return temp; + } + + boolean hasDuplicateTypes() { + for (int i = 0 ; i < types.length ; i++) { + for (int j = 0 ; j < types.length ; j++) { + if (i != j && types[i] == types[j]) { + return true; + } + } + } + return false; + } + + boolean compatibleWith(ModifierKind mod, CastInfo that) { + for (Type t1 : types) { + for (Type t2 : that.types) { + boolean compat = + t1.subtypeOf(t2) || + t2.subtypeOf(t1) || + (t1.isInterface() && t2.isInterface()) || //side-cast (1) + (mod == ModifierKind.NONE && (t1.isInterface() != t2.isInterface())); //side-cast (2) + if (!compat) return false; + } + } + return true; + } + } + + 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 (ModifierKind mod : ModifierKind.values()) { + for (CastInfo cast1 : allCastInfo()) { + for (CastInfo cast2 : allCastInfo()) { + new IntersectionTypeCastTest(mod, cast1, cast2).run(comp, fm); + } + } + } + System.out.println("Total check executed: " + checkCount); + } + + static List allCastInfo() { + ListBuffer buf = ListBuffer.lb(); + for (CastKind kind : CastKind.values()) { + for (ClassKind clazz : ClassKind.values()) { + if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) { + continue; + } else if (kind.interfaceBounds == 0) { + buf.append(new CastInfo(kind, clazz)); + continue; + } else { + for (InterfaceKind intf1 : InterfaceKind.values()) { + if (kind.interfaceBounds == 1) { + buf.append(new CastInfo(kind, clazz, intf1)); + continue; + } else { + for (InterfaceKind intf2 : InterfaceKind.values()) { + if (kind.interfaceBounds == 2) { + buf.append(new CastInfo(kind, clazz, intf1, intf2)); + continue; + } else { + for (InterfaceKind intf3 : InterfaceKind.values()) { + buf.append(new CastInfo(kind, clazz, intf1, intf2, intf3)); + continue; + } + } + } + } + } + } + } + } + return buf.toList(); + } + + ModifierKind mod; + CastInfo cast1, cast2; + JavaSource source; + DiagnosticChecker diagChecker; + + IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) { + this.mod = mod; + this.cast1 = cast1; + this.cast2 = cast2; + this.source = new JavaSource(); + this.diagChecker = new DiagnosticChecker(); + } + + class JavaSource extends SimpleJavaFileObject { + + String bodyTemplate = "class Test {\n" + + " void test() {\n" + + " Object o = #C1#C2null;\n" + + " } }"; + + String source = ""; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + for (ClassKind ck : ClassKind.values()) { + source += ck.getDecl(mod); + } + for (InterfaceKind ik : InterfaceKind.values()) { + source += ik.declStr; + } + source += bodyTemplate.replaceAll("#C1", cast1.getCast()).replaceAll("#C2", cast2.getCast()); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } + + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, + Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source)); + try { + ct.analyze(); + } catch (Throwable ex) { + throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true)); + } + check(); + } + + void check() { + checkCount++; + + boolean errorExpected = cast1.hasDuplicateTypes() || cast2.hasDuplicateTypes(); + + errorExpected |= !cast2.compatibleWith(mod, cast1); + + if (errorExpected != diagChecker.errorFound) { + throw new Error("invalid diagnostics for source:\n" + + source.getCharContent(true) + + "\nFound error: " + diagChecker.errorFound + + "\nExpected error: " + errorExpected); + } + } + + static class DiagnosticChecker implements javax.tools.DiagnosticListener { + + boolean errorFound; + + public void report(Diagnostic diagnostic) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + errorFound = true; + } + } + } +} diff --git a/langtools/test/tools/javac/cast/intersection/IntersectionTypeParserTest.java b/langtools/test/tools/javac/cast/intersection/IntersectionTypeParserTest.java new file mode 100644 index 00000000000..7f113900bc6 --- /dev/null +++ b/langtools/test/tools/javac/cast/intersection/IntersectionTypeParserTest.java @@ -0,0 +1,191 @@ +/* + * 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 8002099 + * @summary Add support for intersection types in cast expression + */ + +import com.sun.source.util.JavacTask; +import java.net.URI; +import java.util.Arrays; +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 IntersectionTypeParserTest { + + static int checkCount = 0; + + enum TypeKind { + SIMPLE("A"), + GENERIC("A"), + WILDCARD("A"); + + String typeStr; + + TypeKind(String typeStr) { + this.typeStr = typeStr; + } + } + + enum ArrayKind { + NONE(""), + SINGLE("[]"), + DOUBLE("[][]"); + + String arrStr; + + ArrayKind(String arrStr) { + this.arrStr = arrStr; + } + } + + static class Type { + TypeKind tk; + ArrayKind ak; + + Type(TypeKind tk, ArrayKind ak) { + this.tk = tk; + this.ak = ak; + } + + String asString() { + return tk.typeStr + ak.arrStr; + } + } + + enum CastKind { + ONE("(#T0)", 1), + TWO("(#T0 & T1)", 2), + THREE("(#T0 & #T1 & #T2)", 3); + + String castTemplate; + int nBounds; + + CastKind(String castTemplate, int nBounds) { + this.castTemplate = castTemplate; + this.nBounds = nBounds; + } + + String asString(Type... types) { + String res = castTemplate; + for (int i = 0; i < nBounds ; i++) { + res = res.replaceAll(String.format("#T%d", i), types[i].asString()); + } + return res; + } + } + + 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 (CastKind ck : CastKind.values()) { + for (TypeKind t1 : TypeKind.values()) { + for (ArrayKind ak1 : ArrayKind.values()) { + Type typ1 = new Type(t1, ak1); + if (ck.nBounds == 1) { + new IntersectionTypeParserTest(ck, typ1).run(comp, fm); + continue; + } + for (TypeKind t2 : TypeKind.values()) { + for (ArrayKind ak2 : ArrayKind.values()) { + Type typ2 = new Type(t2, ak2); + if (ck.nBounds == 2) { + new IntersectionTypeParserTest(ck, typ1, typ2).run(comp, fm); + continue; + } + for (TypeKind t3 : TypeKind.values()) { + for (ArrayKind ak3 : ArrayKind.values()) { + Type typ3 = new Type(t3, ak3); + new IntersectionTypeParserTest(ck, typ1, typ2, typ3).run(comp, fm); + } + } + } + } + } + } + } + System.out.println("Total check executed: " + checkCount); + } + + CastKind ck; + Type[] types; + JavaSource source; + DiagnosticChecker diagChecker; + + IntersectionTypeParserTest(CastKind ck, Type... types) { + this.ck = ck; + this.types = types; + this.source = new JavaSource(); + this.diagChecker = new DiagnosticChecker(); + } + + class JavaSource extends SimpleJavaFileObject { + + String bodyTemplate = "class Test {\n" + + " void test() {\n" + + " Object o = #Cnull;\n" + + " } }"; + + String source = ""; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + source += bodyTemplate.replaceAll("#C", ck.asString(types)); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } + + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { + checkCount++; + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, + Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source)); + ct.parse(); + if (diagChecker.errorFound) { + throw new Error("Unexpected parser error for source:\n" + + source.getCharContent(true)); + } + } + + static class DiagnosticChecker implements javax.tools.DiagnosticListener { + + boolean errorFound; + + public void report(Diagnostic diagnostic) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + errorFound = true; + } + } + } +} diff --git a/langtools/test/tools/javac/cast/intersection/model/Check.java b/langtools/test/tools/javac/cast/intersection/model/Check.java new file mode 100644 index 00000000000..d47a6fd792f --- /dev/null +++ b/langtools/test/tools/javac/cast/intersection/model/Check.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +/** + * Annotation used by ModelChecker to mark the class whose model is to be checked + */ +@interface Check {} diff --git a/langtools/test/tools/javac/cast/intersection/model/IntersectionTypeInfo.java b/langtools/test/tools/javac/cast/intersection/model/IntersectionTypeInfo.java new file mode 100644 index 00000000000..bed6fc023a2 --- /dev/null +++ b/langtools/test/tools/javac/cast/intersection/model/IntersectionTypeInfo.java @@ -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. + */ + +/** + * Used by ModelChecker to validate the modeling information of a union type. + */ +@interface IntersectionTypeInfo { + String[] value(); +} diff --git a/langtools/test/tools/javac/cast/intersection/model/Member.java b/langtools/test/tools/javac/cast/intersection/model/Member.java new file mode 100644 index 00000000000..ee14474e74d --- /dev/null +++ b/langtools/test/tools/javac/cast/intersection/model/Member.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +import javax.lang.model.element.ElementKind; + +/** + * Annotation used by ModelChecker to mark a member that is to be checked + */ +@interface Member { + ElementKind value(); +} diff --git a/langtools/test/tools/javac/cast/intersection/model/Model01.java b/langtools/test/tools/javac/cast/intersection/model/Model01.java new file mode 100644 index 00000000000..1809d6228d2 --- /dev/null +++ b/langtools/test/tools/javac/cast/intersection/model/Model01.java @@ -0,0 +1,52 @@ +/* + * 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 8002099 + * @summary Add support for intersection types in cast expression + * @library ../../../lib + * @build JavacTestingAbstractProcessor ModelChecker + * @compile -XDallowIntersectionTypes -processor ModelChecker Model01.java + */ + +import javax.lang.model.element.ElementKind; + +@Check +class Test { + + interface A { + @Member(ElementKind.METHOD) + public void m1(); + } + + interface B { + @Member(ElementKind.METHOD) + public void m2(); + } + + void test(){ + @IntersectionTypeInfo({"java.lang.Object", "Test.A", "Test.B"}) + Object o = (A & B)null; + } +} diff --git a/langtools/test/tools/javac/cast/intersection/model/ModelChecker.java b/langtools/test/tools/javac/cast/intersection/model/ModelChecker.java new file mode 100644 index 00000000000..1486d21bf1b --- /dev/null +++ b/langtools/test/tools/javac/cast/intersection/model/ModelChecker.java @@ -0,0 +1,153 @@ +/* + * 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. + */ + +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.TypeCastTree; +import com.sun.source.tree.VariableTree; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import com.sun.source.util.TreePath; +import com.sun.tools.javac.tree.JCTree.JCExpression; + +import java.util.Set; + +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.IntersectionType; +import javax.lang.model.type.UnknownTypeException; +import javax.lang.model.util.SimpleTypeVisitor6; +import javax.lang.model.util.SimpleTypeVisitor7; + +@SupportedAnnotationTypes("Check") +public class ModelChecker extends JavacTestingAbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) + return true; + + Trees trees = Trees.instance(processingEnv); + + TypeElement testAnno = elements.getTypeElement("Check"); + for (Element elem: roundEnv.getElementsAnnotatedWith(testAnno)) { + TreePath p = trees.getPath(elem); + new IntersectionCastTester(trees).scan(p, null); + } + return true; + } + + class IntersectionCastTester extends TreePathScanner { + Trees trees; + + public IntersectionCastTester(Trees trees) { + super(); + this.trees = trees; + } + + @Override + public Void visitVariable(VariableTree node, Void p) { + + TreePath varPath = new TreePath(getCurrentPath(), node); + Element v = trees.getElement(varPath); + + IntersectionTypeInfo it = v.getAnnotation(IntersectionTypeInfo.class); + assertTrue(it != null, "IntersectionType annotation must be present"); + + ExpressionTree varInit = node.getInitializer(); + assertTrue(varInit != null && varInit.getKind() == Tree.Kind.TYPE_CAST, + "variable must have be initialized to an expression containing an intersection type cast"); + + TypeMirror t = ((JCExpression)((TypeCastTree)varInit).getType()).type; + + validateIntersectionTypeInfo(t, it); + + for (Element e2 : types.asElement(t).getEnclosedElements()) { + assertTrue(false, "an intersection type has no declared members"); + } + + for (Element e2 : elements.getAllMembers((TypeElement)types.asElement(t))) { + Member m = e2.getAnnotation(Member.class); + if (m != null) { + assertTrue(e2.getKind() == m.value(), "Expected " + m.value() + " - found " + e2.getKind()); + } + } + + assertTrue(assertionCount == 10, "Expected 10 assertions - found " + assertionCount); + return super.visitVariable(node, p); + } + } + + private void validateIntersectionTypeInfo(TypeMirror expectedIntersectionType, IntersectionTypeInfo it) { + + assertTrue(expectedIntersectionType.getKind() == TypeKind.INTERSECTION, "INTERSECTION kind expected"); + + try { + new SimpleTypeVisitor6(){}.visit(expectedIntersectionType); + throw new RuntimeException("Expected UnknownTypeException not thrown."); + } catch (UnknownTypeException ute) { + ; // Expected + } + + try { + new SimpleTypeVisitor7(){}.visit(expectedIntersectionType); + throw new RuntimeException("Expected UnknownTypeException not thrown."); + } catch (UnknownTypeException ute) { + ; // Expected + } + + IntersectionType intersectionType = new SimpleTypeVisitor(){ + @Override + protected IntersectionType defaultAction(TypeMirror e, Void p) {return null;} + + @Override + public IntersectionType visitIntersection(IntersectionType t, Void p) {return t;} + }.visit(expectedIntersectionType); + assertTrue(intersectionType != null, "Must get a non-null intersection type."); + + assertTrue(it.value().length == intersectionType.getBounds().size(), "Cardinalities do not match"); + + String[] typeNames = it.value(); + for(int i = 0; i < typeNames.length; i++) { + TypeMirror typeFromAnnotation = nameToType(typeNames[i]); + assertTrue(types.isSameType(typeFromAnnotation, intersectionType.getBounds().get(i)), + "Types were not equal."); + } + } + + private TypeMirror nameToType(String name) { + return elements.getTypeElement(name).asType(); + } + + private static void assertTrue(boolean cond, String msg) { + assertionCount++; + if (!cond) + throw new AssertionError(msg); + } + + static int assertionCount = 0; +} diff --git a/langtools/test/tools/javac/diags/examples/IntersectionTypesInCastNotSupported.java b/langtools/test/tools/javac/diags/examples/IntersectionTypesInCastNotSupported.java new file mode 100644 index 00000000000..8126a354249 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/IntersectionTypesInCastNotSupported.java @@ -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.intersection.types.in.cast.not.supported.in.source +// options: -source 7 -Xlint:-options + +interface IntersectionTypesInCastNotSupported { + Object o = (A & B)null; +} diff --git a/langtools/test/tools/javac/diags/examples/SecondaryBoundMustBeMarkerIntf.java b/langtools/test/tools/javac/diags/examples/SecondaryBoundMustBeMarkerIntf.java new file mode 100644 index 00000000000..2520f8fb00c --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/SecondaryBoundMustBeMarkerIntf.java @@ -0,0 +1,30 @@ +/* + * 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.prob.found.req +// key: compiler.misc.secondary.bound.must.be.marker.intf +// options: -XDallowIntersectionTypes + +class SecondaryBoundMustBeMarkerInterface { + Runnable r = (Runnable & Comparable)()->{}; +} diff --git a/langtools/test/tools/javac/lambda/Intersection01.java b/langtools/test/tools/javac/lambda/Intersection01.java new file mode 100644 index 00000000000..a04950eaff5 --- /dev/null +++ b/langtools/test/tools/javac/lambda/Intersection01.java @@ -0,0 +1,42 @@ +/* + * 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 8002099 + * @summary Add support for intersection types in cast expression + * @compile/fail/ref=Intersection01.out -XDallowIntersectionTypes -XDrawDiagnostics Intersection01.java + */ +class Intersection01 { + + interface SAM { + void m(); + } + + Object o1 = (java.io.Serializable & SAM)()->{}; + Object o2 = (SAM & java.io.Serializable)()->{}; + Object o3 = (java.io.Serializable & SAM)Intersection01::m; + Object o4 = (SAM & java.io.Serializable)Intersection01::m; + + static void m() { } +} diff --git a/langtools/test/tools/javac/lambda/Intersection01.out b/langtools/test/tools/javac/lambda/Intersection01.out new file mode 100644 index 00000000000..122935b0913 --- /dev/null +++ b/langtools/test/tools/javac/lambda/Intersection01.out @@ -0,0 +1,3 @@ +Intersection01.java:36:45: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf.1: (compiler.misc.no.abstracts: kindname.interface, java.io.Serializable)) +Intersection01.java:38:45: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf.1: (compiler.misc.no.abstracts: kindname.interface, java.io.Serializable)) +2 errors diff --git a/langtools/test/tools/javac/lambda/LambdaParserTest.java b/langtools/test/tools/javac/lambda/LambdaParserTest.java index e208e792f8e..fdc56f6cb1c 100644 --- a/langtools/test/tools/javac/lambda/LambdaParserTest.java +++ b/langtools/test/tools/javac/lambda/LambdaParserTest.java @@ -90,9 +90,14 @@ public class LambdaParserTest { enum LambdaParameterKind { IMPLICIT(""), EXPLIICT_SIMPLE("A"), + EXPLIICT_SIMPLE_ARR1("A[]"), + EXPLIICT_SIMPLE_ARR2("A[][]"), EXPLICIT_VARARGS("A..."), EXPLICIT_GENERIC1("A"), - EXPLICIT_GENERIC3("A"); + EXPLICIT_GENERIC2("A"), + EXPLICIT_GENERIC2_VARARGS("A..."), + EXPLICIT_GENERIC2_ARR1("A[]"), + EXPLICIT_GENERIC2_ARR2("A[][]"); String parameterType; @@ -103,6 +108,11 @@ public class LambdaParserTest { boolean explicit() { return this != IMPLICIT; } + + boolean isVarargs() { + return this == EXPLICIT_VARARGS || + this == EXPLICIT_GENERIC2_VARARGS; + } } enum ModifierKind { @@ -253,7 +263,7 @@ public class LambdaParserTest { if (lk.arity() == 2 && (pk1.explicit() != pk2.explicit() || - pk1 == LambdaParameterKind.EXPLICIT_VARARGS)) { + pk1.isVarargs())) { errorExpected = true; } diff --git a/langtools/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java b/langtools/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java new file mode 100644 index 00000000000..560aae32e4a --- /dev/null +++ b/langtools/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java @@ -0,0 +1,294 @@ +/* + * 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 8002099 + * @summary Add support for intersection types in cast expression + */ + +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import java.net.URI; +import java.util.Arrays; +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 IntersectionTargetTypeTest { + + static int checkCount = 0; + + enum BoundKind { + INTF, + CLASS, + SAM, + ZAM; + } + + enum MethodKind { + NONE, + ABSTRACT, + DEFAULT; + } + + enum TypeKind { + A("interface A { }\n", "A", BoundKind.ZAM), + B("interface B { default void m() { } }\n", "B", BoundKind.ZAM), + C("interface C { void m(); }\n", "C", BoundKind.SAM), + D("interface D extends B { }\n", "D", BoundKind.ZAM), + E("interface E extends C { }\n", "E", BoundKind.SAM), + F("interface F extends C { void g(); }\n", "F", BoundKind.INTF), + G("interface G extends B { void g(); }\n", "G", BoundKind.SAM), + H("interface H extends A { void g(); }\n", "H", BoundKind.SAM), + OBJECT("", "Object", BoundKind.CLASS), + STRING("", "String", BoundKind.CLASS); + + String declStr; + String typeStr; + BoundKind boundKind; + + private TypeKind(String declStr, String typeStr, BoundKind boundKind) { + this.declStr = declStr; + this.typeStr = typeStr; + this.boundKind = boundKind; + } + + boolean compatibleSupertype(TypeKind tk) { + if (tk == this) return true; + switch (tk) { + case B: + return this != C && this != E && this != F; + case C: + return this != B && this != C && this != D && this != G; + case D: return compatibleSupertype(B); + case E: + case F: return compatibleSupertype(C); + case G: return compatibleSupertype(B); + case H: return compatibleSupertype(A); + default: + return true; + } + } + } + + enum CastKind { + ONE_ARY("(#B0)", 1), + TWO_ARY("(#B0 & #B1)", 2), + THREE_ARY("(#B0 & #B1 & #B2)", 3); + + String castTemplate; + int nbounds; + + CastKind(String castTemplate, int nbounds) { + this.castTemplate = castTemplate; + this.nbounds = nbounds; + } + } + + enum ExpressionKind { + LAMBDA("()->{}", true), + MREF("this::m", true), + //COND_LAMBDA("(true ? ()->{} : ()->{})", true), re-enable if spec allows this + //COND_MREF("(true ? this::m : this::m)", true), + STANDALONE("null", false); + + String exprString; + boolean isFunctional; + + private ExpressionKind(String exprString, boolean isFunctional) { + this.exprString = exprString; + this.isFunctional = isFunctional; + } + } + + static class CastInfo { + CastKind kind; + TypeKind[] types; + + CastInfo(CastKind kind, TypeKind... types) { + this.kind = kind; + this.types = types; + } + + String getCast() { + String temp = kind.castTemplate; + for (int i = 0; i < kind.nbounds ; i++) { + temp = temp.replace(String.format("#B%d", i), types[i].typeStr); + } + return temp; + } + + boolean wellFormed() { + //check for duplicate types + for (int i = 0 ; i < types.length ; i++) { + for (int j = 0 ; j < types.length ; j++) { + if (i != j && types[i] == types[j]) { + return false; + } + } + } + //check that classes only appear as first bound + boolean classOk = true; + for (int i = 0 ; i < types.length ; i++) { + if (types[i].boundKind == BoundKind.CLASS && + !classOk) { + return false; + } + classOk = false; + } + //check that supertypes are mutually compatible + for (int i = 0 ; i < types.length ; i++) { + for (int j = 0 ; j < types.length ; j++) { + if (!types[i].compatibleSupertype(types[j]) && i != j) { + return false; + } + } + } + return true; + } + } + + 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 (CastInfo cInfo : allCastInfo()) { + for (ExpressionKind ek : ExpressionKind.values()) { + new IntersectionTargetTypeTest(cInfo, ek).run(comp, fm); + } + } + System.out.println("Total check executed: " + checkCount); + } + + static List allCastInfo() { + ListBuffer buf = ListBuffer.lb(); + for (CastKind kind : CastKind.values()) { + for (TypeKind b1 : TypeKind.values()) { + if (kind.nbounds == 1) { + buf.append(new CastInfo(kind, b1)); + continue; + } else { + for (TypeKind b2 : TypeKind.values()) { + if (kind.nbounds == 2) { + buf.append(new CastInfo(kind, b1, b2)); + continue; + } else { + for (TypeKind b3 : TypeKind.values()) { + buf.append(new CastInfo(kind, b1, b2, b3)); + } + } + } + } + } + } + return buf.toList(); + } + + CastInfo cInfo; + ExpressionKind ek; + JavaSource source; + DiagnosticChecker diagChecker; + + IntersectionTargetTypeTest(CastInfo cInfo, ExpressionKind ek) { + this.cInfo = cInfo; + this.ek = ek; + this.source = new JavaSource(); + this.diagChecker = new DiagnosticChecker(); + } + + class JavaSource extends SimpleJavaFileObject { + + String bodyTemplate = "class Test {\n" + + " void m() { }\n" + + " void test() {\n" + + " Object o = #C#E;\n" + + " } }"; + + String source = ""; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + for (TypeKind tk : TypeKind.values()) { + source += tk.declStr; + } + source += bodyTemplate.replaceAll("#C", cInfo.getCast()).replaceAll("#E", ek.exprString); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } + + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, + Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source)); + try { + ct.analyze(); + } catch (Throwable ex) { + throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true)); + } + check(); + } + + void check() { + checkCount++; + + boolean errorExpected = !cInfo.wellFormed(); + + if (ek.isFunctional) { + //first bound must be a SAM + errorExpected |= cInfo.types[0].boundKind != BoundKind.SAM; + if (cInfo.types.length > 1) { + //additional bounds must be ZAMs + for (int i = 1; i < cInfo.types.length; i++) { + errorExpected |= cInfo.types[i].boundKind != BoundKind.ZAM; + } + } + } + + if (errorExpected != diagChecker.errorFound) { + throw new Error("invalid diagnostics for source:\n" + + source.getCharContent(true) + + "\nFound error: " + diagChecker.errorFound + + "\nExpected error: " + errorExpected); + } + } + + static class DiagnosticChecker implements javax.tools.DiagnosticListener { + + boolean errorFound; + + public void report(Diagnostic diagnostic) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + errorFound = true; + } + } + } +} From 01dc08a587e4e5ac42d5ab882537582eae69b808 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Tue, 4 Dec 2012 17:19:42 +0000 Subject: [PATCH 10/10] 8004360: regression test DefaultMethodRegressionTests fails in langtools Ignore broken failing test Reviewed-by: jjg --- .../defaultMethodExecution/DefaultMethodRegressionTests.java | 1 + 1 file changed, 1 insertion(+) rename langtools/test/tools/javac/{ => defaultMethods}/defaultMethodExecution/DefaultMethodRegressionTests.java (99%) diff --git a/langtools/test/tools/javac/defaultMethodExecution/DefaultMethodRegressionTests.java b/langtools/test/tools/javac/defaultMethods/defaultMethodExecution/DefaultMethodRegressionTests.java similarity index 99% rename from langtools/test/tools/javac/defaultMethodExecution/DefaultMethodRegressionTests.java rename to langtools/test/tools/javac/defaultMethods/defaultMethodExecution/DefaultMethodRegressionTests.java index e22f44b01d3..124e39c5d1e 100644 --- a/langtools/test/tools/javac/defaultMethodExecution/DefaultMethodRegressionTests.java +++ b/langtools/test/tools/javac/defaultMethods/defaultMethodExecution/DefaultMethodRegressionTests.java @@ -25,6 +25,7 @@ /** * @test + * @ignore 8004360 * @bug 8003639 * @summary convert lambda testng tests to jtreg and add them * @run testng DefaultMethodRegressionTests