8031744: Annotations on many Language Model elements are not returned
authorjjg
Tue, 07 Apr 2015 11:04:29 -0700
changeset 29842 826ac2519523
parent 29782 85d4f5471a74
child 29843 f7bd3ddc9292
8031744: Annotations on many Language Model elements are not returned Reviewed-by: jfranck, mcimadamore, emc, jlahoda, jjg Contributed-by: joel.franck@oracle.com, maurizio.cimadamore@oracle.com
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeMetadata.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/UninitializedType.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java
langtools/test/tools/javac/annotations/typeAnnotations/api/AnnotatedArrayOrder.java
langtools/test/tools/javac/annotations/typeAnnotations/newlocations/BasicTest.java
langtools/test/tools/javac/lib/DPrinter.java
langtools/test/tools/javac/processing/model/type/BasicAnnoTests.java
langtools/test/tools/javac/warnings/6747671/T6747671.out
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Tue Apr 07 11:04:29 2015 -0700
@@ -696,7 +696,8 @@
     @DefinedBy(Api.COMPILER_TREE)
     public TypeMirror getTypeMirror(TreePath path) {
         Tree t = path.getLeaf();
-        return ((JCTree)t).type;
+        Type ty = ((JCTree)t).type;
+        return ty == null ? null : ty.stripMetadataIfNeeded();
     }
 
     @DefinedBy(Api.COMPILER_TREE)
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, 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
@@ -25,7 +25,8 @@
 
 package com.sun.tools.javac.code;
 
-import java.io.*;
+import java.io.IOException;
+import java.io.File;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Map;
@@ -38,16 +39,15 @@
 import javax.tools.StandardJavaFileManager;
 
 import com.sun.tools.javac.code.Scope.WriteableScope;
-import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.Completer;
 import com.sun.tools.javac.code.Symbol.CompletionFailure;
 import com.sun.tools.javac.code.Symbol.PackageSymbol;
 import com.sun.tools.javac.code.Symbol.TypeSymbol;
 import com.sun.tools.javac.comp.Annotate;
+import com.sun.tools.javac.comp.Enter;
 import com.sun.tools.javac.file.JRTIndex;
 import com.sun.tools.javac.file.JavacFileManager;
-import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
 import com.sun.tools.javac.jvm.ClassReader;
 import com.sun.tools.javac.jvm.Profile;
 import com.sun.tools.javac.util.*;
@@ -75,7 +75,7 @@
 
     ClassReader reader;
 
-    Annotate annotate;
+    private final Annotate annotate;
 
     /** Switch: verbose output.
      */
@@ -272,18 +272,13 @@
             try {
                 ClassSymbol c = (ClassSymbol) sym;
                 dependencies.push(c, CompletionCause.CLASS_READER);
+                annotate.blockAnnotations();
                 c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
-                annotate.enterStart();
-                try {
-                    completeOwners(c.owner);
-                    completeEnclosing(c);
-                } finally {
-                    // The flush needs to happen only after annotations
-                    // are filled in.
-                    annotate.enterDoneWithoutFlush();
-                }
+                completeOwners(c.owner);
+                completeEnclosing(c);
                 fillIn(c);
             } finally {
+                annotate.unblockAnnotationsNoFlush();
                 dependencies.pop();
             }
         } else if (sym.kind == PCK) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, 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
@@ -33,6 +33,11 @@
 import javax.lang.model.element.*;
 import javax.tools.JavaFileObject;
 
+import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.TypeAnnotations.AnnotationType;
+import com.sun.tools.javac.code.TypeMetadata.Entry;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.comp.Attr;
@@ -738,6 +743,13 @@
             return list;
         }
 
+        public AnnotationTypeMetadata getAnnotationTypeMetadata() {
+            Assert.error("Only on ClassSymbol");
+            return null; //unreachable
+        }
+
+        public boolean isAnnotationType() { return false; }
+
         @Override
         public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
             return v.visitTypeSymbol(this, p);
@@ -958,6 +970,9 @@
          */
         public Pool pool;
 
+        /** the annotation metadata attached to this class */
+        private AnnotationTypeMetadata annotationTypeMetadata;
+
         public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
             super(TYP, flags, name, type, owner);
             this.members_field = null;
@@ -966,6 +981,7 @@
             this.sourcefile = null;
             this.classfile = null;
             this.pool = null;
+            this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
         }
 
         public ClassSymbol(long flags, Name name, Symbol owner) {
@@ -1202,8 +1218,24 @@
                 t.all_interfaces_field = null;
             }
             metadata = null;
+            annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
+        }
+
+        @Override
+        public AnnotationTypeMetadata getAnnotationTypeMetadata() {
+            return annotationTypeMetadata;
         }
 
+        @Override
+        public boolean isAnnotationType() {
+            return (flags_field & Flags.ANNOTATION) != 0;
+        }
+
+        public void setAnnotationTypeMetadata(AnnotationTypeMetadata a) {
+            Assert.checkNonNull(a);
+            Assert.check(!annotationTypeMetadata.isMetadataForAnnotationType());
+            this.annotationTypeMetadata = a;
+        }
     }
 
 
@@ -1360,7 +1392,7 @@
         /** The names of the parameters */
         public List<Name> savedParameterNames;
 
-        /** For an attribute field accessor, its default value if any.
+        /** For an annotation type element, its default value if any.
          *  The value is null if none appeared in the method
          *  declaration.
          */
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, 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
@@ -36,7 +36,7 @@
 import javax.lang.model.type.*;
 
 import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.code.Types.MapVisitor;
+import com.sun.tools.javac.code.TypeMetadata.Entry;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
 import static com.sun.tools.javac.code.BoundKind.*;
@@ -87,11 +87,10 @@
         return metadata;
     }
 
-    public TypeMetadata.Element getMetadataOfKind(final TypeMetadata.Element.Kind kind) {
+    public Entry getMetadataOfKind(final Entry.Kind kind) {
         return metadata != null ? metadata.get(kind) : null;
     }
 
-
     /** Constant type: no type at all. */
     public static final JCNoType noType = new JCNoType() {
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
@@ -238,7 +237,12 @@
             List<Type> typarams = t.getTypeArguments();
             List<Type> typarams1 = visit(typarams, s);
             if (outer1 == outer && typarams1 == typarams) return t;
-            else return new ClassType(outer1, typarams1, t.tsym, t.metadata);
+            else return new ClassType(outer1, typarams1, t.tsym, t.metadata) {
+                @Override
+                protected boolean needsStripping() {
+                    return true;
+                }
+            };
         }
 
         @Override
@@ -249,7 +253,12 @@
             if (t == wt.type)
                 return wt;
             else
-                return new WildcardType(t, wt.kind, wt.tsym, wt.bound, wt.metadata);
+                return new WildcardType(t, wt.kind, wt.tsym, wt.bound, wt.metadata) {
+                    @Override
+                    protected boolean needsStripping() {
+                        return true;
+                    }
+                };
         }
 
         @Override
@@ -257,7 +266,12 @@
             Type elemtype = t.elemtype;
             Type elemtype1 = visit(elemtype, s);
             if (elemtype1 == elemtype) return t;
-            else return new ArrayType(elemtype1, t.tsym, t.metadata);
+            else return new ArrayType(elemtype1, t.tsym, t.metadata) {
+                @Override
+                protected boolean needsStripping() {
+                    return true;
+                }
+            };
         }
 
         @Override
@@ -271,7 +285,12 @@
             if (argtypes1 == argtypes &&
                 restype1 == restype &&
                 thrown1 == thrown) return t;
-            else return new MethodType(argtypes1, restype1, thrown1, t.tsym);
+            else return new MethodType(argtypes1, restype1, thrown1, t.tsym) {
+                @Override
+                protected boolean needsStripping() {
+                    return true;
+                }
+            };
         }
 
         @Override
@@ -313,38 +332,78 @@
     }
 
     /**
-     * Create a new type with exactly the given metadata.  The
-     * argument is guaranteed to always be non-empty, and should have
-     * already been copied/combined with the current type's metadata.
-     * This is used internally by other methods.
-     *
+     * Returns the original version of this type, before metadata were added. This routine is meant
+     * for internal use only (i.e. {@link Type#equalsIgnoreMetadata(Type)}, {@link Type#stripMetadata});
+     * it should not be used outside this class.
      */
-    public abstract Type clone(TypeMetadata md);
+    protected Type typeNoMetadata() {
+        return metadata == TypeMetadata.EMPTY ? this : baseType();
+    }
 
-    public Type combineMetadata(final TypeMetadata.Element md) {
-        return clone(metadata.combine(md));
+    /**
+     * Create a new copy of this type but with the specified TypeMetadata.
+     */
+    public abstract Type cloneWithMetadata(TypeMetadata metadata);
+
+    /**
+     * Does this type require annotation stripping for API clients?
+     */
+    protected boolean needsStripping() {
+        return false;
     }
 
+    /**
+     * Strip all metadata associated with this type - this could return a new clone of the type.
+     * This routine is only used to present the correct annotated types back to the users when types
+     * are accessed through compiler APIs; it should not be used anywhere in the compiler internals
+     * as doing so might result in performance penalties.
+     */
+    public Type stripMetadataIfNeeded() {
+        return needsStripping() ?
+                accept(stripMetadata, null) :
+                this;
+    }
+    //where
+        private final static TypeMapping<Void> stripMetadata = new TypeMapping<Void>() {
+            @Override
+            public Type visitClassType(ClassType t, Void aVoid) {
+                return super.visitClassType((ClassType)t.typeNoMetadata(), aVoid);
+            }
+
+            @Override
+            public Type visitArrayType(ArrayType t, Void aVoid) {
+                return super.visitArrayType((ArrayType)t.typeNoMetadata(), aVoid);
+            }
+
+            @Override
+            public Type visitTypeVar(TypeVar t, Void aVoid) {
+                return super.visitTypeVar((TypeVar)t.typeNoMetadata(), aVoid);
+            }
+
+            @Override
+            public Type visitWildcardType(WildcardType wt, Void aVoid) {
+                return super.visitWildcardType((WildcardType)wt.typeNoMetadata(), aVoid);
+            }
+        };
+
     public Type annotatedType(final List<Attribute.TypeCompound> annos) {
-        final TypeMetadata.Element annoMetadata = new TypeMetadata.Annotations(annos);
-        return combineMetadata(annoMetadata);
+        final Entry annoMetadata = new TypeMetadata.Annotations(annos);
+        return cloneWithMetadata(metadata.combine(annoMetadata));
     }
 
     public boolean isAnnotated() {
         final TypeMetadata.Annotations metadata =
-            (TypeMetadata.Annotations)getMetadataOfKind(TypeMetadata.Element.Kind.ANNOTATIONS);
+            (TypeMetadata.Annotations)getMetadataOfKind(Entry.Kind.ANNOTATIONS);
 
         return null != metadata && !metadata.getAnnotations().isEmpty();
     }
 
-    private static final List<Attribute.TypeCompound> noAnnotations = List.nil();
-
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
     public List<Attribute.TypeCompound> getAnnotationMirrors() {
         final TypeMetadata.Annotations metadata =
-            (TypeMetadata.Annotations)getMetadataOfKind(TypeMetadata.Element.Kind.ANNOTATIONS);
+            (TypeMetadata.Annotations)getMetadataOfKind(Entry.Kind.ANNOTATIONS);
 
-        return metadata == null ? noAnnotations : metadata.getAnnotations();
+        return metadata == null ? List.nil() : metadata.getAnnotations();
     }
 
 
@@ -431,13 +490,15 @@
     }
 
     /**
-     * This method is analogous to isSameType, but weaker, since we
-     * never complete classes. Where isSameType would complete a
-     * class, equals assumes that the two types are different.
+     * Override this method with care. For most Type instances this should behave as ==.
      */
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
     public boolean equals(Object t) {
-        return super.equals(t);
+        return this == t;
+    }
+
+    public boolean equalsIgnoreMetadata(Type t) {
+        return typeNoMetadata().equals(t.typeNoMetadata());
     }
 
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
@@ -547,7 +608,7 @@
      * Does this type contain occurrences of type t?
      */
     public boolean contains(Type t) {
-        return t == this;
+        return t.equalsIgnoreMetadata(this);
     }
 
     public static boolean contains(List<Type> ts, Type t) {
@@ -615,19 +676,21 @@
         TypeTag tag;
 
         public JCPrimitiveType(TypeTag tag, TypeSymbol tsym) {
-            this(tag, tsym, TypeMetadata.empty);
+            this(tag, tsym, TypeMetadata.EMPTY);
         }
 
-        private JCPrimitiveType(TypeTag tag, TypeSymbol tsym,
-                                TypeMetadata metadata) {
+        private JCPrimitiveType(TypeTag tag, TypeSymbol tsym, TypeMetadata metadata) {
             super(tsym, metadata);
             this.tag = tag;
             Assert.check(tag.isPrimitive);
         }
 
         @Override
-        public JCPrimitiveType clone(TypeMetadata md) {
-            return new JCPrimitiveType(tag, tsym, md);
+        public JCPrimitiveType cloneWithMetadata(TypeMetadata md) {
+            return new JCPrimitiveType(tag, tsym, md) {
+                @Override
+                public Type baseType() { return JCPrimitiveType.this.baseType(); }
+            };
         }
 
         @Override
@@ -740,7 +803,7 @@
         }
 
         public WildcardType(Type type, BoundKind kind, TypeSymbol tsym) {
-            this(type, kind, tsym, null, TypeMetadata.empty);
+            this(type, kind, tsym, null, TypeMetadata.EMPTY);
         }
 
         public WildcardType(Type type, BoundKind kind, TypeSymbol tsym,
@@ -750,7 +813,7 @@
 
         public WildcardType(Type type, BoundKind kind, TypeSymbol tsym,
                             TypeVar bound) {
-            this(type, kind, tsym, bound, TypeMetadata.empty);
+            this(type, kind, tsym, bound, TypeMetadata.EMPTY);
         }
 
         public WildcardType(Type type, BoundKind kind, TypeSymbol tsym,
@@ -762,8 +825,11 @@
         }
 
         @Override
-        public WildcardType clone(TypeMetadata md) {
-            return new WildcardType(type, kind, tsym, bound, md);
+        public WildcardType cloneWithMetadata(TypeMetadata md) {
+            return new WildcardType(type, kind, tsym, bound, md) {
+                @Override
+                public Type baseType() { return WildcardType.this.baseType(); }
+            };
         }
 
         @Override
@@ -883,7 +949,7 @@
         public List<Type> all_interfaces_field;
 
         public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym) {
-            this(outer, typarams, tsym, TypeMetadata.empty);
+            this(outer, typarams, tsym, TypeMetadata.EMPTY);
         }
 
         public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym,
@@ -897,13 +963,11 @@
         }
 
         @Override
-        public ClassType clone(TypeMetadata md) {
-            final ClassType out =
-                new ClassType(outer_field, typarams_field, tsym, md);
-            out.allparams_field = allparams_field;
-            out.supertype_field = supertype_field;
-            out.interfaces_field = interfaces_field;
-            return out;
+        public ClassType cloneWithMetadata(TypeMetadata md) {
+            return new ClassType(outer_field, typarams_field, tsym, md) {
+                @Override
+                public Type baseType() { return ClassType.this.baseType(); }
+            };
         }
 
         @Override
@@ -935,14 +999,16 @@
         @DefinedBy(Api.LANGUAGE_MODEL)
         public String toString() {
             StringBuilder buf = new StringBuilder();
-            appendAnnotationsString(buf);
             if (getEnclosingType().hasTag(CLASS) && tsym.owner.kind == TYP) {
                 buf.append(getEnclosingType().toString());
                 buf.append(".");
+                appendAnnotationsString(buf);
                 buf.append(className(tsym, false));
             } else {
+                appendAnnotationsString(buf);
                 buf.append(className(tsym, true));
             }
+
             if (getTypeArguments().nonEmpty()) {
                 buf.append('<');
                 buf.append(getTypeArguments().toString());
@@ -1050,7 +1116,7 @@
 
         public boolean contains(Type elem) {
             return
-                elem == this
+                elem.equalsIgnoreMetadata(this)
                 || (isParameterized()
                     && (getEnclosingType().contains(elem) || contains(getTypeArguments(), elem)))
                 || (isCompound()
@@ -1073,10 +1139,6 @@
     }
 
     public static class ErasedClassType extends ClassType {
-        public ErasedClassType(Type outer, TypeSymbol tsym) {
-            super(outer, List.<Type>nil(), tsym);
-        }
-
         public ErasedClassType(Type outer, TypeSymbol tsym,
                                TypeMetadata metadata) {
             super(outer, List.<Type>nil(), tsym, metadata);
@@ -1104,7 +1166,7 @@
         }
 
         @Override
-        public UnionClassType clone(TypeMetadata md) {
+        public UnionClassType cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to a union type");
         }
 
@@ -1155,7 +1217,7 @@
         }
 
         @Override
-        public IntersectionClassType clone(TypeMetadata md) {
+        public IntersectionClassType cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to an intersection type");
         }
 
@@ -1196,7 +1258,7 @@
         public Type elemtype;
 
         public ArrayType(Type elemtype, TypeSymbol arrayClass) {
-            this(elemtype, arrayClass, TypeMetadata.empty);
+            this(elemtype, arrayClass, TypeMetadata.EMPTY);
         }
 
         public ArrayType(Type elemtype, TypeSymbol arrayClass,
@@ -1205,9 +1267,18 @@
             this.elemtype = elemtype;
         }
 
+        public ArrayType(ArrayType that) {
+            //note: type metadata is deliberately shared here, as we want side-effects from annotation
+            //processing to flow from original array to the cloned array.
+            this(that.elemtype, that.tsym, that.getMetadata());
+        }
+
         @Override
-        public ArrayType clone(TypeMetadata md) {
-            return new ArrayType(elemtype, tsym, md);
+        public ArrayType cloneWithMetadata(TypeMetadata md) {
+            return new ArrayType(elemtype, tsym, md) {
+                @Override
+                public Type baseType() { return ArrayType.this.baseType(); }
+            };
         }
 
         @Override
@@ -1228,12 +1299,15 @@
             return sb.toString();
         }
 
-        @DefinedBy(Api.LANGUAGE_MODEL)
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
         public boolean equals(Object obj) {
-            return
-                this == obj ||
-                (obj instanceof ArrayType &&
-                 this.elemtype.equals(((ArrayType)obj).elemtype));
+            if (obj instanceof ArrayType) {
+                ArrayType that = (ArrayType)obj;
+                return this == that ||
+                        elemtype.equals(that.elemtype);
+            }
+
+            return false;
         }
 
         @DefinedBy(Api.LANGUAGE_MODEL)
@@ -1279,7 +1353,7 @@
         }
 
         public boolean contains(Type elem) {
-            return elem == this || elemtype.contains(elem);
+            return elem.equalsIgnoreMetadata(this) || elemtype.contains(elem);
         }
 
         public void complete() {
@@ -1318,14 +1392,14 @@
                           TypeSymbol methodClass) {
             // Presently no way to refer to a method type directly, so
             // we cannot put type annotations on it.
-            super(methodClass, TypeMetadata.empty);
+            super(methodClass, TypeMetadata.EMPTY);
             this.argtypes = argtypes;
             this.restype = restype;
             this.thrown = thrown;
         }
 
         @Override
-        public MethodType clone(TypeMetadata md) {
+        public MethodType cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to a method type");
         }
 
@@ -1370,7 +1444,7 @@
         }
 
         public boolean contains(Type elem) {
-            return elem == this || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem);
+            return elem.equalsIgnoreMetadata(this) || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem);
         }
 
         public MethodType asMethodType() { return this; }
@@ -1408,11 +1482,11 @@
 
         PackageType(TypeSymbol tsym) {
             // Package types cannot be annotated
-            super(tsym, TypeMetadata.empty);
+            super(tsym, TypeMetadata.EMPTY);
         }
 
         @Override
-        public PackageType clone(TypeMetadata md) {
+        public PackageType cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to a package type");
         }
 
@@ -1464,14 +1538,14 @@
         public Type lower;
 
         public TypeVar(Name name, Symbol owner, Type lower) {
-            super(null, TypeMetadata.empty);
+            super(null, TypeMetadata.EMPTY);
             tsym = new TypeVariableSymbol(0, name, this, owner);
-            this.bound = bound;
+            this.bound = null;
             this.lower = lower;
         }
 
         public TypeVar(TypeSymbol tsym, Type bound, Type lower) {
-            this(tsym, bound, lower, TypeMetadata.empty);
+            this(tsym, bound, lower, TypeMetadata.EMPTY);
         }
 
         public TypeVar(TypeSymbol tsym, Type bound, Type lower,
@@ -1482,8 +1556,11 @@
         }
 
         @Override
-        public TypeVar clone(TypeMetadata md) {
-            return new TypeVar(tsym, bound, lower, md);
+        public TypeVar cloneWithMetadata(TypeMetadata md) {
+            return new TypeVar(tsym, bound, lower, md) {
+                @Override
+                public Type baseType() { return TypeVar.this.baseType(); }
+            };
         }
 
         @Override
@@ -1566,8 +1643,11 @@
         }
 
         @Override
-        public CapturedType clone(TypeMetadata md) {
-            return new CapturedType(tsym, bound, bound, lower, wildcard, md);
+        public CapturedType cloneWithMetadata(TypeMetadata md) {
+            return new CapturedType(tsym, bound, bound, lower, wildcard, md) {
+                @Override
+                public Type baseType() { return CapturedType.this.baseType(); }
+            };
         }
 
         @Override
@@ -1597,7 +1677,7 @@
         public TypeTag tag;
 
         public DelegatedType(TypeTag tag, Type qtype) {
-            this(tag, qtype, TypeMetadata.empty);
+            this(tag, qtype, TypeMetadata.EMPTY);
         }
 
         public DelegatedType(TypeTag tag, Type qtype,
@@ -1635,7 +1715,7 @@
         }
 
         @Override
-        public ForAll clone(TypeMetadata md) {
+        public ForAll cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to a forall type");
         }
 
@@ -1785,7 +1865,7 @@
         }
 
         @Override
-        public UndetVar clone(TypeMetadata md) {
+        public UndetVar cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to an UndetVar type");
         }
 
@@ -1940,11 +2020,11 @@
             // Need to use List.nil(), because JCNoType constructor
             // gets called in static initializers in Type, where
             // noAnnotations is also defined.
-            super(null, TypeMetadata.empty);
+            super(null, TypeMetadata.EMPTY);
         }
 
         @Override
-        public JCNoType clone(TypeMetadata md) {
+        public JCNoType cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to a JCNoType");
         }
 
@@ -1973,11 +2053,11 @@
 
         public JCVoidType() {
             // Void cannot be annotated
-            super(null, TypeMetadata.empty);
+            super(null, TypeMetadata.EMPTY);
         }
 
         @Override
-        public JCVoidType clone(TypeMetadata md) {
+        public JCVoidType cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to a void type");
         }
 
@@ -2008,11 +2088,11 @@
     static class BottomType extends Type implements NullType {
         public BottomType() {
             // Bottom is a synthesized internal type, so it cannot be annotated
-            super(null, TypeMetadata.empty);
+            super(null, TypeMetadata.EMPTY);
         }
 
         @Override
-        public BottomType clone(TypeMetadata md) {
+        public BottomType cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to a bottom type");
         }
 
@@ -2077,8 +2157,11 @@
         }
 
         @Override
-        public ErrorType clone(TypeMetadata md) {
-            return new ErrorType(originalType, tsym, md);
+        public ErrorType cloneWithMetadata(TypeMetadata md) {
+            return new ErrorType(originalType, tsym, md) {
+                @Override
+                public Type baseType() { return ErrorType.this.baseType(); }
+            };
         }
 
         @Override
@@ -2145,11 +2228,11 @@
         public UnknownType() {
             // Unknown is a synthesized internal type, so it cannot be
             // annotated.
-            super(null, TypeMetadata.empty);
+            super(null, TypeMetadata.EMPTY);
         }
 
         @Override
-        public UnknownType clone(TypeMetadata md) {
+        public UnknownType cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to an unknown type");
         }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, 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
@@ -118,14 +118,10 @@
 
     public static final List<TypePathEntry> emptyPath = List.nil();
 
-    // NOTE: All of these will be converted to final fields eventually.
-
     public final TargetType type;
 
     // For generic/array types.
 
-    // This field is in the process of being made final.  Do not
-    // introduce new mutations.
     public List<TypePathEntry> location;
 
     // Tree position.
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, 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
@@ -31,6 +31,7 @@
 
 import javax.tools.JavaFileObject;
 
+import com.sun.tools.javac.code.Attribute.Array;
 import com.sun.tools.javac.code.Attribute.TypeCompound;
 import com.sun.tools.javac.code.Type.ArrayType;
 import com.sun.tools.javac.code.Type.CapturedType;
@@ -47,8 +48,8 @@
 import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntryKind;
 import com.sun.tools.javac.code.Symbol.VarSymbol;
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
 import com.sun.tools.javac.comp.Annotate;
-import com.sun.tools.javac.comp.Annotate.Worker;
 import com.sun.tools.javac.comp.Attr;
 import com.sun.tools.javac.comp.AttrContext;
 import com.sun.tools.javac.comp.Env;
@@ -71,7 +72,6 @@
 import com.sun.tools.javac.util.ListBuffer;
 import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.util.Names;
-import com.sun.tools.javac.util.Options;
 
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 
@@ -105,7 +105,6 @@
         syms = Symtab.instance(context);
         annotate = Annotate.instance(context);
         attr = Attr.instance(context);
-        Options options = Options.instance(context);
     }
 
     /**
@@ -113,12 +112,9 @@
      * determine the correct positions for type annotations.
      * This version only visits types in signatures and should be
      * called from MemberEnter.
-     * The method takes the Annotate object as parameter and
-     * adds an Annotate.Worker to the correct Annotate queue for
-     * later processing.
      */
     public void organizeTypeAnnotationsSignatures(final Env<AttrContext> env, final JCClassDecl tree) {
-        annotate.afterRepeated( new Worker() {
+        annotate.afterTypes(new Runnable() {
             @Override
             public void run() {
                 JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
@@ -129,11 +125,11 @@
                     log.useSource(oldSource);
                 }
             }
-        } );
+        });
     }
 
     public void validateTypeAnnotationsSignatures(final Env<AttrContext> env, final JCClassDecl tree) {
-        annotate.validate(new Worker() { //validate annotations
+        annotate.validate(new Runnable() { //validate annotations
             @Override
             public void run() {
                 JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
@@ -144,7 +140,7 @@
                     log.useSource(oldSource);
                 }
             }
-        } );
+        });
     }
 
     /**
@@ -155,101 +151,106 @@
         new TypeAnnotationPositions(false).scan(tree);
     }
 
-    public enum AnnotationType { DECLARATION, TYPE, BOTH }
+    public enum AnnotationType { DECLARATION, TYPE, NONE, BOTH }
+
+    public List<Attribute> annotationTargets(Attribute.Compound anno) {
+        Attribute.Compound atTarget = anno.type.tsym.getAnnotationTypeMetadata().getTarget();
+        if (atTarget == null) {
+            return null;
+        }
+
+        Attribute atValue = atTarget.member(names.value);
+        if (!(atValue instanceof Attribute.Array)) {
+            return null;
+        }
+
+        List<Attribute> targets = ((Array)atValue).getValue();
+        if (targets.stream().anyMatch(a -> !(a instanceof Attribute.Enum))) {
+            return null;
+        }
+
+        return targets;
+    }
 
     /**
      * Determine whether an annotation is a declaration annotation,
      * a type annotation, or both.
      */
-    public AnnotationType annotationType(Attribute.Compound a, Symbol s) {
-        Attribute.Compound atTarget =
-            a.type.tsym.attribute(syms.annotationTargetType.tsym);
-        if (atTarget == null) {
-            return inferTargetMetaInfo(a, s);
-        }
-        Attribute atValue = atTarget.member(names.value);
-        if (!(atValue instanceof Attribute.Array)) {
-            Assert.error("annotationType(): bad @Target argument " + atValue +
-                    " (" + atValue.getClass() + ")");
-            return AnnotationType.DECLARATION; // error recovery
-        }
-        Attribute.Array arr = (Attribute.Array) atValue;
-        boolean isDecl = false, isType = false;
-        for (Attribute app : arr.values) {
-            if (!(app instanceof Attribute.Enum)) {
-                Assert.error("annotationType(): unrecognized Attribute kind " + app +
-                        " (" + app.getClass() + ")");
-                isDecl = true;
-                continue;
-            }
-            Attribute.Enum e = (Attribute.Enum) app;
-            if (e.value.name == names.TYPE) {
-                if (s.kind == TYP)
-                    isDecl = true;
-            } else if (e.value.name == names.FIELD) {
-                if (s.kind == VAR &&
-                        s.owner.kind != MTH)
-                    isDecl = true;
-            } else if (e.value.name == names.METHOD) {
-                if (s.kind == MTH &&
-                        !s.isConstructor())
-                    isDecl = true;
-            } else if (e.value.name == names.PARAMETER) {
-                if (s.kind == VAR &&
-                        s.owner.kind == MTH &&
-                        (s.flags() & Flags.PARAMETER) != 0)
-                    isDecl = true;
-            } else if (e.value.name == names.CONSTRUCTOR) {
-                if (s.kind == MTH &&
-                        s.isConstructor())
-                    isDecl = true;
-            } else if (e.value.name == names.LOCAL_VARIABLE) {
-                if (s.kind == VAR &&
-                        s.owner.kind == MTH &&
-                        (s.flags() & Flags.PARAMETER) == 0)
-                    isDecl = true;
-            } else if (e.value.name == names.ANNOTATION_TYPE) {
-                if (s.kind == TYP &&
-                        (s.flags() & Flags.ANNOTATION) != 0)
-                    isDecl = true;
-            } else if (e.value.name == names.PACKAGE) {
-                if (s.kind == PCK)
-                    isDecl = true;
-            } else if (e.value.name == names.TYPE_USE) {
-                if (s.kind == TYP ||
-                        s.kind == VAR ||
-                        (s.kind == MTH && !s.isConstructor() &&
-                        !s.type.getReturnType().hasTag(TypeTag.VOID)) ||
-                        (s.kind == MTH && s.isConstructor()))
-                    isType = true;
-            } else if (e.value.name == names.TYPE_PARAMETER) {
-                /* Irrelevant in this case */
-                // TYPE_PARAMETER doesn't aid in distinguishing between
-                // Type annotations and declaration annotations on an
-                // Element
-            } else {
-                Assert.error("annotationType(): unrecognized Attribute name " + e.value.name +
-                        " (" + e.value.name.getClass() + ")");
-                isDecl = true;
-            }
-        }
-        if (isDecl && isType) {
+    public AnnotationType annotationTargetType(Attribute.Compound a, Symbol s) {
+        List<Attribute> targets = annotationTargets(a);
+        return (targets == null) ?
+                AnnotationType.DECLARATION :
+                targets.stream()
+                        .map(attr -> targetToAnnotationType(attr, s))
+                        .reduce(AnnotationType.NONE, this::combineAnnotationType);
+    }
+
+    private AnnotationType combineAnnotationType(AnnotationType at1, AnnotationType at2) {
+        if (at1 == AnnotationType.NONE) {
+            return at2;
+        } else if (at2 == AnnotationType.NONE) {
+            return at1;
+        } else if (at1 != at2) {
             return AnnotationType.BOTH;
-        } else if (isType) {
-            return AnnotationType.TYPE;
         } else {
-            return AnnotationType.DECLARATION;
+            return at1;
         }
     }
 
-    /** Infer the target annotation kind, if none is give.
-     * We only infer declaration annotations.
-     */
-    private static AnnotationType inferTargetMetaInfo(Attribute.Compound a, Symbol s) {
-        return AnnotationType.DECLARATION;
+    private AnnotationType targetToAnnotationType(Attribute a, Symbol s) {
+        Attribute.Enum e = (Attribute.Enum)a;
+        if (e.value.name == names.TYPE) {
+            if (s.kind == TYP)
+                return AnnotationType.DECLARATION;
+        } else if (e.value.name == names.FIELD) {
+            if (s.kind == VAR &&
+                    s.owner.kind != MTH)
+                return AnnotationType.DECLARATION;
+        } else if (e.value.name == names.METHOD) {
+            if (s.kind == MTH &&
+                    !s.isConstructor())
+                return AnnotationType.DECLARATION;
+        } else if (e.value.name == names.PARAMETER) {
+            if (s.kind == VAR &&
+                    s.owner.kind == MTH &&
+                    (s.flags() & Flags.PARAMETER) != 0)
+                return AnnotationType.DECLARATION;
+        } else if (e.value.name == names.CONSTRUCTOR) {
+            if (s.kind == MTH &&
+                    s.isConstructor())
+                return AnnotationType.DECLARATION;
+        } else if (e.value.name == names.LOCAL_VARIABLE) {
+            if (s.kind == VAR &&
+                    s.owner.kind == MTH &&
+                    (s.flags() & Flags.PARAMETER) == 0)
+                return AnnotationType.DECLARATION;
+        } else if (e.value.name == names.ANNOTATION_TYPE) {
+            if (s.kind == TYP &&
+                    (s.flags() & Flags.ANNOTATION) != 0)
+                return AnnotationType.DECLARATION;
+        } else if (e.value.name == names.PACKAGE) {
+            if (s.kind == PCK)
+                return AnnotationType.DECLARATION;
+        } else if (e.value.name == names.TYPE_USE) {
+            if (s.kind == TYP ||
+                    s.kind == VAR ||
+                    (s.kind == MTH && !s.isConstructor() &&
+                    !s.type.getReturnType().hasTag(TypeTag.VOID)) ||
+                    (s.kind == MTH && s.isConstructor()))
+                return AnnotationType.TYPE;
+        } else if (e.value.name == names.TYPE_PARAMETER) {
+            /* Irrelevant in this case */
+            // TYPE_PARAMETER doesn't aid in distinguishing between
+            // Type annotations and declaration annotations on an
+            // Element
+        } else {
+            Assert.error("annotationTargetType(): unrecognized Attribute name " + e.value.name +
+                    " (" + e.value.name.getClass() + ")");
+            return AnnotationType.DECLARATION;
+        }
+        return AnnotationType.NONE;
     }
 
-
     private class TypeAnnotationPositions extends TreeScanner {
 
         private final boolean sigOnly;
@@ -262,18 +263,29 @@
          * When traversing the AST we keep the "frames" of visited
          * trees in order to determine the position of annotations.
          */
-        private ListBuffer<JCTree> frames = new ListBuffer<>();
+        private List<JCTree> frames = List.nil();
 
-        protected void push(JCTree t) { frames = frames.prepend(t); }
-        protected JCTree pop() { return frames.next(); }
+        protected void push(JCTree t) {
+            frames = frames.prepend(t);
+        }
+        protected JCTree pop() {
+            JCTree t = frames.head;
+            frames = frames.tail;
+            return t;
+            }
         // could this be frames.elems.tail.head?
-        private JCTree peek2() { return frames.toList().tail.head; }
+        private JCTree peek2() {
+            return frames.tail.head;
+        }
 
         @Override
         public void scan(JCTree tree) {
             push(tree);
-            super.scan(tree);
-            pop();
+            try {
+                super.scan(tree);
+            } finally {
+                pop();
+            }
         }
 
         /**
@@ -283,41 +295,44 @@
          * we never build an JCAnnotatedType. This step finds these
          * annotations and marks them as if they were part of the type.
          */
-        private void separateAnnotationsKinds(JCTree typetree, Type type, Symbol sym,
-                TypeAnnotationPosition pos) {
-            List<Attribute.Compound> annotations = sym.getRawAttributes();
+        private void separateAnnotationsKinds(JCTree typetree, Type type,
+                                              Symbol sym, TypeAnnotationPosition pos)
+        {
+            List<Attribute.Compound> allAnnotations = sym.getRawAttributes();
             ListBuffer<Attribute.Compound> declAnnos = new ListBuffer<>();
             ListBuffer<Attribute.TypeCompound> typeAnnos = new ListBuffer<>();
             ListBuffer<Attribute.TypeCompound> onlyTypeAnnos = new ListBuffer<>();
 
-            for (Attribute.Compound a : annotations) {
-                switch (annotationType(a, sym)) {
-                case DECLARATION:
-                    declAnnos.append(a);
-                    break;
-                case BOTH: {
-                    declAnnos.append(a);
-                    Attribute.TypeCompound ta = toTypeCompound(a, pos);
-                    typeAnnos.append(ta);
-                    break;
-                }
-                case TYPE: {
-                    Attribute.TypeCompound ta = toTypeCompound(a, pos);
-                    typeAnnos.append(ta);
-                    // Also keep track which annotations are only type annotations
-                    onlyTypeAnnos.append(ta);
-                    break;
-                }
+            for (Attribute.Compound a : allAnnotations) {
+                switch (annotationTargetType(a, sym)) {
+                    case DECLARATION:
+                        declAnnos.append(a);
+                        break;
+                    case BOTH: {
+                        declAnnos.append(a);
+                        Attribute.TypeCompound ta = toTypeCompound(a, pos);
+                        typeAnnos.append(ta);
+                        break;
+                    }
+                    case TYPE: {
+                        Attribute.TypeCompound ta = toTypeCompound(a, pos);
+                        typeAnnos.append(ta);
+                        // Also keep track which annotations are only type annotations
+                        onlyTypeAnnos.append(ta);
+                        break;
+                    }
                 }
             }
 
-            sym.resetAnnotations();
-            sym.setDeclarationAttributes(declAnnos.toList());
-
+            // If we have no type annotations we are done for this Symbol
             if (typeAnnos.isEmpty()) {
                 return;
             }
 
+            // Reset decl annotations to the set {all - type only}
+            sym.resetAnnotations();
+            sym.setDeclarationAttributes(declAnnos.toList());
+
             List<Attribute.TypeCompound> typeAnnotations = typeAnnos.toList();
 
             if (type == null) {
@@ -328,7 +343,7 @@
 
                 // Declaration annotations are always allowed on constructor returns.
                 // Therefore, use typeAnnotations instead of onlyTypeAnnos.
-                type = typeWithAnnotations(typetree, type, typeAnnotations, typeAnnotations);
+                typeWithAnnotations(typetree, type, typeAnnotations, typeAnnotations, pos);
                 // Note that we don't use the result, the call to
                 // typeWithAnnotations side-effects the type annotation positions.
                 // This is important for constructors of nested classes.
@@ -336,8 +351,8 @@
                 return;
             }
 
-            // type is non-null and annotations are added to that type
-            type = typeWithAnnotations(typetree, type, typeAnnotations, onlyTypeAnnos.toList());
+            // type is non-null, add type annotations from declaration context to the type
+            type = typeWithAnnotations(typetree, type, typeAnnotations, onlyTypeAnnos.toList(), pos);
 
             if (sym.getKind() == ElementKind.METHOD) {
                 sym.type.asMethodType().restype = type;
@@ -390,59 +405,23 @@
         // Note that it is assumed that all annotations share the same position.
         private Type typeWithAnnotations(final JCTree typetree, final Type type,
                 final List<Attribute.TypeCompound> annotations,
-                final List<Attribute.TypeCompound> onlyTypeAnnotations) {
-            //System.err.printf("typeWithAnnotations(typetree: %s, type: %s, annotations: %s, onlyTypeAnnotations: %s)%n",
-            //         typetree, type, annotations, onlyTypeAnnotations);
+                final List<Attribute.TypeCompound> onlyTypeAnnotations,
+                final TypeAnnotationPosition pos)
+        {
             if (annotations.isEmpty()) {
                 return type;
             }
-            if (type.hasTag(TypeTag.ARRAY)) {
-                Type.ArrayType arType = (Type.ArrayType) type;
-                Type.ArrayType tomodify = new Type.ArrayType(null, arType.tsym);
-                Type toreturn;
-                if (type.isAnnotated()) {
-                    toreturn = tomodify.annotatedType(type.getAnnotationMirrors());
-                } else {
-                    toreturn = tomodify;
-                }
-
-                JCArrayTypeTree arTree = arrayTypeTree(typetree);
 
-                ListBuffer<TypePathEntry> depth = new ListBuffer<>();
-                depth = depth.append(TypePathEntry.ARRAY);
-                while (arType.elemtype.hasTag(TypeTag.ARRAY)) {
-                    if (arType.elemtype.isAnnotated()) {
-                        Type aelemtype = arType.elemtype;
-                        arType = (Type.ArrayType) aelemtype;
-                        ArrayType prevToMod = tomodify;
-                        tomodify = new Type.ArrayType(null, arType.tsym);
-                        prevToMod.elemtype = tomodify.annotatedType(arType.elemtype.getAnnotationMirrors());
-                    } else {
-                        arType = (Type.ArrayType) arType.elemtype;
-                        tomodify.elemtype = new Type.ArrayType(null, arType.tsym);
-                        tomodify = (Type.ArrayType) tomodify.elemtype;
-                    }
-                    arTree = arrayTypeTree(arTree.elemtype);
-                    depth = depth.append(TypePathEntry.ARRAY);
-                }
-                Type arelemType = typeWithAnnotations(arTree.elemtype, arType.elemtype, annotations, onlyTypeAnnotations);
-                tomodify.elemtype = arelemType;
-                {
-                    // All annotations share the same position; modify the first one.
-                    Attribute.TypeCompound a = annotations.get(0);
-                    TypeAnnotationPosition p = a.position;
-                    p.location = p.location.prependList(depth.toList());
-                }
-                typetree.type = toreturn;
-                return toreturn;
-            } else if (type.hasTag(TypeTag.TYPEVAR)) {
-                // Nothing to do for type variables.
-                return type;
+            if (type.hasTag(TypeTag.ARRAY))
+                return rewriteArrayType((ArrayType)type, annotations, pos);
+
+            if (type.hasTag(TypeTag.TYPEVAR)) {
+                return type.annotatedType(onlyTypeAnnotations);
             } else if (type.getKind() == TypeKind.UNION) {
                 // There is a TypeKind, but no TypeTag.
-                JCTypeUnion tutree = (JCTypeUnion) typetree;
+                JCTypeUnion tutree = (JCTypeUnion)typetree;
                 JCExpression fst = tutree.alternatives.get(0);
-                Type res = typeWithAnnotations(fst, fst.type, annotations, onlyTypeAnnotations);
+                Type res = typeWithAnnotations(fst, fst.type, annotations, onlyTypeAnnotations, pos);
                 fst.type = res;
                 // TODO: do we want to set res as first element in uct.alternatives?
                 // UnionClassType uct = (com.sun.tools.javac.code.Type.UnionClassType)type;
@@ -459,8 +438,8 @@
                         enclTy.getKind() != TypeKind.NONE &&
                         enclTy.getKind() != TypeKind.ERROR &&
                         (enclTr.getKind() == JCTree.Kind.MEMBER_SELECT ||
-                         enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE ||
-                         enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) {
+                                enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE ||
+                                enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) {
                     // Iterate also over the type tree, not just the type: the type is already
                     // completely resolved and we cannot distinguish where the annotation
                     // belongs for a nested type.
@@ -483,20 +462,20 @@
                 if (enclTy != null &&
                         enclTy.hasTag(TypeTag.NONE)) {
                     switch (onlyTypeAnnotations.size()) {
-                    case 0:
-                        // Don't issue an error if all type annotations are
-                        // also declaration annotations.
-                        // If the annotations are also declaration annotations, they are
-                        // illegal as type annotations but might be legal as declaration annotations.
-                        // The normal declaration annotation checks make sure that the use is valid.
-                        break;
-                    case 1:
-                        log.error(typetree.pos(), "cant.type.annotate.scoping.1",
-                                onlyTypeAnnotations);
-                        break;
-                    default:
-                        log.error(typetree.pos(), "cant.type.annotate.scoping",
-                                onlyTypeAnnotations);
+                        case 0:
+                            // Don't issue an error if all type annotations are
+                            // also declaration annotations.
+                            // If the annotations are also declaration annotations, they are
+                            // illegal as type annotations but might be legal as declaration annotations.
+                            // The normal declaration annotation checks make sure that the use is valid.
+                            break;
+                        case 1:
+                            log.error(typetree.pos(), "cant.type.annotate.scoping.1",
+                                    onlyTypeAnnotations);
+                            break;
+                        default:
+                            log.error(typetree.pos(), "cant.type.annotate.scoping",
+                                    onlyTypeAnnotations);
                     }
                     return type;
                 }
@@ -539,15 +518,62 @@
             }
         }
 
-        private JCArrayTypeTree arrayTypeTree(JCTree typetree) {
-            if (typetree.getKind() == JCTree.Kind.ARRAY_TYPE) {
-                return (JCArrayTypeTree) typetree;
-            } else if (typetree.getKind() == JCTree.Kind.ANNOTATED_TYPE) {
-                return (JCArrayTypeTree) ((JCAnnotatedType)typetree).underlyingType;
+        /**
+         * Create a copy of the {@code Type type} with the help of the Tree for a type
+         * {@code JCTree typetree} inserting all type annotations in {@code annotations} to the
+         * innermost array component type.
+         *
+         * SIDE EFFECT: Update position for the annotations to be {@code pos}.
+         */
+        private Type rewriteArrayType(ArrayType type, List<TypeCompound> annotations, TypeAnnotationPosition pos) {
+            ArrayType tomodify = new ArrayType(type);
+            ArrayType res = tomodify;
+
+            List<TypePathEntry> loc = List.nil();
+
+            // peel one and update loc
+            Type tmpType = type.elemtype;
+            loc = loc.prepend(TypePathEntry.ARRAY);
+
+            while (tmpType.hasTag(TypeTag.ARRAY)) {
+                ArrayType arr = (ArrayType)tmpType;
+
+                // Update last type with new element type
+                ArrayType tmp = new ArrayType(arr);
+                tomodify.elemtype = tmp;
+                tomodify = tmp;
+
+                tmpType = arr.elemtype;
+                loc = loc.prepend(TypePathEntry.ARRAY);
+            }
+
+            // Fix innermost element type
+            Type elemType;
+            if (tmpType.getMetadata() != null) {
+                List<TypeCompound> tcs;
+                if (tmpType.getAnnotationMirrors().isEmpty()) {
+                    tcs = annotations;
+                } else {
+                    // Special case, lets prepend
+                    tcs =  annotations.appendList(tmpType.getAnnotationMirrors());
+                }
+                elemType = tmpType.cloneWithMetadata(tmpType
+                        .getMetadata()
+                        .without(Kind.ANNOTATIONS)
+                        .combine(new TypeMetadata.Annotations(tcs)));
             } else {
-                Assert.error("Could not determine array type from type tree: " + typetree);
-                return null;
+                elemType = tmpType.cloneWithMetadata(new TypeMetadata(new TypeMetadata.Annotations(annotations)));
             }
+            tomodify.elemtype = elemType;
+
+            // Update positions
+            for (TypeCompound tc : annotations) {
+                if (tc.position == null)
+                    tc.position = pos;
+                tc.position.location = loc;
+            }
+
+            return res;
         }
 
         /** Return a copy of the first type that only differs by
@@ -569,7 +595,6 @@
         private Type typeWithAnnotations(final Type type,
                 final Type stopAt,
                 final List<Attribute.TypeCompound> annotations) {
-            //System.err.println("typeWithAnnotations " + type + " " + annotations + " stopAt " + stopAt);
             Visitor<Type, List<TypeCompound>> visitor =
                     new Type.Visitor<Type, List<Attribute.TypeCompound>>() {
                 @Override
@@ -660,20 +685,14 @@
         /* This is the beginning of the second part of organizing
          * type annotations: determine the type annotation positions.
          */
-
-        // This method is considered deprecated, and will be removed
-        // in the near future.  Don't use it for anything new.
         private TypeAnnotationPosition
             resolveFrame(JCTree tree,
                          JCTree frame,
                          List<JCTree> path,
                          JCLambda currentLambda,
                          int outer_type_index,
-                         ListBuffer<TypePathEntry> location) {
-            /*
-            System.out.println("Resolving tree: " + tree + " kind: " + tree.getKind());
-            System.out.println("    Framing tree: " + frame + " kind: " + frame.getKind());
-            */
+                         ListBuffer<TypePathEntry> location)
+        {
 
             // Note that p.offset is set in
             // com.sun.tools.javac.jvm.Gen.setTypeAnnotationPositions(int)
@@ -695,20 +714,17 @@
                     if (frameNewClass.def != null) {
                         // Special handling for anonymous class instantiations
                         final JCClassDecl frameClassDecl = frameNewClass.def;
-                        if (frameClassDecl.extending == tree) {
-                            return TypeAnnotationPosition
-                                .classExtends(location.toList(), currentLambda,
-                                              frame.pos);
-                        } else if (frameClassDecl.implementing.contains(tree)) {
+                        if (frameClassDecl.implementing.contains(tree)) {
                             final int type_index =
                                 frameClassDecl.implementing.indexOf(tree);
                             return TypeAnnotationPosition
                                 .classExtends(location.toList(), currentLambda,
                                               type_index, frame.pos);
                         } else {
-                            // In contrast to CLASS below, typarams cannot occur here.
-                            throw new AssertionError("Could not determine position of tree " + tree +
-                                                     " within frame " + frame);
+                            //for encl.new @TA Clazz(), tree may be different from frameClassDecl.extending
+                            return TypeAnnotationPosition
+                                .classExtends(location.toList(), currentLambda,
+                                              frame.pos);
                         }
                     } else if (frameNewClass.typeargs.contains(tree)) {
                         final int type_index =
@@ -1120,29 +1136,31 @@
                     // Nothing to do for separateAnnotationsKinds if
                     // there are no annotations of either kind.
                     // TODO: make sure there are no declaration annotations.
-                    final TypeAnnotationPosition pos =
-                        TypeAnnotationPosition.methodReceiver(tree.recvparam.vartype.pos);
-                    separateAnnotationsKinds(tree.recvparam.vartype,
-                                             tree.recvparam.sym.type,
-                                             tree.recvparam.sym, pos);
+                    final TypeAnnotationPosition pos = TypeAnnotationPosition.methodReceiver(tree.recvparam.vartype.pos);
+                    push(tree.recvparam);
+                    try {
+                        separateAnnotationsKinds(tree.recvparam.vartype, tree.recvparam.sym.type, tree.recvparam.sym, pos);
+                    } finally {
+                        pop();
+                    }
                 }
                 int i = 0;
                 for (JCVariableDecl param : tree.params) {
                     if (!param.mods.annotations.isEmpty()) {
                         // Nothing to do for separateAnnotationsKinds if
                         // there are no annotations of either kind.
-                        final TypeAnnotationPosition pos =
-                            TypeAnnotationPosition.methodParameter(i, param.vartype.pos);
-                        separateAnnotationsKinds(param.vartype,
-                                                 param.sym.type,
-                                                 param.sym, pos);
+                        final TypeAnnotationPosition pos = TypeAnnotationPosition.methodParameter(i, param.vartype.pos);
+                        push(param);
+                        try {
+                            separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos);
+                        } finally {
+                            pop();
+                        }
                     }
                     ++i;
                 }
             }
 
-            push(tree);
-            // super.visitMethodDef(tree);
             if (sigOnly) {
                 scan(tree.mods);
                 scan(tree.restype);
@@ -1154,7 +1172,6 @@
                 scan(tree.defaultValue);
                 scan(tree.body);
             }
-            pop();
         }
 
         /* Store a reference to the current lambda expression, to
@@ -1172,18 +1189,20 @@
                     if (!param.mods.annotations.isEmpty()) {
                         // Nothing to do for separateAnnotationsKinds if
                         // there are no annotations of either kind.
-                        final TypeAnnotationPosition pos =
-                            TypeAnnotationPosition.methodParameter(tree, i,
-                                                                   param.vartype.pos);
-                        separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos);
+                        final TypeAnnotationPosition pos =  TypeAnnotationPosition
+                                .methodParameter(tree, i, param.vartype.pos);
+                        push(param);
+                        try {
+                            separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos);
+                        } finally {
+                            pop();
+                        }
                     }
                     ++i;
                 }
 
-                push(tree);
                 scan(tree.body);
                 scan(tree.params);
-                pop();
             } finally {
                 currentLambda = prevLambda;
             }
@@ -1227,17 +1246,14 @@
                 // No type annotations can occur here.
             } else {
                 // There is nothing else in a variable declaration that needs separation.
-                Assert.error("Unhandled variable kind: " + tree + " of kind: " + tree.sym.getKind());
+                Assert.error("Unhandled variable kind");
             }
 
-            push(tree);
-            // super.visitVarDef(tree);
             scan(tree.mods);
             scan(tree.vartype);
             if (!sigOnly) {
                 scan(tree.init);
             }
-            pop();
         }
 
         @Override
@@ -1363,31 +1379,37 @@
             scan(tree.elems);
         }
 
-        private void findPosition(JCTree tree, JCTree frame, List<JCAnnotation> annotations) {
+
+        private void findTypeCompoundPosition(JCTree tree, JCTree frame, List<Attribute.TypeCompound> annotations) {
             if (!annotations.isEmpty()) {
-                /*
-                System.err.println("Finding pos for: " + annotations);
-                System.err.println("    tree: " + tree + " kind: " + tree.getKind());
-                System.err.println("    frame: " + frame + " kind: " + frame.getKind());
-                */
                 final TypeAnnotationPosition p =
-                    resolveFrame(tree, frame, frames.toList(), currentLambda, 0,
-                                 new ListBuffer<TypePathEntry>());
+                        resolveFrame(tree, frame, frames, currentLambda, 0, new ListBuffer<>());
+                for (TypeCompound tc : annotations)
+                    tc.position = p;
+            }
+        }
+
+        private void findPosition(JCTree tree, JCTree frame, List<JCAnnotation> annotations) {
+            if (!annotations.isEmpty())
+            {
+                final TypeAnnotationPosition p =
+                    resolveFrame(tree, frame, frames, currentLambda, 0, new ListBuffer<>());
+
                 setTypeAnnotationPos(annotations, p);
             }
         }
 
-        private void setTypeAnnotationPos(List<JCAnnotation> annotations,
-                TypeAnnotationPosition position) {
+        private void setTypeAnnotationPos(List<JCAnnotation> annotations, TypeAnnotationPosition position)
+        {
+            // attribute might be null during DeferredAttr;
+            // we will be back later.
             for (JCAnnotation anno : annotations) {
-                // attribute might be null during DeferredAttr;
-                // we will be back later.
-                if (anno.attribute != null) {
+                if (anno.attribute != null)
                     ((Attribute.TypeCompound) anno.attribute).position = position;
-                }
             }
         }
 
+
         @Override
         public String toString() {
             return super.toString() + ": sigOnly: " + sigOnly;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeMetadata.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeMetadata.java	Tue Apr 07 11:04:29 2015 -0700
@@ -30,46 +30,63 @@
 import com.sun.tools.javac.util.List;
 import java.util.EnumMap;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 
 /**
- * A super-interface for all type metadata elements.  Metadata classes
- * can be created for any metadata on types with the following
- * properties:
+ * TypeMetadata is essentially an immutable {@code EnumMap<Entry.Kind, <? extends Entry>>}
  *
- * <ul>
- * <li>They have a default value (preferably empty)</li>
- * <li>The field is usually the default value</li>
- * <li>Different values of the field are visible, and denote distinct
- *     types</li>
- * </ul>
+ * A metadata class represented by a subtype of Entry can express a property on a Type instance.
+ * Thers should be at most one instance of an Entry per Entry.Kind on any given Type instance.
+ *
+ * Metadata classes of a specific kind are responsible for how they combine themselvs.
+ *
+ * @implNote {@code Entry:combine} need not be commutative.
  */
 public class TypeMetadata {
+    public static final TypeMetadata EMPTY = new TypeMetadata();
 
-    public static final TypeMetadata empty = new TypeMetadata();
-    private final EnumMap<TypeMetadata.Element.Kind, TypeMetadata.Element> contents;
+    private final EnumMap<Entry.Kind, Entry> contents;
 
+    /**
+     * Create a new empty TypeMetadata map.
+     */
     private TypeMetadata() {
-        contents = new EnumMap<Element.Kind, Element>(Element.Kind.class);
+        contents = new EnumMap<>(Entry.Kind.class);
     }
 
-    public TypeMetadata(final Element elem) {
+    /**
+     * Create a new TypeMetadata map containing the Entry {@code elem}.
+     *
+     * @param elem the sole contents of this map
+     */
+    public TypeMetadata(Entry elem) {
         this();
+        Assert.checkNonNull(elem);
         contents.put(elem.kind(), elem);
     }
 
-    public TypeMetadata(final TypeMetadata other) {
+    /**
+     * Creates a copy of TypeMetadata {@code other} with a shallow copy the other's metadata contents.
+     *
+     * @param other the TypeMetadata to copy contents from.
+     */
+    public TypeMetadata(TypeMetadata other) {
+        Assert.checkNonNull(other);
         contents = other.contents.clone();
     }
 
-    public TypeMetadata copy() {
-        return new TypeMetadata(this);
-    }
+    /**
+     * Return a copy of this TypeMetadata with the metadata entry for {@code elem.kind()} combined
+     * with {@code elem}.
+     *
+     * @param elem the new value
+     * @return a new TypeMetadata updated with {@code Entry elem}
+     */
+    public TypeMetadata combine(Entry elem) {
+        Assert.checkNonNull(elem);
 
-    public TypeMetadata combine(final Element elem) {
-        final TypeMetadata out = new TypeMetadata(this);
-        final Element.Kind key = elem.kind();
+        TypeMetadata out = new TypeMetadata(this);
+        Entry.Kind key = elem.kind();
         if (contents.containsKey(key)) {
             out.add(key, this.contents.get(key).combine(elem));
         } else {
@@ -78,17 +95,26 @@
         return out;
     }
 
-    public TypeMetadata combine(final TypeMetadata other) {
-        final TypeMetadata out = new TypeMetadata();
-        final Set<Element.Kind> keys = new HashSet<>(this.contents.keySet());
+    /**
+     * Return a copy of this TypeMetadata with the metadata entry for all kinds from {@code other}
+     * combined with the same kind from this.
+     *
+     * @param other the TypeMetadata to combine with this
+     * @return a new TypeMetadata updated with all entries from {@code other}
+     */
+    public TypeMetadata combineAll(TypeMetadata other) {
+        Assert.checkNonNull(other);
+
+        TypeMetadata out = new TypeMetadata();
+        Set<Entry.Kind> keys = new HashSet<>(contents.keySet());
         keys.addAll(other.contents.keySet());
 
-        for(final Element.Kind key : keys) {
-            if (this.contents.containsKey(key)) {
+        for(Entry.Kind key : keys) {
+            if (contents.containsKey(key)) {
                 if (other.contents.containsKey(key)) {
-                    out.add(key, this.contents.get(key).combine(other.contents.get(key)));
+                    out.add(key, contents.get(key).combine(other.contents.get(key)));
                 } else {
-                    out.add(key, this.contents.get(key));
+                    out.add(key, contents.get(key));
                 }
             } else if (other.contents.containsKey(key)) {
                 out.add(key, other.contents.get(key));
@@ -97,26 +123,35 @@
         return out;
     }
 
-    public Element get(final Element.Kind kind) {
+    /**
+     * Return a TypeMetadata with the metadata entry for {@code kind} removed.
+     *
+     * This may be the same instance or a new TypeMetadata.
+     *
+     * @param kind the {@code Kind} to remove metadata for
+     * @return a new TypeMetadata without {@code Kind kind}
+     */
+    public TypeMetadata without(Entry.Kind kind) {
+        if (this == EMPTY || contents.get(kind) == null)
+            return this;
+
+        TypeMetadata out = new TypeMetadata(this);
+        out.contents.remove(kind);
+        return out.contents.isEmpty() ? EMPTY : out;
+    }
+
+    public Entry get(Entry.Kind kind) {
         return contents.get(kind);
     }
 
-    public boolean isEmpty() {
-        return contents.isEmpty();
-    }
-
-    private void add(final Element.Kind kind, final Element elem) {
+    private void add(Entry.Kind kind, Entry elem) {
         contents.put(kind, elem);
     }
 
-    private void addAll(final Map<? extends Element.Kind,? extends Element> m) {
-        contents.putAll(m);
-    }
-
-    public interface Element {
+    public interface Entry {
 
         public enum Kind {
-            ANNOTATIONS;
+            ANNOTATIONS
         }
 
         /**
@@ -131,16 +166,18 @@
          * @param other The metadata with which to combine this one.
          * @return The combined metadata.
          */
-        public Element combine(Element other);
+        public Entry combine(Entry other);
     }
 
     /**
      * A type metadata object holding type annotations.
      */
-    public static class Annotations implements Element {
-        private final List<Attribute.TypeCompound> annos;
+    public static class Annotations implements Entry {
+        private List<Attribute.TypeCompound> annos;
 
-        public Annotations(final List<Attribute.TypeCompound> annos) {
+        public static final List<Attribute.TypeCompound> TO_BE_SET = List.nil();
+
+        public Annotations(List<Attribute.TypeCompound> annos) {
             this.annos = annos;
         }
 
@@ -154,18 +191,16 @@
         }
 
         @Override
-        public Annotations combine(final Element other) {
-            // Temporary: we should append the lists, but that won't
-            // work with type annotations today.  Instead, we replace
-            // the list.
-            return new Annotations(((Annotations) other).annos);
+        public Annotations combine(Entry other) {
+            Assert.check(annos == TO_BE_SET);
+            annos = ((Annotations)other).annos;
+            return this;
         }
 
         @Override
         public Kind kind() { return Kind.ANNOTATIONS; }
 
         @Override
-        public String toString() { return "ANNOTATIONS { " + annos + " }"; }
+        public String toString() { return "ANNOTATIONS [ " + annos + " ]"; }
     }
-
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Tue Apr 07 11:04:29 2015 -0700
@@ -40,6 +40,7 @@
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
+import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
 import com.sun.tools.javac.comp.AttrContext;
 import com.sun.tools.javac.comp.Check;
 import com.sun.tools.javac.comp.Enter;
@@ -809,7 +810,7 @@
         return isSubtype(t, s, false);
     }
     public boolean isSubtype(Type t, Type s, boolean capture) {
-        if (t == s)
+        if (t.equalsIgnoreMetadata(s))
             return true;
         if (s.isPartial())
             return isSuperType(s, t);
@@ -1081,14 +1082,11 @@
                 isSameTypeStrict.visit(t, s) :
                 isSameTypeLoose.visit(t, s);
     }
-    public boolean isSameAnnotatedType(Type t, Type s) {
-        return isSameAnnotatedType.visit(t, s);
-    }
     // where
         abstract class SameTypeVisitor extends TypeRelation {
 
             public Boolean visitType(Type t, Type s) {
-                if (t == s)
+                if (t.equalsIgnoreMetadata(s))
                     return true;
 
                 if (s.isPartial())
@@ -1281,39 +1279,6 @@
 
     // </editor-fold>
 
-    TypeRelation isSameAnnotatedType = new LooseSameTypeVisitor() {
-            private Boolean compareAnnotations(Type t1, Type t2) {
-                List<Attribute.TypeCompound> annos1 = t1.getAnnotationMirrors();
-                List<Attribute.TypeCompound> annos2 = t2.getAnnotationMirrors();
-                return annos1.containsAll(annos2) && annos2.containsAll(annos1);
-            }
-
-            @Override
-            public Boolean visitType(Type t, Type s) {
-                return compareAnnotations(t, s) && super.visitType(t, s);
-            }
-
-            @Override
-            public Boolean visitWildcardType(WildcardType t, Type s) {
-                return compareAnnotations(t, s) && super.visitWildcardType(t, s);
-            }
-
-            @Override
-            public Boolean visitClassType(ClassType t, Type s) {
-                return compareAnnotations(t, s) && super.visitClassType(t, s);
-            }
-
-            @Override
-            public Boolean visitArrayType(ArrayType t, Type s) {
-                return compareAnnotations(t, s) && super.visitArrayType(t, s);
-            }
-
-            @Override
-            public Boolean visitForAll(ForAll t, Type s) {
-                return compareAnnotations(t, s) && super.visitForAll(t, s);
-            }
-        };
-
     // <editor-fold defaultstate="collapsed" desc="Contains Type">
     public boolean containedBy(Type t, Type s) {
         switch (t.getTag()) {
@@ -2167,7 +2132,7 @@
      * type parameters in t are deleted.
      */
     public Type erasure(Type t) {
-        return eraseNotNeeded(t)? t : erasure(t, false);
+        return eraseNotNeeded(t) ? t : erasure(t, false);
     }
     //where
     private boolean eraseNotNeeded(Type t) {
@@ -2187,23 +2152,23 @@
         }
     // where
         private TypeMapping<Boolean> erasure = new TypeMapping<Boolean>() {
-            private Type combineMetadata(final Type ty,
-                                         final TypeMetadata md) {
-                if (!md.isEmpty()) {
-                    switch (ty.getKind()) {
-                    default: return ty.clone(ty.metadata.combine(md));
-                    case OTHER:
-                    case UNION:
-                    case INTERSECTION:
-                    case PACKAGE:
-                    case EXECUTABLE:
-                    case NONE:
-                    case VOID:
-                    case ERROR:
-                        return ty;
+            private Type combineMetadata(final Type s,
+                                         final Type t) {
+                if (t.getMetadata() != TypeMetadata.EMPTY) {
+                    switch (s.getKind()) {
+                        case OTHER:
+                        case UNION:
+                        case INTERSECTION:
+                        case PACKAGE:
+                        case EXECUTABLE:
+                        case NONE:
+                        case VOID:
+                        case ERROR:
+                            return s;
+                        default: return s.cloneWithMetadata(s.getMetadata().without(Kind.ANNOTATIONS));
                     }
                 } else {
-                    return ty;
+                    return s;
                 }
             }
 
@@ -2212,7 +2177,7 @@
                     return t; /*fast special case*/
                 else {
                     //other cases already handled
-                    return combineMetadata(t, t.getMetadata());
+                    return combineMetadata(t, t);
                 }
             }
 
@@ -2220,17 +2185,18 @@
             public Type visitClassType(ClassType t, Boolean recurse) {
                 Type erased = t.tsym.erasure(Types.this);
                 if (recurse) {
-                    erased = new ErasedClassType(erased.getEnclosingType(),erased.tsym, t.getMetadata());
+                    erased = new ErasedClassType(erased.getEnclosingType(),erased.tsym,
+                            t.getMetadata().without(Kind.ANNOTATIONS));
                     return erased;
                 } else {
-                    return combineMetadata(erased, t.getMetadata());
+                    return combineMetadata(erased, t);
                 }
             }
 
             @Override
             public Type visitTypeVar(TypeVar t, Boolean recurse) {
                 Type erased = erasure(t.bound, recurse);
-                return combineMetadata(erased, t.getMetadata());
+                return combineMetadata(erased, t);
             }
         };
 
@@ -2932,7 +2898,7 @@
     public List<Type> subst(List<Type> ts,
                             List<Type> from,
                             List<Type> to) {
-        return new Subst(from, to).subst(ts);
+        return ts.map(new Subst(from, to));
     }
 
     /**
@@ -2942,10 +2908,10 @@
      * elements of the longer list.
      */
     public Type subst(Type t, List<Type> from, List<Type> to) {
-        return new Subst(from, to).subst(t);
+        return t.map(new Subst(from, to));
     }
 
-    private class Subst extends UnaryVisitor<Type> {
+    private class Subst extends TypeMapping<Void> {
         List<Type> from;
         List<Type> to;
 
@@ -2964,49 +2930,12 @@
             this.to = to;
         }
 
-        Type subst(Type t) {
-            if (from.tail == null)
-                return t;
-            else
-                return visit(t);
-            }
-
-        List<Type> subst(List<Type> ts) {
-            if (from.tail == null)
-                return ts;
-            boolean wild = false;
-            if (ts.nonEmpty() && from.nonEmpty()) {
-                Type head1 = subst(ts.head);
-                List<Type> tail1 = subst(ts.tail);
-                if (head1 != ts.head || tail1 != ts.tail)
-                    return tail1.prepend(head1);
-            }
-            return ts;
-        }
-
-        public Type visitType(Type t, Void ignored) {
-            return t;
-        }
-
-        @Override
-        public Type visitMethodType(MethodType t, Void ignored) {
-            List<Type> argtypes = subst(t.argtypes);
-            Type restype = subst(t.restype);
-            List<Type> thrown = subst(t.thrown);
-            if (argtypes == t.argtypes &&
-                restype == t.restype &&
-                thrown == t.thrown)
-                return t;
-            else
-                return new MethodType(argtypes, restype, thrown, t.tsym);
-        }
-
         @Override
         public Type visitTypeVar(TypeVar t, Void ignored) {
             for (List<Type> from = this.from, to = this.to;
                  from.nonEmpty();
                  from = from.tail, to = to.tail) {
-                if (t == from.head) {
+                if (t.equalsIgnoreMetadata(from.head)) {
                     return to.head.withTypeVar(t);
                 }
             }
@@ -3014,26 +2943,12 @@
         }
 
         @Override
-        public Type visitUndetVar(UndetVar t, Void ignored) {
-            //do nothing - we should not replace inside undet variables
-            return t;
-        }
-
-        @Override
         public Type visitClassType(ClassType t, Void ignored) {
             if (!t.isCompound()) {
-                List<Type> typarams = t.getTypeArguments();
-                List<Type> typarams1 = subst(typarams);
-                Type outer = t.getEnclosingType();
-                Type outer1 = subst(outer);
-                if (typarams1 == typarams && outer1 == outer)
-                    return t;
-                else
-                    return new ClassType(outer1, typarams1, t.tsym,
-                                         t.getMetadata());
+                return super.visitClassType(t, ignored);
             } else {
-                Type st = subst(supertype(t));
-                List<Type> is = subst(interfaces(t));
+                Type st = visit(supertype(t));
+                List<Type> is = visit(interfaces(t), ignored);
                 if (st == supertype(t) && is == interfaces(t))
                     return t;
                 else
@@ -3043,26 +2958,11 @@
 
         @Override
         public Type visitWildcardType(WildcardType t, Void ignored) {
-            Type bound = t.type;
-            if (t.kind != BoundKind.UNBOUND)
-                bound = subst(bound);
-            if (bound == t.type) {
-                return t;
-            } else {
-                if (t.isExtendsBound() && bound.isExtendsBound())
-                    bound = wildUpperBound(bound);
-                return new WildcardType(bound, t.kind, syms.boundClass,
-                                        t.bound, t.getMetadata());
+            WildcardType t2 = (WildcardType)super.visitWildcardType(t, ignored);
+            if (t2 != t && t.isExtendsBound() && t2.type.isExtendsBound()) {
+                t2.type = wildUpperBound(t2.type);
             }
-        }
-
-        @Override
-        public Type visitArrayType(ArrayType t, Void ignored) {
-            Type elemtype = subst(t.elemtype);
-            if (elemtype == t.elemtype)
-                return t;
-            else
-                return new ArrayType(elemtype, t.tsym, t.getMetadata());
+            return t2;
         }
 
         @Override
@@ -3075,21 +2975,25 @@
                                Types.this.subst(t.qtype, t.tvars, freevars));
             }
             List<Type> tvars1 = substBounds(t.tvars, from, to);
-            Type qtype1 = subst(t.qtype);
+            Type qtype1 = visit(t.qtype);
             if (tvars1 == t.tvars && qtype1 == t.qtype) {
                 return t;
             } else if (tvars1 == t.tvars) {
-                return new ForAll(tvars1, qtype1);
+                return new ForAll(tvars1, qtype1) {
+                    @Override
+                    public boolean needsStripping() {
+                        return true;
+                    }
+                };
             } else {
-                return new ForAll(tvars1,
-                                  Types.this.subst(qtype1, t.tvars, tvars1));
+                return new ForAll(tvars1, Types.this.subst(qtype1, t.tvars, tvars1)) {
+                    @Override
+                    public boolean needsStripping() {
+                        return true;
+                    }
+                };
             }
         }
-
-        @Override
-        public Type visitErrorType(ErrorType t, Void ignored) {
-            return t;
-        }
     }
 
     public List<Type> substBounds(List<Type> tvars,
@@ -4232,8 +4136,7 @@
     }
 
     private boolean containsTypeEquivalent(Type t, Type s) {
-        return
-            isSameType(t, s) || // shortcut
+        return isSameType(t, s) || // shortcut
             containsType(t, s) && containsType(s, t);
     }
 
@@ -4675,7 +4578,7 @@
         return getRetention(a.type.tsym);
     }
 
-    public RetentionPolicy getRetention(Symbol sym) {
+    public RetentionPolicy getRetention(TypeSymbol sym) {
         RetentionPolicy vis = RetentionPolicy.CLASS; // the default
         Attribute.Compound c = sym.attribute(syms.retentionType.tsym);
         if (c != null) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, 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
@@ -25,28 +25,39 @@
 
 package com.sun.tools.javac.comp;
 
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.List;
 
 import javax.tools.JavaFileObject;
+import java.util.*;
 
-import com.sun.tools.javac.util.*;
-import com.sun.tools.javac.util.DefinedBy.Api;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
-import com.sun.tools.javac.code.*;
-import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.tree.*;
-import com.sun.tools.javac.tree.JCTree.*;
-
-import static com.sun.tools.javac.code.Kinds.Kind.*;
+import static com.sun.tools.javac.code.Flags.SYNTHETIC;
+import static com.sun.tools.javac.code.Kinds.Kind.MTH;
+import static com.sun.tools.javac.code.Kinds.Kind.VAR;
+import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
 import static com.sun.tools.javac.code.TypeTag.ARRAY;
 import static com.sun.tools.javac.code.TypeTag.CLASS;
-import static com.sun.tools.javac.tree.JCTree.Tag.*;
+import static com.sun.tools.javac.tree.JCTree.Tag.ANNOTATION;
+import static com.sun.tools.javac.tree.JCTree.Tag.ASSIGN;
+import static com.sun.tools.javac.tree.JCTree.Tag.IDENT;
+import static com.sun.tools.javac.tree.JCTree.Tag.NEWARRAY;
 
-/** Enter annotations on symbols.  Annotations accumulate in a queue,
- *  which is processed at the top level of any set of recursive calls
- *  requesting it be processed.
+/** Enter annotations onto symbols and types (and trees).
+ *
+ *  This is also a pseudo stage in the compiler taking care of scheduling when annotations are
+ *  entered.
  *
  *  <p><b>This is NOT part of any supported API.
  *  If you write code that depends on this, you do so at your own risk.
@@ -64,95 +75,98 @@
     }
 
     private final Attr attr;
-    private final TreeMaker make;
-    private final Log log;
-    private final Symtab syms;
-    private final Names names;
-    private final Resolve rs;
-    private final Types types;
+    private final Check chk;
     private final ConstFold cfolder;
-    private final Check chk;
+    private final DeferredLintHandler deferredLintHandler;
+    private final Enter enter;
     private final Lint lint;
-    private final DeferredLintHandler deferredLintHandler;
-    private final Source source;
+    private final Log log;
+    private final Names names;
+    private final Resolve resolve;
+    private final TreeMaker make;
+    private final Symtab syms;
+    private final TypeEnvs typeEnvs;
+    private final Types types;
 
-    private boolean allowTypeAnnos;
-    private boolean allowRepeatedAnnos;
+    private final Attribute theUnfinishedDefaultValue;
+    private final boolean allowRepeatedAnnos;
 
     protected Annotate(Context context) {
         context.put(annotateKey, this);
+
         attr = Attr.instance(context);
-        make = TreeMaker.instance(context);
+        chk = Check.instance(context);
+        cfolder = ConstFold.instance(context);
+        deferredLintHandler = DeferredLintHandler.instance(context);
+        enter = Enter.instance(context);
         log = Log.instance(context);
-        syms = Symtab.instance(context);
+        lint = Lint.instance(context);
+        make = TreeMaker.instance(context);
         names = Names.instance(context);
-        rs = Resolve.instance(context);
+        resolve = Resolve.instance(context);
+        syms = Symtab.instance(context);
+        typeEnvs = TypeEnvs.instance(context);
         types = Types.instance(context);
-        cfolder = ConstFold.instance(context);
-        chk = Check.instance(context);
-        source = Source.instance(context);
-        lint = Lint.instance(context);
-        deferredLintHandler = DeferredLintHandler.instance(context);
+
+        theUnfinishedDefaultValue =  new Attribute.Error(syms.errType);
+
+        Source source = Source.instance(context);
         allowRepeatedAnnos = source.allowRepeatedAnnotations();
-        allowTypeAnnos = source.allowTypeAnnotations();
     }
 
-/* ********************************************************************
- * Queue maintenance
- *********************************************************************/
-
-    private int enterCount = 0;
+    /** Semaphore to delay annotation processing */
+    private int blockCount = 0;
 
-    ListBuffer<Worker> q = new ListBuffer<>();
-    ListBuffer<Worker> typesQ = new ListBuffer<>();
-    ListBuffer<Worker> repeatedQ = new ListBuffer<>();
-    ListBuffer<Worker> afterRepeatedQ = new ListBuffer<>();
-    ListBuffer<Worker> validateQ = new ListBuffer<>();
-
-    public void earlier(Worker a) {
-        q.prepend(a);
-    }
-
-    public void normal(Worker a) {
-        q.append(a);
+    /** Called when annotations processing needs to be postponed. */
+    public void blockAnnotations() {
+        blockCount++;
     }
 
-    public void typeAnnotation(Worker a) {
-        typesQ.append(a);
-    }
-
-    public void repeated(Worker a) {
-        repeatedQ.append(a);
-    }
-
-    public void afterRepeated(Worker a) {
-        afterRepeatedQ.append(a);
-    }
-
-    public void validate(Worker a) {
-        validateQ.append(a);
-    }
-
-    /** Called when the Enter phase starts. */
-    public void enterStart() {
-        enterCount++;
-    }
-
-    /** Called after the Enter phase completes. */
-    public void enterDone() {
-        enterCount--;
-        flush();
+    /** Called when annotation processing can be resumed. */
+    public void unblockAnnotations() {
+        blockCount--;
+        if (blockCount == 0)
+            flush();
     }
 
     /** Variant which allows for a delayed flush of annotations.
      * Needed by ClassReader */
-    public void enterDoneWithoutFlush() {
-        enterCount--;
+    public void unblockAnnotationsNoFlush() {
+        blockCount--;
     }
 
+    /** are we blocking annotation processing? */
+    public boolean annotationsBlocked() {return blockCount > 0; }
+
+    public List<TypeCompound> fromAnnotations(List<JCAnnotation> annotations) {
+        if (annotations.isEmpty()) {
+            return List.nil();
+        }
+
+        ListBuffer<TypeCompound> buf = new ListBuffer<>();
+        for (JCAnnotation anno : annotations) {
+            Assert.checkNonNull(anno.attribute);
+            buf.append((TypeCompound) anno.attribute);
+        }
+        return buf.toList();
+    }
+
+    /** Annotate (used for everything else) */
+    public void normal(Runnable r) {
+        q.append(r);
+    }
+
+    /** Validate, triggers after 'normal' */
+    public void validate(Runnable a) {
+        validateQ.append(a);
+    }
+
+    /** Flush all annotation queues */
     public void flush() {
-        if (enterCount != 0) return;
-        enterCount++;
+        if (annotationsBlocked()) return;
+        if (isFlushing()) return;
+
+        startFlushing();
         try {
             while (q.nonEmpty()) {
                 q.next().run();
@@ -160,35 +174,502 @@
             while (typesQ.nonEmpty()) {
                 typesQ.next().run();
             }
-            while (repeatedQ.nonEmpty()) {
-                repeatedQ.next().run();
-            }
-            while (afterRepeatedQ.nonEmpty()) {
-                afterRepeatedQ.next().run();
+            while (afterTypesQ.nonEmpty()) {
+                afterTypesQ.next().run();
             }
             while (validateQ.nonEmpty()) {
                 validateQ.next().run();
             }
         } finally {
-            enterCount--;
+            doneFlushing();
+        }
+    }
+
+    private ListBuffer<Runnable> q = new ListBuffer<>();
+    private ListBuffer<Runnable> validateQ = new ListBuffer<>();
+
+    private int flushCount = 0;
+    private boolean isFlushing() { return flushCount > 0; }
+    private void startFlushing() { flushCount++; }
+    private void doneFlushing() { flushCount--; }
+
+    ListBuffer<Runnable> typesQ = new ListBuffer<>();
+    ListBuffer<Runnable> afterTypesQ = new ListBuffer<>();
+
+
+    public void typeAnnotation(Runnable a) {
+        typesQ.append(a);
+    }
+
+    public void afterTypes(Runnable a) {
+        afterTypesQ.append(a);
+    }
+
+    /**
+     * Queue annotations for later attribution and entering. This is probably the method you are looking for.
+     *
+     * @param annotations the list of JCAnnotations to attribute and enter
+     * @param localEnv    the enclosing env
+     * @param s           ths Symbol on which to enter the annotations
+     * @param deferPos    report errors here
+     */
+    public void annotateLater(List<JCAnnotation> annotations, Env<AttrContext> localEnv,
+            Symbol s, DiagnosticPosition deferPos)
+    {
+        if (annotations.isEmpty()) {
+            return;
+        }
+
+        s.resetAnnotations(); // mark Annotations as incomplete for now
+
+        normal(new Runnable() {
+            @Override
+            public String toString() {
+                return "Annotate " + annotations + " onto " + s + " in " + s.owner;
+            }
+
+            @Override
+            public void run() {
+                Assert.check(s.annotationsPendingCompletion());
+                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
+                DiagnosticPosition prevLintPos =
+                        deferPos != null
+                                ? deferredLintHandler.setPos(deferPos)
+                                : deferredLintHandler.immediate();
+                Lint prevLint = deferPos != null ? null : chk.setLint(lint);
+                try {
+                    if (s.hasAnnotations() && annotations.nonEmpty())
+                        log.error(annotations.head.pos, "already.annotated", Kinds.kindName(s), s);
+
+                    Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null");
+                    annotateNow(s, annotations, localEnv, false);
+                } finally {
+                    if (prevLint != null)
+                        chk.setLint(prevLint);
+                    deferredLintHandler.setPos(prevLintPos);
+                    log.useSource(prev);
+                }
+            }
+        });
+
+        validate(new Runnable() { //validate annotations
+            @Override
+            public void run() {
+                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
+                try {
+                    chk.validateAnnotations(annotations, s);
+                } finally {
+                    log.useSource(prev);
+                }
+            }
+
+            @Override
+            public String toString() {
+                return "validate annotations: " + annotations + " on " + s;
+            }
+        });
+    }
+
+
+    /** Queue processing of an attribute default value. */
+    public void annotateDefaultValueLater(JCExpression defaultValue, Env<AttrContext> localEnv,
+            MethodSymbol m, DiagnosticPosition deferPos)
+    {
+        normal(new Runnable() {
+            @Override
+            public void run() {
+                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
+                DiagnosticPosition prevLintPos = deferredLintHandler.setPos(deferPos);
+                try {
+                    enterDefaultValue(defaultValue, localEnv, m);
+                } finally {
+                    deferredLintHandler.setPos(prevLintPos);
+                    log.useSource(prev);
+                }
+            }
+
+            @Override
+            public String toString() {
+                return "Annotate " + m.owner + "." +
+                        m + " default " + defaultValue;
+            }
+        });
+
+        validate(new Runnable() { //validate annotations
+            @Override
+            public void run() {
+                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
+                try {
+                    // if default value is an annotation, check it is a well-formed
+                    // annotation value (e.g. no duplicate values, no missing values, etc.)
+                    chk.validateAnnotationTree(defaultValue);
+                } finally {
+                    log.useSource(prev);
+                }
+            }
+
+            @Override
+            public String toString() {
+                return "Validate default value " + m.owner + "." + m + " default " + defaultValue;
+            }
+        });
+    }
+
+    /** Enter a default value for an annotation element. */
+    private void enterDefaultValue(JCExpression defaultValue,
+            Env<AttrContext> localEnv, MethodSymbol m) {
+        m.defaultValue = attributeAnnotationValue(m.type.getReturnType(), defaultValue, localEnv);
+    }
+
+    /**
+     * Gather up annotations into a map from type symbols to lists of Compound attributes,
+     * then continue on with repeating annotations processing.
+     */
+    private <T extends Attribute.Compound> void annotateNow(Symbol toAnnotate,
+            List<JCAnnotation> withAnnotations, Env<AttrContext> env, boolean typeAnnotations)
+    {
+        Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>();
+        Map<T, DiagnosticPosition> pos = new HashMap<>();
+        boolean allowRepeatedAnnos = this.allowRepeatedAnnos;
+
+        for (List<JCAnnotation> al = withAnnotations; !al.isEmpty(); al = al.tail) {
+            JCAnnotation a = al.head;
+
+            T c;
+            if (typeAnnotations) {
+                @SuppressWarnings("unchecked")
+                T tmp = (T)attributeTypeAnnotation(a, syms.annotationType, env);
+                c = tmp;
+            } else {
+                @SuppressWarnings("unchecked")
+                T tmp = (T)attributeAnnotation(a, syms.annotationType, env);
+                c = tmp;
+            }
+
+            Assert.checkNonNull(c, "Failed to create annotation");
+
+            if (annotated.containsKey(a.type.tsym)) {
+                if (!allowRepeatedAnnos) {
+                    log.error(a.pos(), "repeatable.annotations.not.supported.in.source");
+                    allowRepeatedAnnos = true;
+                }
+                ListBuffer<T> l = annotated.get(a.type.tsym);
+                l = l.append(c);
+                annotated.put(a.type.tsym, l);
+                pos.put(c, a.pos());
+            } else {
+                annotated.put(a.type.tsym, ListBuffer.of(c));
+                pos.put(c, a.pos());
+            }
+
+            // Note: @Deprecated has no effect on local variables and parameters
+            if (!c.type.isErroneous()
+                    && toAnnotate.owner.kind != MTH
+                    && types.isSameType(c.type, syms.deprecatedType)) {
+                toAnnotate.flags_field |= Flags.DEPRECATED;
+            }
+        }
+
+        List<T> buf = List.nil();
+        for (ListBuffer<T> lb : annotated.values()) {
+            if (lb.size() == 1) {
+                buf = buf.prepend(lb.first());
+            } else {
+                AnnotationContext<T> ctx = new AnnotationContext<>(env, annotated, pos, typeAnnotations);
+                T res = makeContainerAnnotation(lb.toList(), ctx, toAnnotate);
+                if (res != null)
+                    buf = buf.prepend(res);
+            }
+        }
+
+        if (typeAnnotations) {
+            @SuppressWarnings("unchecked")
+            List<TypeCompound> attrs = (List<TypeCompound>)buf.reverse();
+            toAnnotate.appendUniqueTypeAttributes(attrs);
+        } else {
+            @SuppressWarnings("unchecked")
+            List<Attribute.Compound> attrs =  (List<Attribute.Compound>)buf.reverse();
+            toAnnotate.resetAnnotations();
+            toAnnotate.setDeclarationAttributes(attrs);
         }
     }
 
-    /** A client that needs to run during {@link #flush()} registers an worker
-     *  into one of the queues defined in this class. The queues are: {@link #earlier(Worker)},
-     *  {@link #normal(Worker)}, {@link #typeAnnotation(Worker)}, {@link #repeated(Worker)},
-     *  {@link #afterRepeated(Worker)}, {@link #validate(Worker)}.
-     *  The {@link Worker#run()} method will called inside the {@link #flush()}
-     *  call. Queues are empties in the abovementioned order.
+    /**
+     * Attribute and store a semantic representation of the annotation tree {@code tree} into the
+     * tree.attribute field.
+     *
+     * @param tree the tree representing an annotation
+     * @param expectedAnnotationType the expected (super)type of the annotation
+     * @param env the current env in where the annotation instance is found
      */
-    public interface Worker {
-        void run();
-        String toString();
+    public Attribute.Compound attributeAnnotation(JCAnnotation tree, Type expectedAnnotationType,
+                                                  Env<AttrContext> env)
+    {
+        // The attribute might have been entered if it is Target or Repetable
+        // Because TreeCopier does not copy type, redo this if type is null
+        if (tree.attribute != null && tree.type != null)
+            return tree.attribute;
+
+        List<Pair<MethodSymbol, Attribute>> elems = attributeAnnotationValues(tree, expectedAnnotationType, env);
+        Attribute.Compound ac = new Attribute.Compound(tree.type, elems);
+
+        return tree.attribute = ac;
+    }
+
+    /** Attribute and store a semantic representation of the type annotation tree {@code tree} into
+     * the tree.attribute field.
+     *
+     * @param a the tree representing an annotation
+     * @param expectedAnnotationType the expected (super)type of the annotation
+     * @param env the the current env in where the annotation instance is found
+     */
+    public Attribute.TypeCompound attributeTypeAnnotation(JCAnnotation a, Type expectedAnnotationType,
+                                                          Env<AttrContext> env)
+    {
+        // The attribute might have been entered if it is Target or Repetable
+        // Because TreeCopier does not copy type, redo this if type is null
+        if (a.attribute == null || a.type == null || !(a.attribute instanceof Attribute.TypeCompound)) {
+            // Create a new TypeCompound
+            List<Pair<MethodSymbol,Attribute>> elems =
+                    attributeAnnotationValues(a, expectedAnnotationType, env);
+
+            Attribute.TypeCompound tc =
+                    new Attribute.TypeCompound(a.type, elems, TypeAnnotationPosition.unknown);
+            a.attribute = tc;
+            return tc;
+        } else {
+            // Use an existing TypeCompound
+            return (Attribute.TypeCompound)a.attribute;
+        }
     }
 
     /**
+     *  Attribute annotation elements creating a list of pairs of the Symbol representing that
+     *  element and the value of that element as an Attribute. */
+    private List<Pair<MethodSymbol, Attribute>> attributeAnnotationValues(JCAnnotation a,
+            Type expected, Env<AttrContext> env)
+    {
+        // The annotation might have had its type attributed (but not
+        // checked) by attr.attribAnnotationTypes during MemberEnter,
+        // in which case we do not need to do it again.
+        Type at = (a.annotationType.type != null ?
+                a.annotationType.type : attr.attribType(a.annotationType, env));
+        a.type = chk.checkType(a.annotationType.pos(), at, expected);
+
+        boolean isError = a.type.isErroneous();
+        if (!a.type.tsym.isAnnotationType() && !isError) {
+            log.error(a.annotationType.pos(),
+                    "not.annotation.type", a.type.toString());
+            isError = true;
+        }
+
+        // List of name=value pairs (or implicit "value=" if size 1)
+        List<JCExpression> args = a.args;
+
+        boolean elidedValue = false;
+        // special case: elided "value=" assumed
+        if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
+            args.head = make.at(args.head.pos).
+                    Assign(make.Ident(names.value), args.head);
+            elidedValue = true;
+        }
+
+        ListBuffer<Pair<MethodSymbol,Attribute>> buf = new ListBuffer<>();
+        for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
+            Pair<MethodSymbol, Attribute> p = attributeAnnotationNameValuePair(tl.head, a.type, isError, env, elidedValue);
+            if (p != null && !p.fst.type.isErroneous())
+                buf.append(p);
+        }
+        return buf.toList();
+    }
+
+    // where
+    private Pair<MethodSymbol, Attribute> attributeAnnotationNameValuePair(JCExpression nameValuePair,
+            Type thisAnnotationType, boolean badAnnotation, Env<AttrContext> env, boolean elidedValue)
+    {
+        if (!nameValuePair.hasTag(ASSIGN)) {
+            log.error(nameValuePair.pos(), "annotation.value.must.be.name.value");
+            attributeAnnotationValue(nameValuePair.type = syms.errType, nameValuePair, env);
+            return null;
+        }
+        JCAssign assign = (JCAssign)nameValuePair;
+        if (!assign.lhs.hasTag(IDENT)) {
+            log.error(nameValuePair.pos(), "annotation.value.must.be.name.value");
+            attributeAnnotationValue(nameValuePair.type = syms.errType, nameValuePair, env);
+            return null;
+        }
+
+        // Resolve element to MethodSym
+        JCIdent left = (JCIdent)assign.lhs;
+        Symbol method = resolve.resolveQualifiedMethod(elidedValue ? assign.rhs.pos() : left.pos(),
+                env, thisAnnotationType,
+                left.name, List.<Type>nil(), null);
+        left.sym = method;
+        left.type = method.type;
+        if (method.owner != thisAnnotationType.tsym && !badAnnotation)
+            log.error(left.pos(), "no.annotation.member", left.name, thisAnnotationType);
+        Type resultType = method.type.getReturnType();
+
+        // Compute value part
+        Attribute value = attributeAnnotationValue(resultType, assign.rhs, env);
+        nameValuePair.type = resultType;
+
+        return method.type.isErroneous() ? null : new Pair<>((MethodSymbol)method, value);
+
+    }
+
+    /** Attribute an annotation element value */
+    private Attribute attributeAnnotationValue(Type expectedElementType, JCExpression tree,
+            Env<AttrContext> env)
+    {
+        //first, try completing the symbol for the annotation value - if acompletion
+        //error is thrown, we should recover gracefully, and display an
+        //ordinary resolution diagnostic.
+        try {
+            expectedElementType.tsym.complete();
+        } catch(CompletionFailure e) {
+            log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
+            expectedElementType = syms.errType;
+        }
+
+        if (expectedElementType.hasTag(ARRAY)) {
+            return getAnnotationArrayValue(expectedElementType, tree, env);
+
+        }
+
+        //error recovery
+        if (tree.hasTag(NEWARRAY)) {
+            if (!expectedElementType.isErroneous())
+                log.error(tree.pos(), "annotation.value.not.allowable.type");
+            JCNewArray na = (JCNewArray)tree;
+            if (na.elemtype != null) {
+                log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
+            }
+            for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
+                attributeAnnotationValue(syms.errType,
+                        l.head,
+                        env);
+            }
+            return new Attribute.Error(syms.errType);
+        }
+
+        if (expectedElementType.tsym.isAnnotationType()) {
+            if (tree.hasTag(ANNOTATION)) {
+                return attributeAnnotation((JCAnnotation)tree, expectedElementType, env);
+            } else {
+                log.error(tree.pos(), "annotation.value.must.be.annotation");
+                expectedElementType = syms.errType;
+            }
+        }
+
+        //error recovery
+        if (tree.hasTag(ANNOTATION)) {
+            if (!expectedElementType.isErroneous())
+                log.error(tree.pos(), "annotation.not.valid.for.type", expectedElementType);
+            attributeAnnotation((JCAnnotation)tree, syms.errType, env);
+            return new Attribute.Error(((JCAnnotation)tree).annotationType.type);
+        }
+
+        if (expectedElementType.isPrimitive() ||
+                (types.isSameType(expectedElementType, syms.stringType) && !expectedElementType.hasTag(TypeTag.ERROR))) {
+            return getAnnotationPrimitiveValue(expectedElementType, tree, env);
+        }
+
+        if (expectedElementType.tsym == syms.classType.tsym) {
+            return getAnnotationClassValue(expectedElementType, tree, env);
+        }
+
+        if (expectedElementType.hasTag(CLASS) &&
+                (expectedElementType.tsym.flags() & Flags.ENUM) != 0) {
+            return getAnnotationEnumValue(expectedElementType, tree, env);
+        }
+
+        //error recovery:
+        if (!expectedElementType.isErroneous())
+            log.error(tree.pos(), "annotation.value.not.allowable.type");
+        return new Attribute.Error(attr.attribExpr(tree, env, expectedElementType));
+    }
+
+    private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
+        Type result = attr.attribExpr(tree, env, expectedElementType);
+        Symbol sym = TreeInfo.symbol(tree);
+        if (sym == null ||
+                TreeInfo.nonstaticSelect(tree) ||
+                sym.kind != VAR ||
+                (sym.flags() & Flags.ENUM) == 0) {
+            log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
+            return new Attribute.Error(result.getOriginalType());
+        }
+        VarSymbol enumerator = (VarSymbol) sym;
+        return new Attribute.Enum(expectedElementType, enumerator);
+    }
+
+    private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
+        Type result = attr.attribExpr(tree, env, expectedElementType);
+        if (result.isErroneous()) {
+            // Does it look like an unresolved class literal?
+            if (TreeInfo.name(tree) == names._class &&
+                    ((JCFieldAccess) tree).selected.type.isErroneous()) {
+                Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName();
+                return new Attribute.UnresolvedClass(expectedElementType,
+                        types.createErrorType(n,
+                                syms.unknownSymbol, syms.classType));
+            } else {
+                return new Attribute.Error(result.getOriginalType());
+            }
+        }
+
+        // Class literals look like field accesses of a field named class
+        // at the tree level
+        if (TreeInfo.name(tree) != names._class) {
+            log.error(tree.pos(), "annotation.value.must.be.class.literal");
+            return new Attribute.Error(syms.errType);
+        }
+        return new Attribute.Class(types,
+                (((JCFieldAccess) tree).selected).type);
+    }
+
+    private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
+        Type result = attr.attribExpr(tree, env, expectedElementType);
+        if (result.isErroneous())
+            return new Attribute.Error(result.getOriginalType());
+        if (result.constValue() == null) {
+            log.error(tree.pos(), "attribute.value.must.be.constant");
+            return new Attribute.Error(expectedElementType);
+        }
+        result = cfolder.coerce(result, expectedElementType);
+        return new Attribute.Constant(expectedElementType, result.constValue());
+    }
+
+    private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
+        // Special case, implicit array
+        if (!tree.hasTag(NEWARRAY)) {
+            tree = make.at(tree.pos).
+                    NewArray(null, List.<JCExpression>nil(), List.of(tree));
+        }
+
+        JCNewArray na = (JCNewArray)tree;
+        if (na.elemtype != null) {
+            log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
+        }
+        ListBuffer<Attribute> buf = new ListBuffer<>();
+        for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
+            buf.append(attributeAnnotationValue(types.elemtype(expectedElementType),
+                    l.head,
+                    env));
+        }
+        na.type = expectedElementType;
+        return new Attribute.
+                Array(expectedElementType, buf.toArray(new Attribute[buf.length()]));
+    }
+
+    /* *********************************
+     * Support for repeating annotations
+     ***********************************/
+
+    /**
      * This context contains all the information needed to synthesize new
-     * annotations trees by the completer for repeating annotations.
+     * annotations trees for repeating annotations.
      */
     private class AnnotationContext<T extends Attribute.Compound> {
         public final Env<AttrContext> env;
@@ -209,280 +690,15 @@
             this.pos = pos;
             this.isTypeCompound = isTypeCompound;
         }
-
-        public String toString() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("RepeatedContext[");
-            for (Map.Entry<Symbol.TypeSymbol, ListBuffer<T>> entry :
-                     annotated.entrySet()) {
-                sb.append(" ");
-                sb.append(entry.getKey());
-                sb.append(" = { ");
-                sb.append(entry.getValue());
-                sb.append(" }");
-            }
-            sb.append(" ]");
-            return sb.toString();
-        }
     }
 
-    private static class Placeholder<T extends Attribute.Compound> extends Attribute.Compound {
-
-        private final Annotate.AnnotationContext<T> ctx;
-        private final List<T> placeholderFor;
-        private final Symbol on;
-
-        public Placeholder(Annotate.AnnotationContext<T> ctx,
-                           List<T> placeholderFor, Symbol on) {
-            super(on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(),
-                  placeholderFor.head.position);
-            this.ctx = ctx;
-            this.placeholderFor = placeholderFor;
-            this.on = on;
-        }
-
-        @Override @DefinedBy(Api.LANGUAGE_MODEL)
-        public String toString() {
-            return "<placeholder: " + placeholderFor + " on: " + on + ">";
-    }
-
-        public List<T> getPlaceholderFor() {
-            return placeholderFor;
-        }
-
-        public Annotate.AnnotationContext<T> getRepeatedContext() {
-            return ctx;
-        }
-    }
-
-
-/* ********************************************************************
- * Compute an attribute from its annotation.
- *********************************************************************/
-
-    /** Process a single compound annotation, returning its
-     *  Attribute. Used from MemberEnter for attaching the attributes
-     *  to the annotated symbol.
-     */
-    Attribute.Compound enterAnnotation(JCAnnotation a,
-                                       Type expected,
-                                       Env<AttrContext> env) {
-        List<Pair<MethodSymbol,Attribute>> elems =
-            enterAttributeValues(a, expected, env);
-        Attribute.Compound ac = new Attribute.Compound(a.type, elems);
-        a.attribute = ac;
-
-        return ac;
-    }
-
-    Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a,
-                                               Type expected,
-                                               Env<AttrContext> env) {
-        List<Pair<MethodSymbol,Attribute>> elems =
-            enterAttributeValues(a, expected, env);
-
-        if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) {
-            // Create a new TypeCompound
-
-            Attribute.TypeCompound tc =
-                new Attribute.TypeCompound(a.type, elems,
-                // TODO: Eventually, we will get rid of this use of
-                // unknown, because we'll get a position from
-                // MemberEnter (task 8027262).
-                                           TypeAnnotationPosition.unknown);
-            a.attribute = tc;
-            return tc;
-        } else {
-            // Use an existing TypeCompound
-            return (Attribute.TypeCompound)a.attribute;
-        }
-    }
-
-    private List<Pair<MethodSymbol,Attribute>>
-            enterAttributeValues(JCAnnotation a,
-                                 Type expected,
-                                 Env<AttrContext> env) {
-        // The annotation might have had its type attributed (but not
-        // checked) by attr.attribAnnotationTypes during MemberEnter,
-        // in which case we do not need to do it again.
-        Type at = (a.annotationType.type != null ? a.annotationType.type
-                  : attr.attribType(a.annotationType, env));
-        a.type = chk.checkType(a.annotationType.pos(), at, expected);
-        boolean isError = a.type.isErroneous();
-        if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0 && !isError) {
-            log.error(a.annotationType.pos(),
-                      "not.annotation.type", a.type.toString());
-            isError = true;
-        }
-        List<JCExpression> args = a.args;
-        boolean elidedValue = false;
-        if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
-            // special case: elided "value=" assumed
-            elidedValue = true;
-            args.head = make.at(args.head.pos).
-                Assign(make.Ident(names.value), args.head);
-        }
-        ListBuffer<Pair<MethodSymbol,Attribute>> buf =
-            new ListBuffer<>();
-        for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
-            JCExpression t = tl.head;
-            if (!t.hasTag(ASSIGN)) {
-                log.error(t.pos(), "annotation.value.must.be.name.value");
-                enterAttributeValue(t.type = syms.errType, t, env);
-                continue;
-            }
-            JCAssign assign = (JCAssign)t;
-            if (!assign.lhs.hasTag(IDENT)) {
-                log.error(t.pos(), "annotation.value.must.be.name.value");
-                enterAttributeValue(t.type = syms.errType, t, env);
-                continue;
-            }
-            JCIdent left = (JCIdent)assign.lhs;
-            Symbol method = rs.resolveQualifiedMethod(elidedValue ? assign.rhs.pos() : left.pos(),
-                                                          env,
-                                                          a.type,
-                                                          left.name,
-                                                          List.<Type>nil(),
-                                                          null);
-            left.sym = method;
-            left.type = method.type;
-            if (method.owner != a.type.tsym && !isError)
-                log.error(left.pos(), "no.annotation.member", left.name, a.type);
-            Type result = method.type.getReturnType();
-            Attribute value = enterAttributeValue(result, assign.rhs, env);
-            if (!method.type.isErroneous())
-                buf.append(new Pair<>((MethodSymbol)method, value));
-            t.type = result;
-        }
-        return buf.toList();
-    }
-
-    Attribute enterAttributeValue(Type expected,
-                                  JCExpression tree,
-                                  Env<AttrContext> env) {
-        //first, try completing the attribution value sym - if a completion
-        //error is thrown, we should recover gracefully, and display an
-        //ordinary resolution diagnostic.
-        try {
-            expected.tsym.complete();
-        } catch(CompletionFailure e) {
-            log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
-            expected = syms.errType;
-        }
-        if (expected.hasTag(ARRAY)) {
-            if (!tree.hasTag(NEWARRAY)) {
-                tree = make.at(tree.pos).
-                    NewArray(null, List.<JCExpression>nil(), List.of(tree));
-            }
-            JCNewArray na = (JCNewArray)tree;
-            if (na.elemtype != null) {
-                log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
-            }
-            ListBuffer<Attribute> buf = new ListBuffer<>();
-            for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
-                buf.append(enterAttributeValue(types.elemtype(expected),
-                                               l.head,
-                                               env));
-            }
-            na.type = expected;
-            return new Attribute.
-                Array(expected, buf.toArray(new Attribute[buf.length()]));
-        }
-        if (tree.hasTag(NEWARRAY)) { //error recovery
-            if (!expected.isErroneous())
-                log.error(tree.pos(), "annotation.value.not.allowable.type");
-            JCNewArray na = (JCNewArray)tree;
-            if (na.elemtype != null) {
-                log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
-            }
-            for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
-                enterAttributeValue(syms.errType,
-                                    l.head,
-                                    env);
-            }
-            return new Attribute.Error(syms.errType);
-        }
-        if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
-            if (tree.hasTag(ANNOTATION)) {
-                return enterAnnotation((JCAnnotation)tree, expected, env);
-            } else {
-                log.error(tree.pos(), "annotation.value.must.be.annotation");
-                expected = syms.errType;
-            }
-        }
-        if (tree.hasTag(ANNOTATION)) { //error recovery
-            if (!expected.isErroneous())
-                log.error(tree.pos(), "annotation.not.valid.for.type", expected);
-            enterAnnotation((JCAnnotation)tree, syms.errType, env);
-            return new Attribute.Error(((JCAnnotation)tree).annotationType.type);
-        }
-        if (expected.isPrimitive() ||
-            (types.isSameType(expected, syms.stringType) && !expected.hasTag(TypeTag.ERROR))) {
-            Type result = attr.attribExpr(tree, env, expected);
-            if (result.isErroneous())
-                return new Attribute.Error(result.getOriginalType());
-            if (result.constValue() == null) {
-                log.error(tree.pos(), "attribute.value.must.be.constant");
-                return new Attribute.Error(expected);
-            }
-            result = cfolder.coerce(result, expected);
-            return new Attribute.Constant(expected, result.constValue());
-        }
-        if (expected.tsym == syms.classType.tsym) {
-            Type result = attr.attribExpr(tree, env, expected);
-            if (result.isErroneous()) {
-                // Does it look like an unresolved class literal?
-                if (TreeInfo.name(tree) == names._class &&
-                    ((JCFieldAccess) tree).selected.type.isErroneous()) {
-                    Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName();
-                    return new Attribute.UnresolvedClass(expected,
-                            types.createErrorType(n,
-                                    syms.unknownSymbol, syms.classType));
-                } else {
-                    return new Attribute.Error(result.getOriginalType());
-                }
-            }
-
-            // Class literals look like field accesses of a field named class
-            // at the tree level
-            if (TreeInfo.name(tree) != names._class) {
-                log.error(tree.pos(), "annotation.value.must.be.class.literal");
-                return new Attribute.Error(syms.errType);
-            }
-            return new Attribute.Class(types,
-                                       (((JCFieldAccess) tree).selected).type);
-        }
-        if (expected.hasTag(CLASS) &&
-            (expected.tsym.flags() & Flags.ENUM) != 0) {
-            Type result = attr.attribExpr(tree, env, expected);
-            Symbol sym = TreeInfo.symbol(tree);
-            if (sym == null ||
-                TreeInfo.nonstaticSelect(tree) ||
-                sym.kind != VAR ||
-                (sym.flags() & Flags.ENUM) == 0) {
-                log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
-                return new Attribute.Error(result.getOriginalType());
-            }
-            VarSymbol enumerator = (VarSymbol) sym;
-            return new Attribute.Enum(expected, enumerator);
-        }
-        //error recovery:
-        if (!expected.isErroneous())
-            log.error(tree.pos(), "annotation.value.not.allowable.type");
-        return new Attribute.Error(attr.attribExpr(tree, env, expected));
-    }
-
-    /* *********************************
-     * Support for repeating annotations
-     ***********************************/
-
     /* Process repeated annotations. This method returns the
      * synthesized container annotation or null IFF all repeating
      * annotation are invalid.  This method reports errors/warnings.
      */
     private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
-            AnnotationContext<T> ctx,
-            Symbol on) {
+            AnnotationContext<T> ctx, Symbol on)
+    {
         T firstOccurrence = annotations.head;
         List<Attribute> repeated = List.nil();
         Type origAnnoType = null;
@@ -490,14 +706,10 @@
         Type targetContainerType = null;
         MethodSymbol containerValueSymbol = null;
 
-        Assert.check(!annotations.isEmpty() &&
-                     !annotations.tail.isEmpty()); // i.e. size() > 1
+        Assert.check(!annotations.isEmpty() && !annotations.tail.isEmpty()); // i.e. size() > 1
 
         int count = 0;
-        for (List<T> al = annotations;
-             !al.isEmpty();
-             al = al.tail)
-        {
+        for (List<T> al = annotations; !al.isEmpty(); al = al.tail) {
             count++;
 
             // There must be more than a single anno in the annotation list
@@ -532,18 +744,23 @@
             repeated = repeated.prepend(currentAnno);
         }
 
+        if (!repeated.isEmpty() && targetContainerType == null) {
+            log.error(ctx.pos.get(annotations.head), "duplicate.annotation.invalid.repeated", origAnnoType);
+            return null;
+        }
+
         if (!repeated.isEmpty()) {
             repeated = repeated.reverse();
             TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
             Pair<MethodSymbol, Attribute> p =
                     new Pair<MethodSymbol, Attribute>(containerValueSymbol,
-                               new Attribute.Array(arrayOfOrigAnnoType, repeated));
+                            new Attribute.Array(arrayOfOrigAnnoType, repeated));
             if (ctx.isTypeCompound) {
                 /* TODO: the following code would be cleaner:
                 Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
                         ((Attribute.TypeCompound)annotations.head).position);
                 JCTypeAnnotation annoTree = m.TypeAnnotation(at);
-                at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env);
+                at = attributeTypeAnnotation(annoTree, targetContainerType, ctx.env);
                 */
                 // However, we directly construct the TypeCompound to keep the
                 // direct relation to the contained TypeCompounds.
@@ -562,12 +779,13 @@
                 JCAnnotation annoTree = m.Annotation(c);
 
                 if (!chk.annotationApplicable(annoTree, on))
-                    log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType);
+                    log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target",
+                            targetContainerType, origAnnoType);
 
                 if (!chk.validateAnnotationDeferErrors(annoTree))
                     log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType);
 
-                c = enterAnnotation(annoTree, targetContainerType, ctx.env);
+                c = attributeAnnotation(annoTree, targetContainerType, ctx.env);
                 c.setSynthesized(true);
 
                 @SuppressWarnings("unchecked")
@@ -579,17 +797,19 @@
         }
     }
 
-    /** Fetches the actual Type that should be the containing annotation. */
+    /**
+     * Fetches the actual Type that should be the containing annotation.
+     */
     private Type getContainingType(Attribute.Compound currentAnno,
-            DiagnosticPosition pos,
-            boolean reportError)
+                                   DiagnosticPosition pos,
+                                   boolean reportError)
     {
         Type origAnnoType = currentAnno.type;
         TypeSymbol origAnnoDecl = origAnnoType.tsym;
 
         // Fetch the Repeatable annotation from the current
         // annotation's declaration, or null if it has none
-        Attribute.Compound ca = origAnnoDecl.attribute(syms.repeatableType.tsym);
+        Attribute.Compound ca = origAnnoDecl.getAnnotationTypeMetadata().getRepeatable();
         if (ca == null) { // has no Repeatable annotation
             if (reportError)
                 log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.repeatableType);
@@ -597,7 +817,7 @@
         }
 
         return filterSame(extractContainingType(ca, pos, origAnnoDecl),
-                          origAnnoType);
+                origAnnoType);
     }
 
     // returns null if t is same as 's', returns 't' otherwise
@@ -611,8 +831,8 @@
 
     /** Extract the actual Type to be used for a containing annotation. */
     private Type extractContainingType(Attribute.Compound ca,
-            DiagnosticPosition pos,
-            TypeSymbol annoDecl)
+                                       DiagnosticPosition pos,
+                                       TypeSymbol annoDecl)
     {
         // The next three checks check that the Repeatable annotation
         // on the declaration of the annotation type that is repeating is
@@ -657,7 +877,7 @@
             nr_value_elems++;
 
             if (nr_value_elems == 1 &&
-                elm.kind == MTH) {
+                    elm.kind == MTH) {
                 containerValueSymbol = (MethodSymbol)elm;
             } else {
                 error = true;
@@ -665,14 +885,14 @@
         }
         if (error) {
             log.error(pos,
-                      "invalid.repeatable.annotation.multiple.values",
-                      targetContainerType,
-                      nr_value_elems);
+                    "invalid.repeatable.annotation.multiple.values",
+                    targetContainerType,
+                    nr_value_elems);
             return null;
         } else if (nr_value_elems == 0) {
             log.error(pos,
-                      "invalid.repeatable.annotation.no.value",
-                      targetContainerType);
+                    "invalid.repeatable.annotation.no.value",
+                    targetContainerType);
             return null;
         }
 
@@ -680,8 +900,8 @@
         // probably "impossible" to fail this
         if (containerValueSymbol.kind != MTH) {
             log.error(pos,
-                      "invalid.repeatable.annotation.invalid.value",
-                      targetContainerType);
+                    "invalid.repeatable.annotation.invalid.value",
+                    targetContainerType);
             fatalError = true;
         }
 
@@ -690,174 +910,24 @@
         Type valueRetType = containerValueSymbol.type.getReturnType();
         Type expectedType = types.makeArrayType(originalAnnoType);
         if (!(types.isArray(valueRetType) &&
-              types.isSameType(expectedType, valueRetType))) {
+                types.isSameType(expectedType, valueRetType))) {
             log.error(pos,
-                      "invalid.repeatable.annotation.value.return",
-                      targetContainerType,
-                      valueRetType,
-                      expectedType);
+                    "invalid.repeatable.annotation.value.return",
+                    targetContainerType,
+                    valueRetType,
+                    expectedType);
             fatalError = true;
         }
-        if (error) {
-            fatalError = true;
-        }
-
-        // The conditions for a valid containing annotation are made
-        // in Check.validateRepeatedAnnotaton();
 
         return fatalError ? null : containerValueSymbol;
     }
 
-    private <T extends Attribute.Compound> AnnotationContext<T>
-            prepareEnterAnnotations(List<JCAnnotation> annotations,
-                                    Env<AttrContext> env,
-                                    Symbol sym,
-                                    AttributeCreator<T> creator,
-                                    boolean isTypeCompound) {
-        Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>();
-        Map<T, DiagnosticPosition> pos = new HashMap<>();
-
-        for (List<JCAnnotation> al = annotations; !al.isEmpty(); al = al.tail) {
-            JCAnnotation a = al.head;
-            T c = creator.create(a, syms.annotationType, env);
-
-            Assert.checkNonNull(c, "Failed to create annotation");
-
-            if (annotated.containsKey(a.type.tsym)) {
-                if (!allowRepeatedAnnos) {
-                    log.error(a.pos(), "repeatable.annotations.not.supported.in.source");
-                    allowRepeatedAnnos = true;
-                }
-                ListBuffer<T> l = annotated.get(a.type.tsym);
-                l = l.append(c);
-                annotated.put(a.type.tsym, l);
-                pos.put(c, a.pos());
-            } else {
-                annotated.put(a.type.tsym, ListBuffer.of(c));
-                pos.put(c, a.pos());
-            }
-
-            // Note: @Deprecated has no effect on local variables and parameters
-            if (!c.type.isErroneous()
-                && sym.owner.kind != MTH
-                && types.isSameType(c.type, syms.deprecatedType)) {
-                sym.flags_field |= Flags.DEPRECATED;
-            }
-        }
-
-        return new AnnotationContext<>(env, annotated, pos,
-                                             isTypeCompound);
-    }
-
-    // Gather up annotations into a map from type symbols to lists of
-    // Compound attributes, then continue on with repeating
-    // annotations processing
-    private <T extends Attribute.Compound>
-            void attachAttributesLater(final List<JCAnnotation> annotations,
-                                       final Env<AttrContext> env,
-                                       final Symbol sym,
-                                       final boolean isTypeCompound,
-                                       final AttributeCreator<T> creator,
-                                       final AttributeAttacher<T> attacher) {
-        final AnnotationContext<T> ctx =
-            prepareEnterAnnotations(annotations, env, sym, creator, isTypeCompound);
-        final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated =
-            ctx.annotated;
-        boolean hasRepeated = false;
-
-        List<T> buf = List.<T>nil();
-        for (ListBuffer<T> lb : annotated.values()) {
-            if (lb.size() == 1) {
-                buf = buf.prepend(lb.first());
-            } else {
-                @SuppressWarnings("unchecked")
-                T res = (T) new Placeholder<>(ctx, lb.toList(), sym);
-                buf = buf.prepend(res);
-                hasRepeated = true;
-            }
-        }
-
-        final List<T> attrs = buf.reverse();
-
-        if (!isTypeCompound) {
-            // Attach declaration attributes early, so
-            // that @Repeatable and other annotations get attached.
-            // Since the attacher uses setDeclarationAttributes, this
-            // will be overwritten later.
-            attacher.attach(sym, attrs);
-        }
-        if (hasRepeated) {
-            repeated(new Annotate.Worker() {
-                    @Override
-                    public String toString() {
-                        return "repeated annotation pass of: " + sym + " in: " + sym.owner;
-                    }
-
-                    @Override
-                    public void run() {
-                        JavaFileObject oldSource =
-                            log.useSource(env.toplevel.sourcefile);
-                        try {
-                            attacher.attach(sym, replacePlaceholders(attrs, ctx, sym));
-                        } finally {
-                            log.useSource(oldSource);
-                        }
-                    }
-                });
-        } else {
-            attacher.attach(sym, attrs);
-        }
-    }
-
-    private interface AttributeAttacher<T extends Attribute.Compound> {
-        public void attach(Symbol sym, List<T> attrs);
-    }
-
-    private final AttributeAttacher<Attribute.Compound> declAnnotationsAttacher =
-        new AttributeAttacher<Attribute.Compound>() {
-            @Override
-            public void attach(Symbol sym, List<Attribute.Compound> attrs) {
-                sym.resetAnnotations();
-                sym.setDeclarationAttributes(attrs);
-            }
-        };
-
-    private final AttributeAttacher<Attribute.TypeCompound> typeAnnotationsAttacher =
-        new AttributeAttacher<Attribute.TypeCompound>() {
-            @Override
-            public void attach(Symbol sym, List<Attribute.TypeCompound> attrs) {
-                sym.appendUniqueTypeAttributes(attrs);
-            }
-        };
-
-    private <T extends Attribute.Compound> List<T>
-            replacePlaceholders(List<T> buf,
-                                Annotate.AnnotationContext<T> ctx,
-                                Symbol sym) {
-        List<T> result = List.nil();
-        for (T a : buf) {
-            if (a instanceof Placeholder) {
-                @SuppressWarnings("unchecked")
-                    T replacement = replaceOne((Placeholder<T>) a, ctx, sym);
-
-                if (null != replacement) {
-                    result = result.prepend(replacement);
-                }
-            } else {
-                result = result.prepend(a);
-            }
-        }
-
-        return result.reverse();
-    }
-
-    private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder,
-                                                        Annotate.AnnotationContext<T> ctx,
-                                                        Symbol sym) {
+    private <T extends Attribute.Compound> T makeContainerAnnotation(List<T> toBeReplaced,
+            AnnotationContext<T> ctx, Symbol sym)
+    {
         // Process repeated annotations
         T validRepeated =
-            processRepeatedAnnotations(placeholder.getPlaceholderFor(),
-                                       ctx, sym);
+                processRepeatedAnnotations(toBeReplaced, ctx, sym);
 
         if (validRepeated != null) {
             // Check that the container isn't manually
@@ -865,7 +935,8 @@
             // its contained annotation.
             ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym);
             if (manualContainer != null) {
-                log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present",
+                log.error(ctx.pos.get(manualContainer.first()),
+                        "invalid.repeatable.annotation.repeated.and.container.present",
                         manualContainer.first().type.tsym);
             }
         }
@@ -874,107 +945,16 @@
         return validRepeated;
     }
 
-/* ********************************************************************
- * Annotation processing
- *********************************************************************/
-
-    /** Queue annotations for later processing. */
-    void annotateLater(final List<JCAnnotation> annotations,
-                       final Env<AttrContext> localEnv,
-                       final Symbol s,
-                       final DiagnosticPosition deferPos) {
-        if (annotations.isEmpty()) {
-            return;
-        }
-        if (s.kind != PCK) {
-            s.resetAnnotations(); // mark Annotations as incomplete for now
-        }
-        normal(new Annotate.Worker() {
-                @Override
-                public String toString() {
-                    return "annotate " + annotations + " onto " + s + " in " + s.owner;
-                }
-
-                @Override
-                public void run() {
-                    Assert.check(s.kind == PCK || s.annotationsPendingCompletion());
-                    JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
-                    DiagnosticPosition prevLintPos =
-                        deferPos != null
-                        ? deferredLintHandler.setPos(deferPos)
-                        : deferredLintHandler.immediate();
-                    Lint prevLint = deferPos != null ? null : chk.setLint(lint);
-                    try {
-                        if (s.hasAnnotations() &&
-                            annotations.nonEmpty())
-                            log.error(annotations.head.pos,
-                                      "already.annotated",
-                                      Kinds.kindName(s), s);
-                        actualEnterAnnotations(annotations, localEnv, s);
-                    } finally {
-                        if (prevLint != null)
-                            chk.setLint(prevLint);
-                        deferredLintHandler.setPos(prevLintPos);
-                        log.useSource(prev);
-                    }
-                }
-            });
+    /********************
+     * Type annotations *
+     ********************/
 
-        validate(new Annotate.Worker() { //validate annotations
-            @Override
-            public void run() {
-                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
-                try {
-                    chk.validateAnnotations(annotations, s);
-                } finally {
-                    log.useSource(prev);
-                }
-            }
-        });
-    }
-
-    private interface AttributeCreator<T extends Attribute.Compound> {
-        public T create(JCAnnotation a, Type expected, Env<AttrContext> env);
-    }
-
-    // TODO: When SE8 features can be used, these can go away and be
-    // replaced by method refs.
-    private final AttributeCreator<Attribute.Compound> enterAnnotationsCreator =
-        new AttributeCreator<Attribute.Compound>() {
-        @Override
-        public Attribute.Compound create(JCAnnotation a,
-                                         Type expected,
-                                         Env<AttrContext> env) {
-            return enterAnnotation(a, syms.annotationType, env);
-        }
-    };
-    private final AttributeCreator<Attribute.TypeCompound> enterTypeAnnotationsCreator =
-        new AttributeCreator<Attribute.TypeCompound>() {
-        @Override
-        public Attribute.TypeCompound create(JCAnnotation a,
-                                             Type expected,
-                                             Env<AttrContext> env) {
-            return enterTypeAnnotation(a, syms.annotationType, env);
-        }
-    };
-
-    /** Enter a set of annotations. */
-    private void actualEnterAnnotations(List<JCAnnotation> annotations,
-                                        Env<AttrContext> env,
-                                        Symbol s) {
-        Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null");
-        attachAttributesLater(annotations, env, s, false,
-                              enterAnnotationsCreator,
-                              declAnnotationsAttacher);
-    }
-
-    /*
-     * If the symbol is non-null, attach the type annotation to it.
+    /**
+     * Attribute the list of annotations and enter them onto s.
      */
-    private void actualEnterTypeAnnotations(final List<JCAnnotation> annotations,
-                                            final Env<AttrContext> env,
-                                            final Symbol s,
-                                            final DiagnosticPosition deferPos) {
+    public void enterTypeAnnotations(List<JCAnnotation> annotations, Env<AttrContext> env,
+            Symbol s, DiagnosticPosition deferPos)
+    {
         Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/");
         JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
         DiagnosticPosition prevLintPos = null;
@@ -983,9 +963,7 @@
             prevLintPos = deferredLintHandler.setPos(deferPos);
         }
         try {
-            attachAttributesLater(annotations, env, s, true,
-                                  enterTypeAnnotationsCreator,
-                                  typeAnnotationsAttacher);
+            annotateNow(s, annotations, env, true);
         } finally {
             if (prevLintPos != null)
                 deferredLintHandler.setPos(prevLintPos);
@@ -993,21 +971,61 @@
         }
     }
 
-    public void annotateTypeLater(final JCTree tree,
-                                  final Env<AttrContext> env,
-                                  final Symbol sym,
-                                  final DiagnosticPosition deferPos) {
+    /**
+     * Enqueue tree for scanning of type annotations, attaching to the Symbol sym.
+     */
+    public void queueScanTreeAndTypeAnnotate(JCTree tree, Env<AttrContext> env, Symbol sym,
+            DiagnosticPosition deferPos)
+    {
         Assert.checkNonNull(sym);
-        normal(new Annotate.Worker() {
-                @Override
-                public String toString() {
-                    return "type annotate " + tree + " onto " + sym + " in " + sym.owner;
-                }
-                @Override
-                public void run() {
-                    tree.accept(new TypeAnnotate(env, sym, deferPos));
-                }
-            });
+        normal(new Runnable() {
+            @Override
+            public String toString() {
+                return "type annotate " + tree + " onto " + sym + " in " + sym.owner;
+            }
+
+            @Override
+            public void run() {
+                tree.accept(new TypeAnnotate(env, sym, deferPos));
+            }
+        });
+    }
+
+    /**
+     * Apply the annotations to the particular type.
+     */
+    public void annotateTypeSecondStage(JCTree tree, List<JCAnnotation> annotations, Type storeAt) {
+        typeAnnotation(new Runnable() {
+            @Override
+            public String toString() {
+                return "Type annotate 2:nd stage " + annotations + " onto " + tree;
+            }
+
+            @Override
+            public void run() {
+                List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
+                Assert.check(annotations.size() == compounds.size());
+                storeAt.getMetadataOfKind(Kind.ANNOTATIONS).combine(new TypeMetadata.Annotations(compounds));
+            }
+        });
+    }
+
+    /**
+     * Apply the annotations to the particular type.
+     */
+    public void annotateTypeParameterSecondStage(JCTree tree, List<JCAnnotation> annotations) {
+        typeAnnotation(new Runnable() {
+            @Override
+            public String toString() {
+                return "Type annotate 2:nd stage " + annotations + " onto " + tree;
+            }
+
+            @Override
+            public void run() {
+                List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
+                Assert.check(annotations.size() == compounds.size());
+            }
+        });
     }
 
     /**
@@ -1019,9 +1037,7 @@
         private final Symbol sym;
         private DiagnosticPosition deferPos;
 
-        public TypeAnnotate(final Env<AttrContext> env,
-                            final Symbol sym,
-                            final DiagnosticPosition deferPos) {
+        public TypeAnnotate(Env<AttrContext> env, Symbol sym, DiagnosticPosition deferPos) {
 
             this.env = env;
             this.sym = sym;
@@ -1029,27 +1045,28 @@
         }
 
         @Override
-        public void visitAnnotatedType(final JCAnnotatedType tree) {
-            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
-            super.visitAnnotatedType(tree);
+        public void visitAnnotatedType(JCAnnotatedType tree) {
+            enterTypeAnnotations(tree.annotations, env, sym, deferPos);
+            scan(tree.underlyingType);
         }
 
         @Override
-        public void visitTypeParameter(final JCTypeParameter tree) {
-            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
-            super.visitTypeParameter(tree);
+        public void visitTypeParameter(JCTypeParameter tree) {
+            enterTypeAnnotations(tree.annotations, env, sym, deferPos);
+            scan(tree.bounds);
         }
 
         @Override
-        public void visitNewArray(final JCNewArray tree) {
-            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
+        public void visitNewArray(JCNewArray tree) {
+            enterTypeAnnotations(tree.annotations, env, sym, deferPos);
             for (List<JCAnnotation> dimAnnos : tree.dimAnnotations)
-                actualEnterTypeAnnotations(dimAnnos, env, sym, deferPos);
-            super.visitNewArray(tree);
+                enterTypeAnnotations(dimAnnos, env, sym, deferPos);
+            scan(tree.elemtype);
+            scan(tree.elems);
         }
 
         @Override
-        public void visitMethodDef(final JCMethodDecl tree) {
+        public void visitMethodDef(JCMethodDecl tree) {
             scan(tree.mods);
             scan(tree.restype);
             scan(tree.typarams);
@@ -1058,11 +1075,10 @@
             scan(tree.thrown);
             scan(tree.defaultValue);
             // Do not annotate the body, just the signature.
-            // scan(tree.body);
         }
 
         @Override
-        public void visitVarDef(final JCVariableDecl tree) {
+        public void visitVarDef(JCVariableDecl tree) {
             DiagnosticPosition prevPos = deferPos;
             deferPos = tree.pos();
             try {
@@ -1094,4 +1110,238 @@
             }
         }
     }
+
+    /*********************
+     * Completer support *
+     *********************/
+
+    private AnnotationTypeCompleter theSourceCompleter = new AnnotationTypeCompleter() {
+        @Override
+        public void complete(ClassSymbol sym) throws CompletionFailure {
+            Env<AttrContext> context = typeEnvs.get(sym);
+            Annotate.this.attributeAnnotationType(context);
+        }
+    };
+
+    /* Last stage completer to enter just enough annotations to have a prototype annotation type.
+     * This currently means entering @Target and @Repetable.
+     */
+    public AnnotationTypeCompleter annotationTypeSourceCompleter() {
+        return theSourceCompleter;
+    }
+
+    private void attributeAnnotationType(Env<AttrContext> env) {
+        Assert.check(((JCClassDecl)env.tree).sym.isAnnotationType(),
+                "Trying to annotation type complete a non-annotation type");
+
+        JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
+        try {
+            JCClassDecl tree = (JCClassDecl)env.tree;
+            AnnotationTypeVisitor v = new AnnotationTypeVisitor(attr, chk, syms, typeEnvs);
+            v.scanAnnotationType(tree);
+            tree.sym.getAnnotationTypeMetadata().setRepeatable(v.repeatable);
+            tree.sym.getAnnotationTypeMetadata().setTarget(v.target);
+        } finally {
+            log.useSource(prev);
+        }
+    }
+
+    public Attribute unfinishedDefaultValue() {
+        return theUnfinishedDefaultValue;
+    }
+
+    public static interface AnnotationTypeCompleter {
+        void complete(ClassSymbol sym) throws CompletionFailure;
+    }
+
+    /** Visitor to determine a prototype annotation type for a class declaring an annotation type.
+     *
+     *  <p><b>This is NOT part of any supported API.
+     *  If you write code that depends on this, you do so at your own risk.
+     *  This code and its internal interfaces are subject to change or
+     *  deletion without notice.</b>
+     */
+    public class AnnotationTypeVisitor extends TreeScanner {
+        private Env<AttrContext> env;
+
+        private final Attr attr;
+        private final Check check;
+        private final Symtab tab;
+        private final TypeEnvs typeEnvs;
+
+        private Compound target;
+        private Compound repeatable;
+
+        public AnnotationTypeVisitor(Attr attr, Check check, Symtab tab, TypeEnvs typeEnvs) {
+            this.attr = attr;
+            this.check = check;
+            this.tab = tab;
+            this.typeEnvs = typeEnvs;
+        }
+
+        public Compound getRepeatable() {
+            return repeatable;
+        }
+
+        public Compound getTarget() {
+            return target;
+        }
+
+        public void scanAnnotationType(JCClassDecl decl) {
+            visitClassDef(decl);
+        }
+
+        @Override
+        public void visitClassDef(JCClassDecl tree) {
+            Env<AttrContext> prevEnv = env;
+            env = typeEnvs.get(tree.sym);
+            try {
+                scan(tree.mods); // look for repeatable and target
+                // don't descend into body
+            } finally {
+                env = prevEnv;
+            }
+        }
+
+        @Override
+        public void visitAnnotation(JCAnnotation tree) {
+            Type t = tree.annotationType.type;
+            if (t == null) {
+                t = attr.attribType(tree.annotationType, env);
+                tree.annotationType.type = t = check.checkType(tree.annotationType.pos(), t, tab.annotationType);
+            }
+
+            if (t == tab.annotationTargetType) {
+                target = Annotate.this.attributeAnnotation(tree, tab.annotationTargetType, env);
+            } else if (t == tab.repeatableType) {
+                repeatable = Annotate.this.attributeAnnotation(tree, tab.repeatableType, env);
+            }
+        }
+    }
+
+    /** Represents the semantics of an Annotation Type.
+     *
+     *  <p><b>This is NOT part of any supported API.
+     *  If you write code that depends on this, you do so at your own risk.
+     *  This code and its internal interfaces are subject to change or
+     *  deletion without notice.</b>
+     */
+    public static class AnnotationTypeMetadata {
+        final ClassSymbol metaDataFor;
+        private Compound target;
+        private Compound repeatable;
+        private AnnotationTypeCompleter annotationTypeCompleter;
+
+        public AnnotationTypeMetadata(ClassSymbol metaDataFor, AnnotationTypeCompleter annotationTypeCompleter) {
+            this.metaDataFor = metaDataFor;
+            this.annotationTypeCompleter = annotationTypeCompleter;
+        }
+
+        private void init() {
+            // Make sure metaDataFor is member entered
+            while (metaDataFor.completer != null)
+                metaDataFor.complete();
+
+            if (annotationTypeCompleter != null) {
+                AnnotationTypeCompleter c = annotationTypeCompleter;
+                annotationTypeCompleter = null;
+                c.complete(metaDataFor);
+            }
+        }
+
+        public void complete() {
+            init();
+        }
+
+        public Compound getRepeatable() {
+            init();
+            return repeatable;
+        }
+
+        public void setRepeatable(Compound repeatable) {
+            Assert.checkNull(this.repeatable);
+            this.repeatable = repeatable;
+        }
+
+        public Compound getTarget() {
+            init();
+            return target;
+        }
+
+        public void setTarget(Compound target) {
+            Assert.checkNull(this.target);
+                this.target = target;
+        }
+
+        public Set<MethodSymbol> getAnnotationElements() {
+            init();
+            Set<MethodSymbol> members = new LinkedHashSet<>();
+            WriteableScope s = metaDataFor.members();
+            Iterable<Symbol> ss = s.getSymbols(NON_RECURSIVE);
+            for (Symbol sym : ss)
+                if (sym.kind == MTH &&
+                        sym.name != sym.name.table.names.clinit &&
+                        (sym.flags() & SYNTHETIC) == 0)
+                    members.add((MethodSymbol)sym);
+            return members;
+        }
+
+        public Set<MethodSymbol> getAnnotationElementsWithDefault() {
+            init();
+            Set<MethodSymbol> members = getAnnotationElements();
+            Set<MethodSymbol> res = new LinkedHashSet<>();
+            for (MethodSymbol m : members)
+                if (m.defaultValue != null)
+                    res.add(m);
+            return res;
+        }
+
+        @Override
+        public String toString() {
+            return "Annotation type for: " + metaDataFor;
+        }
+
+        public boolean isMetadataForAnnotationType() { return true; }
+
+        public static AnnotationTypeMetadata notAnAnnotationType() {
+            return NOT_AN_ANNOTATION_TYPE;
+        }
+
+        private static final AnnotationTypeMetadata NOT_AN_ANNOTATION_TYPE =
+                new AnnotationTypeMetadata(null, null) {
+                    @Override
+                    public void complete() {
+                    } // do nothing
+
+                    @Override
+                    public String toString() {
+                        return "Not an annotation type";
+                    }
+
+                    @Override
+                    public Set<MethodSymbol> getAnnotationElements() {
+                        return new LinkedHashSet<>(0);
+                    }
+
+                    @Override
+                    public Set<MethodSymbol> getAnnotationElementsWithDefault() {
+                        return new LinkedHashSet<>(0);
+                    }
+
+                    @Override
+                    public boolean isMetadataForAnnotationType() {
+                        return false;
+                    }
+
+                    @Override
+                    public Compound getTarget() {
+                        return null;
+                    }
+
+                    @Override
+                    public Compound getRepeatable() {
+                        return null;
+                    }
+                };
+    }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Apr 07 11:04:29 2015 -0700
@@ -40,6 +40,7 @@
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.code.TypeMetadata.Annotations;
 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
 import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
@@ -103,11 +104,11 @@
     final Target target;
     final Types types;
     final JCDiagnostic.Factory diags;
-    final Annotate annotate;
     final TypeAnnotations typeAnnotations;
     final DeferredLintHandler deferredLintHandler;
     final TypeEnvs typeEnvs;
     final Dependencies dependencies;
+    final Annotate annotate;
 
     public static Attr instance(Context context) {
         Attr instance = context.get(attrKey);
@@ -997,7 +998,7 @@
                 }
 
                 // Attribute all type annotations in the body
-                annotate.annotateTypeLater(tree.body, localEnv, m, null);
+                annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m, null);
                 annotate.flush();
 
                 // Attribute method body.
@@ -1020,16 +1021,16 @@
                 env.info.scope.enter(tree.sym);
             } else {
                 try {
-                    annotate.enterStart();
+                    annotate.blockAnnotations();
                     memberEnter.memberEnter(tree, env);
                 } finally {
-                    annotate.enterDone();
+                    annotate.unblockAnnotations();
                 }
             }
         } else {
             if (tree.init != null) {
                 // Field initializer expression need to be entered.
-                annotate.annotateTypeLater(tree.init, env, tree.sym, tree.pos());
+                annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym, tree.pos());
                 annotate.flush();
             }
         }
@@ -1090,7 +1091,7 @@
 
             if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++;
             // Attribute all type annotations in the block
-            annotate.annotateTypeLater(tree, localEnv, localEnv.info.scope.owner, null);
+            annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, localEnv.info.scope.owner, null);
             annotate.flush();
             attribStats(tree.stats, localEnv);
 
@@ -1953,9 +1954,16 @@
 
         // Attribute clazz expression and store
         // symbol + type back into the attributed tree.
-        Type clazztype = TreeInfo.isEnumInit(env.tree) ?
-            attribIdentAsEnumType(env, (JCIdent)clazz) :
-            attribType(clazz, env);
+        Type clazztype;
+
+        try {
+            env.info.isNewClass = true;
+            clazztype = TreeInfo.isEnumInit(env.tree) ?
+                attribIdentAsEnumType(env, (JCIdent)clazz) :
+                attribType(clazz, env);
+        } finally {
+            env.info.isNewClass = false;
+        }
 
         clazztype = chk.checkDiamond(tree, clazztype);
         chk.validate(clazz, localEnv);
@@ -4002,7 +4010,7 @@
         TypeVar typeVar = (TypeVar) tree.type;
 
         if (tree.annotations != null && tree.annotations.nonEmpty()) {
-            annotateType(tree, tree.annotations);
+            annotate.annotateTypeParameterSecondStage(tree, tree.annotations);
         }
 
         if (!typeVar.bound.isErroneous()) {
@@ -4092,45 +4100,17 @@
     }
 
     public void visitAnnotation(JCAnnotation tree) {
-        Assert.error("should be handled in Annotate");
+        Assert.error("should be handled in annotate");
     }
 
     public void visitAnnotatedType(JCAnnotatedType tree) {
-        Type underlyingType = attribType(tree.getUnderlyingType(), env);
-        this.attribAnnotationTypes(tree.annotations, env);
-        annotateType(tree, tree.annotations);
-        result = tree.type = underlyingType;
-    }
-
-    /**
-     * Apply the annotations to the particular type.
-     */
-    public void annotateType(final JCTree tree, final List<JCAnnotation> annotations) {
-        annotate.typeAnnotation(new Annotate.Worker() {
-            @Override
-            public String toString() {
-                return "annotate " + annotations + " onto " + tree;
-            }
-            @Override
-            public void run() {
-                List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
-                Assert.check(annotations.size() == compounds.size());
-                tree.type = tree.type.annotatedType(compounds);
-                }
-        });
-    }
-
-    private static List<Attribute.TypeCompound> fromAnnotations(List<JCAnnotation> annotations) {
-        if (annotations.isEmpty()) {
-            return List.nil();
-        }
-
-        ListBuffer<Attribute.TypeCompound> buf = new ListBuffer<>();
-        for (JCAnnotation anno : annotations) {
-            Assert.checkNonNull(anno.attribute);
-            buf.append((Attribute.TypeCompound) anno.attribute);
-        }
-        return buf.toList();
+        attribAnnotationTypes(tree.annotations, env);
+        Type underlyingType = attribType(tree.underlyingType, env);
+        Type annotatedType = underlyingType.annotatedType(Annotations.TO_BE_SET);
+
+        if (!env.info.isNewClass)
+            annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType);
+        result = tree.type = annotatedType;
     }
 
     public void visitErroneous(JCErroneous tree) {
@@ -4298,8 +4278,9 @@
                 log.error(tree.typarams.head.pos(),
                           "intf.annotation.cant.have.type.params");
 
-            // If this annotation has a @Repeatable, validate
-            Attribute.Compound repeatable = c.attribute(syms.repeatableType.tsym);
+            // If this annotation type has a @Repeatable, validate
+            Attribute.Compound repeatable = c.getAnnotationTypeMetadata().getRepeatable();
+            // If this annotation type has a @Repeatable, validate
             if (repeatable != null) {
                 // get diagnostic position for error reporting
                 DiagnosticPosition cbPos = getDiagnosticPosition(tree, repeatable.type);
@@ -4675,7 +4656,7 @@
             // This method will raise an error for such a type.
             for (JCAnnotation ai : annotations) {
                 if (!ai.type.isErroneous() &&
-                        typeAnnotations.annotationType(ai.attribute, sym) == TypeAnnotations.AnnotationType.DECLARATION) {
+                        typeAnnotations.annotationTargetType(ai.attribute, sym) == TypeAnnotations.AnnotationType.DECLARATION) {
                     log.error(ai.pos(), "annotation.type.not.applicable");
                 }
             }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Tue Apr 07 11:04:29 2015 -0700
@@ -68,6 +68,11 @@
      */
     boolean isAnonymousDiamond = false;
 
+    /**
+     *  Is this an attribution environment for an instance creation expression?
+     */
+    boolean isNewClass = false;
+
     /** Are arguments to current function applications boxed into an array for varargs?
      */
     Resolve.MethodResolutionPhase pendingResolutionPhase = null;
@@ -106,6 +111,7 @@
         info.isSerializable = isSerializable;
         info.isSpeculative = isSpeculative;
         info.isAnonymousDiamond = isAnonymousDiamond;
+        info.isNewClass = isNewClass;
         return info;
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Apr 07 11:04:29 2015 -0700
@@ -31,6 +31,7 @@
 
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
@@ -81,6 +82,7 @@
     private final DeferredAttr deferredAttr;
     private final Infer infer;
     private final Types types;
+    private final TypeAnnotations typeAnnotations;
     private final JCDiagnostic.Factory diags;
     private boolean warnOnSyntheticConflicts;
     private boolean suppressAbortOnBadClassFile;
@@ -120,6 +122,7 @@
         deferredAttr = DeferredAttr.instance(context);
         infer = Infer.instance(context);
         types = Types.instance(context);
+        typeAnnotations = TypeAnnotations.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
         Options options = Options.instance(context);
         lint = Lint.instance(context);
@@ -526,7 +529,7 @@
      *  @param found      The type that was found.
      *  @param req        The type that was required.
      */
-    Type checkType(DiagnosticPosition pos, Type found, Type req) {
+    public Type checkType(DiagnosticPosition pos, Type found, Type req) {
         return checkType(pos, found, req, basicHandler);
     }
 
@@ -587,7 +590,7 @@
                 public void report() {
                     if (lint.isEnabled(Lint.LintCategory.CAST))
                         log.warning(Lint.LintCategory.CAST,
-                                tree.pos(), "redundant.cast", tree.expr.type);
+                                tree.pos(), "redundant.cast", tree.clazz.type);
                 }
             });
         }
@@ -2830,7 +2833,7 @@
         }
     }
 
-    private void validateRetention(Symbol container, Symbol contained, DiagnosticPosition pos) {
+    private void validateRetention(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) {
         Attribute.RetentionPolicy containerRetention = types.getRetention(container);
         Attribute.RetentionPolicy containedRetention = types.getRetention(contained);
 
@@ -2869,7 +2872,7 @@
         }
     }
 
-    private void validateTarget(Symbol container, Symbol contained, DiagnosticPosition pos) {
+    private void validateTarget(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) {
         // The set of targets the container is applicable to must be a subset
         // (with respect to annotation target semantics) of the set of targets
         // the contained is applicable to. The target sets may be implicit or
@@ -2996,33 +2999,19 @@
 
     /** Is the annotation applicable to types? */
     protected boolean isTypeAnnotation(JCAnnotation a, boolean isTypeParameter) {
-        Attribute.Compound atTarget =
-            a.annotationType.type.tsym.attribute(syms.annotationTargetType.tsym);
-        if (atTarget == null) {
-            // An annotation without @Target is not a type annotation.
-            return false;
-        }
-
-        Attribute atValue = atTarget.member(names.value);
-        if (!(atValue instanceof Attribute.Array)) {
-            return false; // error recovery
+        List<Attribute> targets = typeAnnotations.annotationTargets(a.attribute);
+        return (targets == null) ?
+                false :
+                targets.stream()
+                        .anyMatch(attr -> isTypeAnnotation(attr, isTypeParameter));
+    }
+    //where
+        boolean isTypeAnnotation(Attribute a, boolean isTypeParameter) {
+            Attribute.Enum e = (Attribute.Enum)a;
+            return (e.value.name == names.TYPE_USE ||
+                    (isTypeParameter && e.value.name == names.TYPE_PARAMETER));
         }
 
-        Attribute.Array arr = (Attribute.Array) atValue;
-        for (Attribute app : arr.values) {
-            if (!(app instanceof Attribute.Enum)) {
-                return false; // recovery
-            }
-            Attribute.Enum e = (Attribute.Enum) app;
-
-            if (e.value.name == names.TYPE_USE)
-                return true;
-            else if (isTypeParameter && e.value.name == names.TYPE_PARAMETER)
-                return true;
-        }
-        return false;
-    }
-
     /** Is the annotation applicable to the symbol? */
     boolean annotationApplicable(JCAnnotation a, Symbol s) {
         Attribute.Array arr = getAttributeTargetAttribute(a.annotationType.type.tsym);
@@ -3043,51 +3032,55 @@
             }
         }
         for (Name target : targets) {
-            if (target == names.TYPE)
-                { if (s.kind == TYP) return true; }
-            else if (target == names.FIELD)
-                { if (s.kind == VAR && s.owner.kind != MTH) return true; }
-            else if (target == names.METHOD)
-                { if (s.kind == MTH && !s.isConstructor()) return true; }
-            else if (target == names.PARAMETER)
-                { if (s.kind == VAR && s.owner.kind == MTH &&
-                      (s.flags() & PARAMETER) != 0)
+            if (target == names.TYPE) {
+                if (s.kind == TYP)
+                    return true;
+            } else if (target == names.FIELD) {
+                if (s.kind == VAR && s.owner.kind != MTH)
                     return true;
-                }
-            else if (target == names.CONSTRUCTOR)
-                { if (s.kind == MTH && s.isConstructor()) return true; }
-            else if (target == names.LOCAL_VARIABLE)
-                { if (s.kind == VAR && s.owner.kind == MTH &&
-                      (s.flags() & PARAMETER) == 0)
+            } else if (target == names.METHOD) {
+                if (s.kind == MTH && !s.isConstructor())
+                    return true;
+            } else if (target == names.PARAMETER) {
+                if (s.kind == VAR && s.owner.kind == MTH &&
+                      (s.flags() & PARAMETER) != 0) {
                     return true;
                 }
-            else if (target == names.ANNOTATION_TYPE)
-                { if (s.kind == TYP && (s.flags() & ANNOTATION) != 0)
+            } else if (target == names.CONSTRUCTOR) {
+                if (s.kind == MTH && s.isConstructor())
+                    return true;
+            } else if (target == names.LOCAL_VARIABLE) {
+                if (s.kind == VAR && s.owner.kind == MTH &&
+                      (s.flags() & PARAMETER) == 0) {
+                    return true;
+                }
+            } else if (target == names.ANNOTATION_TYPE) {
+                if (s.kind == TYP && (s.flags() & ANNOTATION) != 0) {
                     return true;
                 }
-            else if (target == names.PACKAGE)
-                { if (s.kind == PCK) return true; }
-            else if (target == names.TYPE_USE)
-                { if (s.kind == TYP || s.kind == VAR ||
-                      (s.kind == MTH && !s.isConstructor() &&
-                      !s.type.getReturnType().hasTag(VOID)) ||
-                      (s.kind == MTH && s.isConstructor()))
+            } else if (target == names.PACKAGE) {
+                if (s.kind == PCK)
+                    return true;
+            } else if (target == names.TYPE_USE) {
+                if (s.kind == TYP || s.kind == VAR ||
+                        (s.kind == MTH && !s.isConstructor() &&
+                                !s.type.getReturnType().hasTag(VOID)) ||
+                        (s.kind == MTH && s.isConstructor())) {
                     return true;
                 }
-            else if (target == names.TYPE_PARAMETER)
-                { if (s.kind == TYP && s.type.hasTag(TYPEVAR))
+            } else if (target == names.TYPE_PARAMETER) {
+                if (s.kind == TYP && s.type.hasTag(TYPEVAR))
                     return true;
-                }
-            else
-                return true; // recovery
+            } else
+                return true; // Unknown ElementType. This should be an error at declaration site,
+                             // assume applicable.
         }
         return false;
     }
 
 
-    Attribute.Array getAttributeTargetAttribute(Symbol s) {
-        Attribute.Compound atTarget =
-            s.attribute(syms.annotationTargetType.tsym);
+    Attribute.Array getAttributeTargetAttribute(TypeSymbol s) {
+        Attribute.Compound atTarget = s.getAnnotationTypeMetadata().getTarget();
         if (atTarget == null) return null; // ok, is applicable
         Attribute atValue = atTarget.member(names.value);
         if (!(atValue instanceof Attribute.Array)) return null; // error recovery
@@ -3117,32 +3110,33 @@
 
     private boolean validateAnnotation(JCAnnotation a) {
         boolean isValid = true;
+        AnnotationTypeMetadata metadata = a.annotationType.type.tsym.getAnnotationTypeMetadata();
+
         // collect an inventory of the annotation elements
-        Set<MethodSymbol> members = new LinkedHashSet<>();
-        for (Symbol sym : a.annotationType.type.tsym.members().getSymbols(NON_RECURSIVE))
-            if (sym.kind == MTH && sym.name != names.clinit &&
-                    (sym.flags() & SYNTHETIC) == 0)
-                members.add((MethodSymbol) sym);
+        Set<MethodSymbol> elements = metadata.getAnnotationElements();
 
         // remove the ones that are assigned values
         for (JCTree arg : a.args) {
             if (!arg.hasTag(ASSIGN)) continue; // recovery
-            JCAssign assign = (JCAssign) arg;
+            JCAssign assign = (JCAssign)arg;
             Symbol m = TreeInfo.symbol(assign.lhs);
             if (m == null || m.type.isErroneous()) continue;
-            if (!members.remove(m)) {
+            if (!elements.remove(m)) {
                 isValid = false;
                 log.error(assign.lhs.pos(), "duplicate.annotation.member.value",
-                          m.name, a.type);
+                        m.name, a.type);
             }
         }
 
         // all the remaining ones better have default values
         List<Name> missingDefaults = List.nil();
-        for (MethodSymbol m : members) {
-            if (m.defaultValue == null && !m.type.isErroneous()) {
+        Set<MethodSymbol> membersWithDefault = metadata.getAnnotationElementsWithDefault();
+        for (MethodSymbol m : elements) {
+            if (m.type.isErroneous())
+                continue;
+
+            if (!membersWithDefault.contains(m))
                 missingDefaults = missingDefaults.append(m.name);
-            }
         }
         missingDefaults = missingDefaults.reverse();
         if (missingDefaults.nonEmpty()) {
@@ -3153,12 +3147,18 @@
             log.error(a.pos(), key, a.type, missingDefaults);
         }
 
+        return isValid && validateTargetAnnotationValue(a);
+    }
+
+    /* Validate the special java.lang.annotation.Target annotation */
+    boolean validateTargetAnnotationValue(JCAnnotation a) {
         // special case: java.lang.annotation.Target must not have
         // repeated values in its value member
         if (a.annotationType.type.tsym != syms.annotationTargetType.tsym ||
-            a.args.tail == null)
-            return isValid;
-
+                a.args.tail == null)
+            return true;
+
+        boolean isValid = true;
         if (!a.args.head.hasTag(ASSIGN)) return false; // error recovery
         JCAssign assign = (JCAssign) a.args.head;
         Symbol m = TreeInfo.symbol(assign.lhs);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Apr 07 11:04:29 2015 -0700
@@ -176,14 +176,14 @@
         SpeculativeCache speculativeCache;
 
         DeferredType(JCExpression tree, Env<AttrContext> env) {
-            super(null, TypeMetadata.empty);
+            super(null, TypeMetadata.EMPTY);
             this.tree = tree;
             this.env = attr.copyEnv(env);
             this.speculativeCache = new SpeculativeCache();
         }
 
         @Override
-        public DeferredType clone(TypeMetadata md) {
+        public DeferredType cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Cannot add metadata to a deferred type");
         }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java	Tue Apr 07 11:04:29 2015 -0700
@@ -25,7 +25,6 @@
 
 package com.sun.tools.javac.comp;
 
-import java.util.*;
 import javax.tools.JavaFileObject;
 import javax.tools.JavaFileManager;
 
@@ -34,7 +33,6 @@
 import com.sun.tools.javac.code.Scope.*;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
-import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.main.Option.PkgInfo;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -87,11 +85,11 @@
 public class Enter extends JCTree.Visitor {
     protected static final Context.Key<Enter> enterKey = new Context.Key<>();
 
+    Annotate annotate;
     Log log;
     Symtab syms;
     Check chk;
     TreeMaker make;
-    Annotate annotate;
     TypeEnter typeEnter;
     Types types;
     Lint lint;
@@ -253,11 +251,13 @@
         Env<AttrContext> prevEnv = this.env;
         try {
             this.env = env;
+            annotate.blockAnnotations();
             tree.accept(this);
             return result;
         }  catch (CompletionFailure ex) {
             return chk.completionError(tree.pos(), ex);
         } finally {
+            annotate.unblockAnnotations();
             this.env = prevEnv;
         }
     }
@@ -474,7 +474,7 @@
      *  @param c          The class symbol to be processed or null to process all.
      */
     public void complete(List<JCCompilationUnit> trees, ClassSymbol c) {
-        annotate.enterStart();
+        annotate.blockAnnotations();
         ListBuffer<ClassSymbol> prevUncompleted = uncompleted;
         if (typeEnter.completionEnabled) uncompleted = new ListBuffer<>();
 
@@ -497,7 +497,7 @@
             }
         } finally {
             uncompleted = prevUncompleted;
-            annotate.enterDone();
+            annotate.unblockAnnotations();
         }
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Tue Apr 07 11:04:29 2015 -0700
@@ -2766,20 +2766,6 @@
             return translationMap;
         }
 
-    public void visitAnnotatedType(JCAnnotatedType tree) {
-        // No need to retain type annotations in the tree
-        // tree.annotations = translate(tree.annotations);
-        tree.annotations = List.nil();
-        tree.underlyingType = translate(tree.underlyingType);
-        // but maintain type annotations in the type.
-        if (tree.type.isAnnotated()) {
-            tree.type = tree.underlyingType.type.annotatedType(tree.type.getAnnotationMirrors());
-        } else if (tree.underlyingType.type.isAnnotated()) {
-            tree.type = tree.underlyingType.type;
-        }
-        result = tree;
-    }
-
     public void visitTypeCast(JCTypeCast tree) {
         tree.clazz = translate(tree.clazz);
         if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, 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
@@ -25,8 +25,6 @@
 
 package com.sun.tools.javac.comp;
 
-import javax.tools.JavaFileObject;
-
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.tree.*;
@@ -224,10 +222,12 @@
         annotate.annotateLater(tree.mods.annotations, localEnv, m, tree.pos());
         // Visit the signature of the method. Note that
         // TypeAnnotate doesn't descend into the body.
-        annotate.annotateTypeLater(tree, localEnv, m, tree.pos());
+        annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m, tree.pos());
 
-        if (tree.defaultValue != null)
-            annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree.pos());
+        if (tree.defaultValue != null) {
+            m.defaultValue = annotate.unfinishedDefaultValue(); // set it to temporary sentinel for now
+            annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree.pos());
+        }
     }
 
     /** Create a fresh environment for method bodies.
@@ -255,6 +255,7 @@
             localEnv.info.staticLevel++;
         }
         DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
+
         try {
             if (TreeInfo.isEnumInit(tree)) {
                 attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
@@ -297,7 +298,7 @@
         }
 
         annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
-        annotate.annotateTypeLater(tree.vartype, localEnv, v, tree.pos());
+        annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
 
         v.pos = tree.pos;
     }
@@ -434,53 +435,4 @@
         Env<AttrContext> iEnv = initEnv(tree, env);
         return iEnv;
     }
-
-    /** Queue processing of an attribute default value. */
-    void annotateDefaultValueLater(final JCExpression defaultValue,
-                                   final Env<AttrContext> localEnv,
-                                   final MethodSymbol m,
-                                   final DiagnosticPosition deferPos) {
-        annotate.normal(new Annotate.Worker() {
-                @Override
-                public String toString() {
-                    return "annotate " + m.owner + "." +
-                        m + " default " + defaultValue;
-                }
-
-                @Override
-                public void run() {
-                    JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
-                    DiagnosticPosition prevLintPos = deferredLintHandler.setPos(deferPos);
-                    try {
-                        enterDefaultValue(defaultValue, localEnv, m);
-                    } finally {
-                        deferredLintHandler.setPos(prevLintPos);
-                        log.useSource(prev);
-                    }
-                }
-            });
-        annotate.validate(new Annotate.Worker() { //validate annotations
-            @Override
-            public void run() {
-                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
-                try {
-                    // if default value is an annotation, check it is a well-formed
-                    // annotation value (e.g. no duplicate values, no missing values, etc.)
-                    chk.validateAnnotationTree(defaultValue);
-                } finally {
-                    log.useSource(prev);
-                }
-            }
-        });
-    }
-
-    /** Enter a default value for an attribute method. */
-    private void enterDefaultValue(final JCExpression defaultValue,
-                                   final Env<AttrContext> localEnv,
-                                   final MethodSymbol m) {
-        m.defaultValue = annotate.enterAttributeValue(m.type.getReturnType(),
-                                                      defaultValue,
-                                                      localEnv);
-    }
-
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Tue Apr 07 11:04:29 2015 -0700
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Attribute.TypeCompound;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -68,6 +69,7 @@
     private TreeMaker make;
     private Enter enter;
     private Types types;
+    private Annotate annotate;
     private final Resolve resolve;
     private final CompileStates compileStates;
 
@@ -91,6 +93,7 @@
         Source source = Source.instance(context);
         allowInterfaceBridges = source.allowDefaultMethods();
         allowGraphInference = source.allowGraphInference();
+        annotate = Annotate.instance(context);
     }
 
     /** A hashtable mapping bridge methods to the methods they override after
@@ -751,6 +754,15 @@
         result = tree;
     }
 
+    public void visitAnnotatedType(JCAnnotatedType tree) {
+        // For now, we need to keep the annotations in the tree because of the current
+        // MultiCatch implementation wrt type annotations
+        List<TypeCompound> mirrors = annotate.fromAnnotations(tree.annotations);
+        tree.underlyingType = translate(tree.underlyingType);
+        tree.type = tree.underlyingType.type.annotatedType(mirrors);
+        result = tree;
+    }
+
     public void visitTypeCast(JCTypeCast tree) {
         tree.clazz = translate(tree.clazz, null);
         Type originalTarget = tree.type;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, 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
@@ -36,6 +36,7 @@
 import com.sun.tools.javac.code.Scope.NamedImportScope;
 import com.sun.tools.javac.code.Scope.StarImportScope;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -135,6 +136,7 @@
         lint = Lint.instance(context);
         typeEnvs = TypeEnvs.instance(context);
         dependencies = Dependencies.instance(context);
+        Source source = Source.instance(context);
         allowTypeAnnos = source.allowTypeAnnotations();
         allowDeprecationOnImport = source.allowDeprecationOnImport();
     }
@@ -164,7 +166,7 @@
                 Env<AttrContext> topEnv = enter.topLevelEnv(tree);
                 finishImports(tree, () -> { completeClass.resolveImports(tree, topEnv); });
             }
-       }
+        }
     }
 
 /* ********************************************************************
@@ -184,7 +186,7 @@
         }
 
         try {
-            annotate.enterStart();
+            annotate.blockAnnotations();
             sym.flags_field |= UNATTRIBUTED;
 
             List<Env<AttrContext>> queue;
@@ -206,7 +208,7 @@
                 }
             }
         } finally {
-            annotate.enterDone();
+            annotate.unblockAnnotations();
         }
     }
 
@@ -780,9 +782,9 @@
             Env<AttrContext> baseEnv = baseEnv(tree, env);
 
             if (tree.extending != null)
-                annotate.annotateTypeLater(tree.extending, baseEnv, sym, tree.pos());
+                annotate.queueScanTreeAndTypeAnnotate(tree.extending, baseEnv, sym, tree.pos());
             for (JCExpression impl : tree.implementing)
-                annotate.annotateTypeLater(impl, baseEnv, sym, tree.pos());
+                annotate.queueScanTreeAndTypeAnnotate(impl, baseEnv, sym, tree.pos());
             annotate.flush();
 
             attribSuperTypes(env, baseEnv);
@@ -800,7 +802,7 @@
 
             attr.attribTypeVariables(tree.typarams, baseEnv);
             for (JCTypeParameter tp : tree.typarams)
-                annotate.annotateTypeLater(tp, baseEnv, sym, tree.pos());
+                annotate.queueScanTreeAndTypeAnnotate(tp, baseEnv, sym, tree.pos());
 
             // check that no package exists with same fully qualified name,
             // but admit classes in the unnamed package which have the same
@@ -899,6 +901,11 @@
                 addEnumMembers(tree, env);
             }
             memberEnter.memberEnter(tree.defs, env);
+
+            if (tree.sym.isAnnotationType()) {
+                Assert.checkNull(tree.sym.completer);
+                tree.sym.setAnnotationTypeMetadata(new AnnotationTypeMetadata(tree.sym, annotate.annotationTypeSourceCompleter()));
+            }
         }
 
         /** Add the implicit members for an enum type
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Tue Apr 07 11:04:29 2015 -0700
@@ -36,17 +36,17 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-
 import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
-
+import com.sun.tools.javac.comp.Annotate;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Type.*;
-import com.sun.tools.javac.comp.Annotate;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.file.BaseFileObject;
 import com.sun.tools.javac.jvm.ClassFile.NameAndType;
 import com.sun.tools.javac.jvm.ClassFile.Version;
@@ -81,7 +81,7 @@
 
     public static final int INITIAL_BUFFER_SIZE = 0x0fff0;
 
-    Annotate annotate;
+    private final Annotate annotate;
 
     /** Switch: verbose output.
      */
@@ -190,6 +190,18 @@
      */
     Set<Name> warnedAttrs = new HashSet<>();
 
+    /**
+     * The prototype @Target Attribute.Compound if this class is an annotation annotated with
+     * @Target
+     */
+    CompoundAnnotationProxy target;
+
+    /**
+     * The prototype @Repetable Attribute.Compound if this class is an annotation annotated with
+     * @Repeatable
+     */
+    CompoundAnnotationProxy repeatable;
+
     /** Get the ClassReader instance for this invocation. */
     public static ClassReader instance(Context context) {
         ClassReader instance = context.get(classReaderKey);
@@ -201,6 +213,7 @@
     /** Construct a new class reader. */
     protected ClassReader(Context context) {
         context.put(classReaderKey, this);
+        annotate = Annotate.instance(context);
         names = Names.instance(context);
         syms = Symtab.instance(context);
         types = Types.instance(context);
@@ -212,9 +225,8 @@
         log = Log.instance(context);
 
         Options options = Options.instance(context);
-        annotate = Annotate.instance(context);
-        verbose        = options.isSet(VERBOSE);
-        checkClassFile = options.isSet("-checkclassfile");
+        verbose         = options.isSet(VERBOSE);
+        checkClassFile  = options.isSet("-checkclassfile");
 
         Source source = Source.instance(context);
         allowSimplifiedVarargs = source.allowSimplifiedVarargs();
@@ -1304,6 +1316,13 @@
             ListBuffer<CompoundAnnotationProxy> proxies = new ListBuffer<>();
             for (int i = 0; i<numAttributes; i++) {
                 CompoundAnnotationProxy proxy = readCompoundAnnotation();
+
+                if (proxy.type.tsym == syms.annotationTargetType.tsym) {
+                    target = proxy;
+                } else if (proxy.type.tsym == syms.repeatableType.tsym) {
+                    repeatable = proxy;
+                }
+
                 proxies.append(proxy);
             }
             annotate.normal(new AnnotationCompleter(sym, proxies.toList()));
@@ -1705,8 +1724,11 @@
     }
 
     class AnnotationDeproxy implements ProxyVisitor {
-        private ClassSymbol requestingOwner = currentOwner.kind == MTH
-            ? currentOwner.enclClass() : (ClassSymbol)currentOwner;
+        private ClassSymbol requestingOwner;
+
+        AnnotationDeproxy(ClassSymbol owner) {
+            this.requestingOwner = owner;
+        }
 
         List<Attribute.Compound> deproxyCompoundList(List<CompoundAnnotationProxy> pl) {
             // also must fill in types!!!!
@@ -1855,19 +1877,19 @@
         }
     }
 
-    class AnnotationDefaultCompleter extends AnnotationDeproxy implements Annotate.Worker {
+    class AnnotationDefaultCompleter extends AnnotationDeproxy implements Runnable {
         final MethodSymbol sym;
         final Attribute value;
         final JavaFileObject classFile = currentClassFile;
-        @Override
-        public String toString() {
-            return " ClassReader store default for " + sym.owner + "." + sym + " is " + value;
-        }
+
         AnnotationDefaultCompleter(MethodSymbol sym, Attribute value) {
+            super(currentOwner.kind == MTH
+                    ? currentOwner.enclClass() : (ClassSymbol)currentOwner);
             this.sym = sym;
             this.value = value;
         }
-        // implement Annotate.Worker.run()
+
+        @Override
         public void run() {
             JavaFileObject previousClassFile = currentClassFile;
             try {
@@ -1880,22 +1902,27 @@
                 currentClassFile = previousClassFile;
             }
         }
+
+        @Override
+        public String toString() {
+            return " ClassReader store default for " + sym.owner + "." + sym + " is " + value;
+        }
     }
 
-    class AnnotationCompleter extends AnnotationDeproxy implements Annotate.Worker {
+    class AnnotationCompleter extends AnnotationDeproxy implements Runnable {
         final Symbol sym;
         final List<CompoundAnnotationProxy> l;
         final JavaFileObject classFile;
-        @Override
-        public String toString() {
-            return " ClassReader annotate " + sym.owner + "." + sym + " with " + l;
-        }
+
         AnnotationCompleter(Symbol sym, List<CompoundAnnotationProxy> l) {
+            super(currentOwner.kind == MTH
+                    ? currentOwner.enclClass() : (ClassSymbol)currentOwner);
             this.sym = sym;
             this.l = l;
             this.classFile = currentClassFile;
         }
-        // implement Annotate.Worker.run()
+
+        @Override
         public void run() {
             JavaFileObject previousClassFile = currentClassFile;
             try {
@@ -1910,6 +1937,11 @@
                 currentClassFile = previousClassFile;
             }
         }
+
+        @Override
+        public String toString() {
+            return " ClassReader annotate " + sym.owner + "." + sym + " with " + l;
+        }
     }
 
     class TypeAnnotationCompleter extends AnnotationCompleter {
@@ -2298,6 +2330,8 @@
         currentClassFile = c.classfile;
         warnedAttrs.clear();
         filling = true;
+        target = null;
+        repeatable = null;
         try {
             bp = 0;
             buf = readInputStream(buf, c.classfile.openInputStream());
@@ -2318,6 +2352,12 @@
                 Name name = missingTypeVariables.head.tsym.name;
                 throw badClassFile("undecl.type.var", name);
             }
+
+            if ((c.flags_field & Flags.ANNOTATION) != 0) {
+                c.setAnnotationTypeMetadata(new AnnotationTypeMetadata(c, new CompleterDeproxy(c, target, repeatable)));
+            } else {
+                c.setAnnotationTypeMetadata(AnnotationTypeMetadata.notAnAnnotationType());
+            }
         } catch (IOException ex) {
             throw badClassFile("unable.to.access.file", ex.getMessage());
         } catch (ArrayIndexOutOfBoundsException ex) {
@@ -2515,4 +2555,42 @@
             return name.hashCode();
         }
     }
+
+    private class CompleterDeproxy implements AnnotationTypeCompleter {
+        ClassSymbol proxyOn;
+        CompoundAnnotationProxy target;
+        CompoundAnnotationProxy repeatable;
+
+        public CompleterDeproxy(ClassSymbol c, CompoundAnnotationProxy target,
+                CompoundAnnotationProxy repeatable)
+        {
+            this.proxyOn = c;
+            this.target = target;
+            this.repeatable = repeatable;
+        }
+
+        @Override
+        public void complete(ClassSymbol sym) {
+            Assert.check(proxyOn == sym);
+            Attribute.Compound theTarget = null, theRepeatable = null;
+            AnnotationDeproxy deproxy;
+
+            try {
+                if (target != null) {
+                    deproxy = new AnnotationDeproxy(proxyOn);
+                    theTarget = deproxy.deproxyCompound(target);
+                }
+
+                if (repeatable != null) {
+                    deproxy = new AnnotationDeproxy(proxyOn);
+                    theRepeatable = deproxy.deproxyCompound(repeatable);
+                }
+            } catch (Exception e) {
+                throw new CompletionFailure(sym, e.getMessage());
+            }
+
+            sym.getAnnotationTypeMetadata().setTarget(theTarget);
+            sym.getAnnotationTypeMetadata().setRepeatable(theRepeatable);
+        }
+    }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue Apr 07 11:04:29 2015 -0700
@@ -75,6 +75,7 @@
     private final Types types;
     private final Lower lower;
     private final Flow flow;
+    private final Annotate annotate;
 
     /** Format of stackmap tables to be generated. */
     private final Code.StackMapFormat stackMap;
@@ -142,6 +143,7 @@
         }
         this.jsrlimit = setjsrlimit;
         this.useJsrLocally = false; // reset in visitTry
+        annotate = Annotate.instance(context);
     }
 
     /** Switches
@@ -1468,21 +1470,18 @@
                       int startpc, int endpc,
                       List<Integer> gaps) {
             if (startpc != endpc) {
-                List<JCExpression> subClauses = TreeInfo.isMultiCatch(tree) ?
-                        ((JCTypeUnion)tree.param.vartype).alternatives :
-                        List.of(tree.param.vartype);
+                List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypeExprs
+                        = catchTypesWithAnnotations(tree);
                 while (gaps.nonEmpty()) {
-                    for (JCExpression subCatch : subClauses) {
+                    for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) {
+                        JCExpression subCatch = subCatch1.snd;
                         int catchType = makeRef(tree.pos(), subCatch.type);
                         int end = gaps.head.intValue();
                         registerCatch(tree.pos(),
                                       startpc,  end, code.curCP(),
                                       catchType);
-                        if (subCatch.type.isAnnotated()) {
-                            for (Attribute.TypeCompound tc :
-                                     subCatch.type.getAnnotationMirrors()) {
+                        for (Attribute.TypeCompound tc :  subCatch1.fst) {
                                 tc.position.setCatchInfo(catchType, startpc);
-                            }
                         }
                     }
                     gaps = gaps.tail;
@@ -1490,16 +1489,14 @@
                     gaps = gaps.tail;
                 }
                 if (startpc < endpc) {
-                    for (JCExpression subCatch : subClauses) {
+                    for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) {
+                        JCExpression subCatch = subCatch1.snd;
                         int catchType = makeRef(tree.pos(), subCatch.type);
                         registerCatch(tree.pos(),
                                       startpc, endpc, code.curCP(),
                                       catchType);
-                        if (subCatch.type.isAnnotated()) {
-                            for (Attribute.TypeCompound tc :
-                                     subCatch.type.getAnnotationMirrors()) {
-                                tc.position.setCatchInfo(catchType, startpc);
-                            }
+                        for (Attribute.TypeCompound tc :  subCatch1.fst) {
+                            tc.position.setCatchInfo(catchType, startpc);
                         }
                     }
                 }
@@ -1507,7 +1504,7 @@
                 code.statBegin(tree.pos);
                 code.markStatBegin();
                 int limit = code.nextreg;
-                int exlocal = code.newLocal(exparam);
+                code.newLocal(exparam);
                 items.makeLocalItem(exparam).store();
                 code.statBegin(TreeInfo.firstStatPos(tree.body));
                 genStat(tree.body, env, CRT_BLOCK);
@@ -1515,6 +1512,30 @@
                 code.statBegin(TreeInfo.endPos(tree.body));
             }
         }
+        // where
+        List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotations(JCCatch tree) {
+            return TreeInfo.isMultiCatch(tree) ?
+                    catchTypesWithAnnotationsFromMulticatch((JCTypeUnion)tree.param.vartype, tree.param.sym.getRawTypeAttributes()) :
+                    List.of(new Pair<>(tree.param.sym.getRawTypeAttributes(), tree.param.vartype));
+        }
+        // where
+        List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotationsFromMulticatch(JCTypeUnion tree, List<TypeCompound> first) {
+            List<JCExpression> alts = tree.alternatives;
+            List<Pair<List<TypeCompound>, JCExpression>> res = List.of(new Pair<>(first, alts.head));
+            alts = alts.tail;
+
+            while(alts != null && alts.head != null) {
+                JCExpression alt = alts.head;
+                if (alt instanceof JCAnnotatedType) {
+                    JCAnnotatedType a = (JCAnnotatedType)alt;
+                    res = res.prepend(new Pair<>(annotate.fromAnnotations(a.annotations), alt));
+                } else {
+                    res = res.prepend(new Pair<>(List.nil(), alt));
+                }
+                alts = alts.tail;
+            }
+            return res.reverse();
+        }
 
         /** Register a catch clause in the "Exceptions" code-attribute.
          */
@@ -2052,7 +2073,7 @@
             code.emitop2(new_, makeRef(pos, stringBufferType));
             code.emitop0(dup);
             callMethod(
-                pos, stringBufferType, names.init, List.<Type>nil(), false);
+                    pos, stringBufferType, names.init, List.<Type>nil(), false);
         }
 
         /** Append value (on tos) to string buffer (on tos - 1).
@@ -2100,11 +2121,11 @@
          */
         void bufferToString(DiagnosticPosition pos) {
             callMethod(
-                pos,
-                stringBufferType,
-                names.toString,
-                List.<Type>nil(),
-                false);
+                    pos,
+                    stringBufferType,
+                    names.toString,
+                    List.<Type>nil(),
+                    false);
         }
 
         /** Complete generating code for operation, with left operand
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/UninitializedType.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/UninitializedType.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, 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
@@ -59,7 +59,7 @@
     }
 
     @Override
-    public UninitializedType clone(final TypeMetadata md) {
+    public UninitializedType cloneWithMetadata(final TypeMetadata md) {
         return new UninitializedType(tag, qtype, offset, md);
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, 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
@@ -25,11 +25,13 @@
 
 package com.sun.tools.javac.model;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
@@ -115,14 +117,17 @@
     @DefinedBy(Api.LANGUAGE_MODEL)
     public List<Type> directSupertypes(TypeMirror t) {
         validateTypeNotIn(t, EXEC_OR_PKG);
-        return types.directSupertypes((Type) t);
+        Type ty = (Type)t;
+        return types.directSupertypes(ty).stream()
+                .map(Type::stripMetadataIfNeeded)
+                .collect(Collectors.toList());
     }
 
     @DefinedBy(Api.LANGUAGE_MODEL)
     public TypeMirror erasure(TypeMirror t) {
         if (t.getKind() == TypeKind.PACKAGE)
             throw new IllegalArgumentException(t.toString());
-        return types.erasure((Type) t);
+        return types.erasure((Type)t).stripMetadataIfNeeded();
     }
 
     @DefinedBy(Api.LANGUAGE_MODEL)
@@ -143,7 +148,7 @@
     @DefinedBy(Api.LANGUAGE_MODEL)
     public TypeMirror capture(TypeMirror t) {
         validateTypeNotIn(t, EXEC_OR_PKG);
-        return types.capture((Type) t);
+        return types.capture((Type)t).stripMetadataIfNeeded();
     }
 
     @DefinedBy(Api.LANGUAGE_MODEL)
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, 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
@@ -34,8 +34,6 @@
 import javax.tools.JavaFileObject;
 
 import com.sun.source.tree.*;
-import com.sun.source.tree.LambdaExpressionTree.BodyKind;
-import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Scope.*;
 import com.sun.tools.javac.code.Symbol.*;
@@ -2502,12 +2500,6 @@
 
         public JCTree annotationType;
         public List<JCExpression> args;
-
-        // Attribute.Compound if tag is ANNOTATION
-        // Attribute.TypeCompound if tag is TYPE_ANNOTATION
-        //
-        // NOTE: This field is slated for removal in the future.  Do
-        // not use it for anything new.
         public Attribute.Compound attribute;
 
         protected JCAnnotation(Tag tag, JCTree annotationType, List<JCExpression> args) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, 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
@@ -234,6 +234,8 @@
     }
 
     private boolean unique(TypeVar typevar) {
+        typevar = (TypeVar)typevar.stripMetadataIfNeeded();
+
         int found = 0;
         for (Type t : whereClauses.get(WhereClauseKind.TYPEVAR).keySet()) {
             if (t.toString().equals(typevar.toString())) {
@@ -542,6 +544,7 @@
 
         @Override
         public Void visitTypeVar(TypeVar t, Void ignored) {
+            t = (TypeVar)t.stripMetadataIfNeeded();
             if (indexOf(t, WhereClauseKind.TYPEVAR) == -1) {
                 //access the bound type and skip error types
                 Type bound = t.bound;
--- a/langtools/test/tools/javac/annotations/typeAnnotations/api/AnnotatedArrayOrder.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/api/AnnotatedArrayOrder.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, 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,6 +23,7 @@
 
 /*
  * @test
+ * @bug 8031744
  * @summary Checks the annotation types targeting array types
  */
 
@@ -34,7 +35,6 @@
 import java.util.Map;
 import java.util.HashMap;
 import java.lang.annotation.*;
-import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
 import com.sun.source.tree.*;
 import com.sun.source.util.JavacTask;
--- a/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/BasicTest.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/BasicTest.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2015, 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,7 +23,7 @@
 
 /*
  * @test
- * @bug 6843077 8006775
+ * @bug 6843077 8006775 8031744
  * @summary random tests for new locations
  * @author Matt Papi
  * @compile BasicTest.java
@@ -41,12 +41,16 @@
 @interface C {}
 @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
 @interface D {}
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@interface E {}
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@interface F {}
 
 /**
  * Tests basic JSR 308 parser functionality. We don't really care about what
  * the parse tree looks like, just that these annotations can be parsed.
  */
-class BasicTest<T extends @A Object> extends @B LinkedList<T> implements @C List<T> {
+class BasicTest<@D T extends @A Object> extends @B LinkedList<@E T> implements @C List<@F T> {
 
     void test() {
 
--- a/langtools/test/tools/javac/lib/DPrinter.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/test/tools/javac/lib/DPrinter.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -477,7 +477,7 @@
                 out.print(label);
                 out.println(": " +
                         info(sym.getClass(),
-                            String.format("0x%x--%s", sym.kind, Kinds.kindName(sym)),
+                            String.format("0x%x--%s", sym.kind.ordinal(), Kinds.kindName(sym)),
                             sym.getKind())
                         + " " + sym.name
                         + " " + hashString(sym));
--- a/langtools/test/tools/javac/processing/model/type/BasicAnnoTests.java	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/test/tools/javac/processing/model/type/BasicAnnoTests.java	Tue Apr 07 11:04:29 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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,21 +23,27 @@
 
 /*
  * @test
- * @bug     8013852
+ * @bug 8013852 8031744
  * @summary Annotations on types
  * @library /tools/javac/lib
- * @ignore 8057688 type annotations in type argument position are lost
- * @ignore 8031744 Annotations on many Language Model elements are not returned
  * @build JavacTestingAbstractProcessor DPrinter BasicAnnoTests
  * @compile/process -processor BasicAnnoTests -proc:only BasicAnnoTests.java
  */
 
 import java.io.PrintWriter;
+import java.io.Serializable;
 import java.lang.annotation.Annotation;
 import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
 import java.lang.annotation.Target;
+import java.util.ArrayList;
+
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.Set;
+import java.util.TreeMap;
 
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.annotation.processing.RoundEnvironment;
@@ -48,15 +54,23 @@
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.IntersectionType;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.type.TypeVariable;
 import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.Types;
 import javax.tools.Diagnostic.Kind;
 
+import com.sun.tools.javac.code.Attribute;
 import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.util.Name;
+
+import static com.sun.tools.javac.code.Attribute.Array;
+import static com.sun.tools.javac.code.Attribute.Constant;
+import static com.sun.tools.javac.code.Attribute.Compound;
 
 /**
  * The test scans this file looking for test cases annotated with @Test.
@@ -77,7 +91,7 @@
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
         TestElementScanner s = new TestElementScanner();
         for (Element e: roundEnv.getRootElements()) {
-            s.scan(e);
+            s.scan(e, null);
         }
         return true;
     }
@@ -95,17 +109,17 @@
      */
     class TestElementScanner extends ElementScanner<Void,Void> {
         public Void scan(Element elem, Void ignore) {
+            List<AnnotationMirror> tests = new ArrayList<>();
             AnnotationMirror test = getAnnotation(elem, Test.class.getName().replace('$', '.'));
             if (test != null) {
+                tests.add(test);
+            }
+            tests.addAll(getAnnotations(elem, Tests.class.getName().replace('$', '.')));
+
+            if (tests.size() > 0) {
                 out.println("Test: " + elem + " " + test);
-                TestTypeScanner s = new TestTypeScanner(elem, test);
-                s.scan(elem.asType(), null);
-                if (getPosn(test) >= s.count)
-                    error(elem, "position " + getPosn(test) + " not found");
-                if (!s.found) {
-                    dprinter.printSymbol("element", (Symbol) elem);
-                    dprinter.printType("type", (Type) elem.asType());
-                }
+                TestTypeScanner s = new TestTypeScanner(elem, tests, types);
+                s.test(elem.asType());
                 out.println();
             }
             return super.scan(elem, ignore);
@@ -118,45 +132,110 @@
      */
     class TestTypeScanner extends TypeScanner<Void, Void> {
         Element elem;
-        AnnotationMirror test;
+        NavigableMap<Integer, AnnotationMirror> toBeFound;
         int count = 0;
-        boolean found = false;
+        Set<TypeMirror> seen = new HashSet<>();
+
+        TestTypeScanner(Element elem, List<AnnotationMirror> tests, Types types) {
+            super(types);
+            this.elem = elem;
 
-        TestTypeScanner(Element elem, AnnotationMirror test) {
-            this.elem = elem;
-            this.test = test;
+            NavigableMap<Integer, AnnotationMirror> testByPos = new TreeMap<>();
+            for (AnnotationMirror test : tests) {
+                for (int pos : getPosn(test)) {
+                    testByPos.put(pos, test);
+                }
+            }
+            this.toBeFound = testByPos;
+        }
+
+        public void test(TypeMirror t) {
+            scan(t, null);
         }
 
         @Override
         Void scan(TypeMirror t, Void ignore) {
             if (t == null)
                 return DEFAULT_VALUE;
-            if (verbose)
-                out.println("scan " + count + ": " + t);
-            if (count == getPosn(test)) {
-                String annoType = getAnnoType(test);
-                AnnotationMirror anno = getAnnotation(t, annoType);
-                if (anno == null) {
-                    error(elem, "annotation not found on " + count + ": " + t);
-                } else {
-                    String v = getValue(anno, "value").toString();
-                    if (v.equals(getExpect(test))) {
-                        out.println("found " + anno + " as expected");
-                        found = true;
+
+            if (!seen.contains(t)) {
+                try {
+                    seen.add(t);
+                    if (verbose)
+                        out.println("scan " + count + ": " + t);
+                    if (toBeFound.size() > 0) {
+                        if (toBeFound.firstKey().equals(count)) {
+                            AnnotationMirror test = toBeFound.pollFirstEntry().getValue();
+                            String annoType = getAnnoType(test);
+                            AnnotationMirror anno = getAnnotation(t, annoType);
+                            if (anno == null) {
+                                error(elem, "annotation not found on " + count + ": " + t);
+                            } else {
+                                String v = getValue(anno, "value").toString();
+                                if (v.equals(getExpect(test))) {
+                                    out.println("found " + anno + " as expected");
+                                } else {
+                                    error(elem, "Unexpected value: " + v + ", expected: " + getExpect(test));
+                                }
+                            }
+                        } else if (count > toBeFound.firstKey()) {
+                            rescue();
+                        } else {
+                            List<? extends AnnotationMirror> annos = t.getAnnotationMirrors();
+                            if (annos.size() > 0) {
+                                for (AnnotationMirror a : annos)
+                                    error(elem, "annotation " + a + " found on " + count + ": " + t);
+                            }
+                        }
                     } else {
-                        error(elem, "Unexpected value: " + v + ", expected: " + getExpect(test));
+                        List<? extends AnnotationMirror> annos = t.getAnnotationMirrors();
+                        if (annos.size() > 0) {
+                            for (AnnotationMirror a : annos)
+                                error(elem, "annotation " + a + " found on " + count + ": " + t);
+                        }
                     }
+                    count++;
+                    return super.scan(t, ignore);
+
+                } finally {
+                    seen.remove(t);
                 }
             }
-            count++;
-            return super.scan(t, ignore);
+
+            return DEFAULT_VALUE;
+
+        }
+
+        private void rescue() {
+            while (toBeFound.size() > 0 && toBeFound.firstKey() >= count)
+                toBeFound.pollFirstEntry();
         }
     }
 
-    /** Get the position value from an @Test annotation mirror. */
-    static int getPosn(AnnotationMirror test) {
+    /** Get the position value from an element annotated with a @Test annotation mirror. */
+    static int[] getPosn(Element elem) {
+        return elem.getAnnotation(Test.class).posn();
+    }
+
+    /** Get the position value from a @Test annotation mirror. */
+    static Integer[] getPosn(AnnotationMirror test) {
         AnnotationValue v = getValue(test, "posn");
-        return (Integer) v.getValue();
+        Object value = v.getValue();
+        Integer i = 0;
+        if (value instanceof Constant) {
+            i = (Integer)((Constant)value).getValue();
+            Integer[] res = new Integer[1];
+            res[0] = i;
+            return res;
+        } else if (value instanceof List) {
+            List<Constant> l = (List<Constant>)value;
+            Integer[] res = new Integer[l.size()];
+            for (int c = 0; c < l.size(); c++) {
+                res[c] = (Integer)l.get(c).getValue();
+            }
+            return res;
+        }
+        return null;
     }
 
     /** Get the expect value from an @Test annotation mirror. */
@@ -185,6 +264,25 @@
         return null;
     }
 
+    static List<AnnotationMirror> getAnnotations(Element e, String name) {
+        Name valueName = ((Symbol)e).getSimpleName().table.names.value;
+        List<AnnotationMirror> res = new ArrayList<>();
+
+        for (AnnotationMirror m : e.getAnnotationMirrors()) {
+            TypeElement te = (TypeElement) m.getAnnotationType().asElement();
+            if (te.getQualifiedName().contentEquals(name)) {
+                Compound theAnno = (Compound)m;
+                Array valueArray = (Array)theAnno.member(valueName);
+                for (Attribute a : valueArray.getValue()) {
+                    AnnotationMirror theMirror = (AnnotationMirror) a;
+
+                    res.add(theMirror);
+                }
+            }
+        }
+        return res;
+    }
+
     /**
      * Get a specific value from an annotation mirror.
      */
@@ -203,6 +301,13 @@
      * one sufficient for our needs.
      */
     static class TypeScanner<R, P> extends SimpleTypeVisitor<R, P> {
+        private Types types;
+
+        public TypeScanner(Types types) {
+            super();
+            this.types = types;
+        }
+
         @Override
         public R visitArray(ArrayType t, P p) {
             scan(t.getComponentType(), p);
@@ -211,17 +316,34 @@
 
         @Override
         public R visitExecutable(ExecutableType t, P p) {
+            //out.println("  type parameters: " + t.getTypeVariables());
+            scan(t.getTypeVariables(), p);
+            //out.println("  return: " + t.getReturnType());
+            scan(t.getReturnType(), p);
+            //out.println("  receiver: " + t.getReceiverTypes());
             scan(t.getReceiverType());
             //out.println("  params: " + t.getParameterTypes());
             scan(t.getParameterTypes(), p);
-            //out.println("  return: " + t.getReturnType());
-            scan(t.getReturnType(), p);
             //out.println("  throws: " + t.getThrownTypes());
             scan(t.getThrownTypes(), p);
             return super.visitExecutable(t, p);
         }
 
         @Override
+        public R visitDeclared(DeclaredType t, P p) {
+            scan(t.getTypeArguments(), p);
+            // don't scan enclosing
+            scan(types.directSupertypes(t), p);
+            return super.visitDeclared(t, p);
+        }
+
+        @Override
+        public R visitIntersection(IntersectionType t, P p) {
+            scan(t.getBounds(), p);
+            return super.visitIntersection(t, p);
+        }
+
+        @Override
         public R visitTypeVariable(TypeVariable t, P p) {
             scan(t.getLowerBound(), p);
             scan(t.getUpperBound(), p);
@@ -254,36 +376,194 @@
     }
 
     /** Annotation to identify test cases. */
+    @Repeatable(Tests.class)
     @interface Test {
         /** Where to look for the annotation, expressed as a scan index. */
-        int posn();
+        int[] posn();
         /** The annotation to look for. */
         Class<? extends Annotation> annoType();
         /** The string representation of the annotation's value. */
         String expect();
     }
 
+    @interface Tests {
+        Test[] value();
+    }
+
     /** Type annotation to use in test cases. */
     @Target(ElementType.TYPE_USE)
     public @interface TA {
         int value();
     }
+    @Target(ElementType.TYPE_USE)
+    public @interface TB {
+        int value();
+    }
+
+    // Test cases
+
+    // TODO: add more cases for arrays
+    //       all annotated
+    //       all but one annotated
+    //             vary position of one not annotated
+    //       only one annotated
+    //             vary position of one annotated
+    //       the three above with the corner case of the ambiguos decl + type anno added
 
     @Test(posn=0, annoType=TA.class, expect="1")
     public @TA(1) int f1;
 
+    @Test(posn=0, annoType=TA.class, expect="11")
+    @TA(11) public int f11;
+
+    @Test(posn=1, annoType=TA.class, expect="111")
+    @TA(111) public int [] f111;
+
+    @Test(posn=1, annoType=TA.class, expect="1120")
+    @Test(posn=0, annoType=TB.class, expect="1121")
+    @TA(1120) public int @TB(1121) [] f112;
+
+    @Test(posn=0, annoType=TB.class, expect="11211")
+    @Test(posn=1, annoType=TA.class, expect="11200")
+    public @TA(11200) int @TB(11211) [] f112b;
+
+    @Test(posn=1, annoType=TB.class, expect="1131")
+    @Test(posn=2, annoType=TA.class, expect="1130")
+    @TA(1130) public int [] @TB(1131) [] f113;
+
+    @Test(posn=5, annoType=TA.class, expect="12")
+    public @TA(12) int [] [] [] [] [] f12;
+
+    @Test(posn=6, annoType=TA.class, expect="13")
+    public @TA(13) int [] [] [] [] [] [] f13;
+
+    @Test(posn=7, annoType=TA.class, expect="14")
+    @TA(14) public int [] [] [] [] [] [] [] f14;
+
+    @Test(posn=6, annoType=TA.class, expect="150")
+    @Test(posn=7, annoType=TB.class, expect="151")
+    @TB(151) public int [] [] [] [] [] [] @TA(150) [] f15;
+
+    @Test(posn=0, annoType=TB.class, expect="1511")
+    @Test(posn=3, annoType=TA.class, expect="1512")
+    @Test(posn=6, annoType=TA.class, expect="150")
+    @Test(posn=7, annoType=TB.class, expect="151")
+    @TB(151) public int @TB(1511) [] [] [] @TA(1512) [] [] [] @TA(150) [] f15b;
+
+    @Test(posn=0, annoType=TB.class, expect="1521")
+    @Test(posn=3, annoType=TA.class, expect="1522")
+    @Test(posn=6, annoType=TA.class, expect="152")
+    public int @TB(1521) [] [] [] @TA(1522) [] [] [] @TA(152) [] f15c;
+
+    @Test(posn=5, annoType=TA.class, expect="160")
+    @Test(posn=6, annoType=TB.class, expect="161")
+    public int [] [] [] [] [] @TA(160) [] @TB(161) [] f16;
+
     @Test(posn=0, annoType=TA.class, expect="2")
     public int @TA(2) [] f2;
 
+    @Test(posn=0, annoType=TB.class, expect="33")
     @Test(posn=1, annoType=TA.class, expect="3")
-    public @TA(3) int [] f3;
+    public @TA(3) int @TB(33) [] f3;
 
-    @Test(posn=1, annoType=TA.class, expect="4")
+    @Test(posn=2, annoType=TA.class, expect="4")
     public int m1(@TA(4) float a) throws Exception { return 0; }
 
-    @Test(posn=2, annoType=TA.class, expect="5")
+    @Test(posn=1, annoType=TA.class, expect="5")
     public @TA(5) int m2(float a) throws Exception { return 0; }
 
     @Test(posn=3, annoType=TA.class, expect="6")
     public int m3(float a) throws @TA(6) Exception { return 0; }
+
+    // Also tests that a decl anno on a typevar doesn't show up on the Type
+    @Test(posn=7, annoType=TA.class, expect="8")
+    public <@TA(7) M> M m4(@TA(8) float a) throws Exception { return null; }
+
+    // Also tests that a decl anno on a typevar doesn't show up on the Type
+    @Test(posn=4, annoType=TA.class, expect="10")
+    public class Inner1<@TA(9) S> extends @TA(10) Object implements Cloneable {}
+
+    // Also tests that a decl anno on a typevar doesn't show up on the Type
+    @Test(posn=5, annoType=TA.class, expect="12")
+    public class Inner2<@TA(11) S> extends Object implements @TA(12) Cloneable {}
+
+    @Test(posn={3,6}, annoType=TA.class, expect="13")
+    public <M extends @TA(13) Object> M m5(float a) { return null; }
+
+    @Test(posn=3, annoType=TA.class, expect="14")
+    public class Inner3<QQQ extends @TA(14) Map> {}
+
+    @Test(posn=4, annoType=TA.class, expect="15")
+    public class Inner4<T extends @TA(15) Object & Cloneable & Serializable> {}
+
+    @Test(posn=5, annoType=TA.class, expect="16")
+    public class Inner5<T extends Object & @TA(16) Cloneable & Serializable> {}
+
+    @Test(posn=7, annoType=TA.class, expect="17")
+    public class Inner6<T extends Object & Cloneable & @TA(17) Serializable> {}
+
+    // Test annotated bounds
+
+    @Test(posn=1, annoType=TA.class, expect="18")
+    public Set<@TA(18) ? extends Object> f4;
+
+    @Test(posn=2, annoType=TA.class, expect="19")
+    public Set<? extends @TA(19) Object> f5;
+
+    @Test(posn=3, annoType=TA.class, expect="20")
+    public Set<? extends Set<@TA(20) ? extends Object>> f6;
+
+    @Test(posn=4, annoType=TA.class, expect="21")
+    public Set<? extends Set<? extends @TA(21) Object>> f7;
+
+    @Test(posn=1, annoType=TA.class, expect="22")
+    public Set<@TA(22) ?> f8;
+
+    @Test(posn=1, annoType=TA.class, expect="23")
+    public Set<@TA(23) ? super Object> f9;
+
+    // Test type use annotations on uses of type variables
+    @Test(posn=5, annoType = TA.class, expect = "25")
+    @Test(posn=5, annoType = TB.class, expect = "26")
+    <T> void m6(@TA(25) @TB(26) T t) { }
+
+    class Inner7<T> {
+        @Test(posn=0, annoType = TA.class, expect = "30")
+        @Test(posn=0, annoType = TB.class, expect = "31")
+        @TA(30) @TB(31) T f;
+    }
+
+    // Test type use annotations on uses of type variables
+    @Test(posn=5, annoType = TB.class, expect = "41")
+    <@TA(40) T> void m7(@TB(41) T t) { }
+
+    class Inner8<@TA(50) T> {
+        @Test(posn=0, annoType = TB.class, expect = "51")
+        @TB(51) T f;
+    }
+
+    // Test type use annotations on uses of Class types
+    @Test(posn=5, annoType = TA.class, expect = "60")
+    @Test(posn=5, annoType = TB.class, expect = "61")
+    <T> void m60(@TA(60) @TB(61) String t) { }
+
+    class Inner70<T> {
+        @Test(posn=0, annoType = TA.class, expect = "70")
+        @Test(posn=0, annoType = TB.class, expect = "71")
+        @TA(70) @TB(71) String f;
+    }
+
+    // Test type use annotations on uses of type variables
+    @Test(posn=5, annoType = TB.class, expect = "81")
+    <@TA(80) T> void m80(@TB(81) String t) { }
+
+    class Inner90<@TA(90) T> {
+        @Test(posn=0, annoType = TB.class, expect = "91")
+        @TB(91) String f;
+    }
+
+    // Recursive bound
+    @Test(posn=4, annoType = TB.class, expect = "100")
+    class Inner100<T extends Inner100<@TB(100) T>> {
+    }
 }
--- a/langtools/test/tools/javac/warnings/6747671/T6747671.out	Fri Apr 03 16:35:58 2015 -0700
+++ b/langtools/test/tools/javac/warnings/6747671/T6747671.out	Tue Apr 07 11:04:29 2015 -0700
@@ -7,6 +7,6 @@
 T6747671.java:32:9: compiler.warn.raw.class.use: T6747671.A, T6747671<E>.A<X>
 T6747671.java:32:20: compiler.warn.raw.class.use: T6747671.A, T6747671<E>.A<X>
 T6747671.java:33:16: compiler.warn.raw.class.use: T6747671.A.Z, T6747671<E>.A<X>.Z<Y>
-T6747671.java:36:9: compiler.warn.raw.class.use: @T6747671.TA T6747671.B, T6747671.B<X>
+T6747671.java:36:9: compiler.warn.raw.class.use: T6747671.B, T6747671.B<X>
 T6747671.java:36:27: compiler.warn.raw.class.use: T6747671.B, T6747671.B<X>
 11 warnings