Update jdt.core from origin BETA_JAVA8 with
a0e37e3c6cc37202a2e94a486c41b8cffb4d296d upto
a38d26ea4f2f03195744026af44f070900d21cea
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
index fec3c0a..afb998e 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
@@ -429,10 +429,10 @@
 		expectedProblemAttributes.put("CodeCannotBeReached", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
 		expectedProblemAttributes.put("CodeSnippetMissingClass", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
 		expectedProblemAttributes.put("CodeSnippetMissingMethod", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
-		expectedProblemAttributes.put("ContainingAnnotationHasNonDefaultMembers", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
-		expectedProblemAttributes.put("ContainingAnnotationHasShorterRetention", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
-		expectedProblemAttributes.put("ContainingAnnotationHasWrongValueType", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
-		expectedProblemAttributes.put("ContainingAnnotationMustHaveValue", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+		expectedProblemAttributes.put("ContainerAnnotationTypeHasNonDefaultMembers", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+		expectedProblemAttributes.put("ContainerAnnotationTypeHasShorterRetention", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+		expectedProblemAttributes.put("ContainerAnnotationTypeHasWrongValueType", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+		expectedProblemAttributes.put("ContainerAnnotationTypeMustHaveValue", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
 		expectedProblemAttributes.put("ContradictoryNullAnnotations", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
 		expectedProblemAttributes.put("ContradictoryNullAnnotationsOnBound", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
 		expectedProblemAttributes.put("ComparingIdentical", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
@@ -451,7 +451,7 @@
 		expectedProblemAttributes.put("DereferencingNullableExpression", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
 		expectedProblemAttributes.put("DiamondNotBelow17", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
 		expectedProblemAttributes.put("DirectInvocationOfAbstractMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
-		expectedProblemAttributes.put("DisallowedTargetForContainerAnnotation", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+		expectedProblemAttributes.put("DisallowedTargetForContainerAnnotationType", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
 		expectedProblemAttributes.put("DisallowedTargetForAnnotation", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
 		expectedProblemAttributes.put("DisallowedExplicitThisParameter", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
 		expectedProblemAttributes.put("DiscouragedReference", new ProblemAttributes(CategorizedProblem.CAT_RESTRICTION));
@@ -923,10 +923,9 @@
 		expectedProblemAttributes.put("RequiredNonNullButProvidedSpecdNullable", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
 		expectedProblemAttributes.put("RequiredNonNullButProvidedUnknown", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
 		expectedProblemAttributes.put("ReferenceToForwardTypeVariable", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
-		expectedProblemAttributes.put("RepeatableAnnotationHasTargets", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
-		expectedProblemAttributes.put("RepeatableAnnotationIsDocumented", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
-		expectedProblemAttributes.put("RepeatableAnnotationIsInherited", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
-		expectedProblemAttributes.put("RepeatableAnnotationTargetMismatch", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+		expectedProblemAttributes.put("RepeatableAnnotationTypeIsDocumented", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+		expectedProblemAttributes.put("RepeatableAnnotationTypeIsInherited", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
+		expectedProblemAttributes.put("RepeatableAnnotationTypeTargetMismatch", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
 		expectedProblemAttributes.put("RepeatedAnnotationWithContainerAnnotation", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
 		expectedProblemAttributes.put("ResourceHasToImplementAutoCloseable", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
 		expectedProblemAttributes.put("ReturnTypeAmbiguous", DEPRECATED);
@@ -1327,10 +1326,10 @@
 		expectedProblemAttributes.put("ConstructionTypeMismatch", SKIP);
 		expectedProblemAttributes.put("ConflictingInheritedNullAnnotations", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
 		expectedProblemAttributes.put("ConstructorReferenceNotBelow18", SKIP);
-		expectedProblemAttributes.put("ContainingAnnotationHasNonDefaultMembers", SKIP);
-		expectedProblemAttributes.put("ContainingAnnotationHasShorterRetention", SKIP);
-		expectedProblemAttributes.put("ContainingAnnotationHasWrongValueType", SKIP);
-		expectedProblemAttributes.put("ContainingAnnotationMustHaveValue", SKIP);
+		expectedProblemAttributes.put("ContainerAnnotationTypeHasNonDefaultMembers", SKIP);
+		expectedProblemAttributes.put("ContainerAnnotationTypeHasShorterRetention", SKIP);
+		expectedProblemAttributes.put("ContainerAnnotationTypeHasWrongValueType", SKIP);
+		expectedProblemAttributes.put("ContainerAnnotationTypeMustHaveValue", SKIP);
 		expectedProblemAttributes.put("ContradictoryNullAnnotations", SKIP);
 		expectedProblemAttributes.put("ContradictoryNullAnnotationsOnBound", SKIP);
 		expectedProblemAttributes.put("ConstructorVarargsArgumentNeedCast", new ProblemAttributes(JavaCore.COMPILER_PB_VARARGS_ARGUMENT_NEED_CAST));
@@ -1343,7 +1342,7 @@
 		expectedProblemAttributes.put("DiamondNotBelow17", SKIP);
 		expectedProblemAttributes.put("DirectInvocationOfAbstractMethod", SKIP);
 		expectedProblemAttributes.put("DisallowedTargetForAnnotation", SKIP);
-		expectedProblemAttributes.put("DisallowedTargetForContainerAnnotation", SKIP);
+		expectedProblemAttributes.put("DisallowedTargetForContainerAnnotationType", SKIP);
 		expectedProblemAttributes.put("DiscouragedReference", new ProblemAttributes(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE));
 		expectedProblemAttributes.put("DuplicateAnnotation", SKIP);
 		expectedProblemAttributes.put("DuplicateAnnotationNotMarkedRepeatable", SKIP);
@@ -1809,10 +1808,9 @@
 		expectedProblemAttributes.put("ReferenceExpressionReturnNullRedefUnchecked", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_UNCHECKED_CONVERSION));
 		expectedProblemAttributes.put("ReferenceToForwardField", SKIP);
 		expectedProblemAttributes.put("ReferenceToForwardTypeVariable", SKIP);
-		expectedProblemAttributes.put("RepeatableAnnotationHasTargets", SKIP);
-		expectedProblemAttributes.put("RepeatableAnnotationIsDocumented", SKIP);
-		expectedProblemAttributes.put("RepeatableAnnotationIsInherited", SKIP);
-		expectedProblemAttributes.put("RepeatableAnnotationTargetMismatch", SKIP);
+		expectedProblemAttributes.put("RepeatableAnnotationTypeIsDocumented", SKIP);
+		expectedProblemAttributes.put("RepeatableAnnotationTypeIsInherited", SKIP);
+		expectedProblemAttributes.put("RepeatableAnnotationTypeTargetMismatch", SKIP);
 		expectedProblemAttributes.put("RepeatedAnnotationWithContainerAnnotation", SKIP);
 		expectedProblemAttributes.put("RequiredNonNullButProvidedNull", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
 		expectedProblemAttributes.put("RequiredNonNullButProvidedPotentialNull", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_ANNOTATION_INFERENCE_CONFLICT));
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
index edce618..fe81185 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
@@ -18,7 +18,6 @@
  *								bug 402237 - [1.8][compiler] investigate differences between compilers re MethodVerifyTest
  *								bug 395681 - [compiler] Improve simulation of javac6 behavior from bug 317719 after fixing bug 388795
  *								bug 409473 - [compiler] JDT cannot compile against JRE 1.8
- *								Bug 410325 - [1.7][compiler] Generified method override different between javac and eclipse compiler
  *	   Andy Clement - Contribution for
  *								bug 406928 - computation of inherited methods seems damaged (affecting @Overrides)
  *******************************************************************************/
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java
index 3ffd81f..5dbab13 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java
@@ -4082,5 +4082,24 @@
 			"	^^^^^^\n" + 
 			"The method getAdd(List<P>, List<P>) in the type X is not applicable for the arguments (List<capture#7-of ? extends X>, List<capture#8-of ? extends X>)\n" + 
 			"----------\n");		
+	}
+	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=414038, [1.8][compiler] CCE in resolveAnnotations
+	public void testBug414038() {
+		runNegativeTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.*;\n" +
+				"@Target(ElementType.TYPE_USE)\n" +
+				"@interface NonNull { int[].class value() default 0;}\n" +
+				"public class X extends @NonNull() Object {    \n" +
+				"    public static int i = 0; \n" +
+				"}\n"
+			}, 
+			"----------\n" + 
+			"1. ERROR in X.java (at line 3)\n" + 
+			"	@interface NonNull { int[].class value() default 0;}\n" + 
+			"	                          ^^^^^^\n" + 
+			"Syntax error on tokens, delete these tokens\n" + 
+			"----------\n");		
 	}	
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java
index df5b2e2..70dfd1e 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java
@@ -6629,4 +6629,29 @@
 		"Missing cannot be resolved to a type\n" + 
 		"----------\n");
 }
+public void testBug418235() {
+    runNegativeTestWithLibs(
+            new String[] {
+                    "GenericInterface.java",
+                    "public interface GenericInterface<T> {\n" + 
+                    "       T doSomethingGeneric(T o);\n" + 
+                    "}",
+                    "Implementation.java",
+                    "import org.eclipse.jdt.annotation.NonNullByDefault;\n" + 
+                    "@NonNullByDefault\n" + 
+                    "public class Implementation implements GenericInterface<Object> {\n" + 
+                    "\n" + 
+                    (this.complianceLevel < ClassFileConstants.JDK1_6 ? "\n" : "      @Override\n" ) +
+                    "       public Object doSomethingGeneric(Object o) {\n" + 
+                    "               return o;\n" + 
+                    "       }\n" + 
+                    "}\n"
+            },
+            "----------\n" + 
+            "1. ERROR in Implementation.java (at line 6)\n" + 
+    		"	public Object doSomethingGeneric(Object o) {\n" + 
+    		"	                                 ^^^^^^\n" + 
+            "Illegal redefinition of parameter o, inherited method from GenericInterface<Object> does not constrain this parameter\n" + 
+            "----------\n");
+}
 }
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RepeatableAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RepeatableAnnotationTest.java
index 7ad2303..978f40c 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RepeatableAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RepeatableAnnotationTest.java
@@ -12,11 +12,15 @@
  * Contributors:
  *     Jesper S Moller - initial API and implementation
  *     					Bug 412151 - [1.8][compiler] Check repeating annotation's collection type
+ *     					Bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container
  *******************************************************************************/
 package org.eclipse.jdt.core.tests.compiler.regression;
 
+import java.io.File;
+
 import junit.framework.Test;
 
+import org.eclipse.jdt.core.util.ClassFileBytesDisassembler;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.impl.IntConstant;
@@ -114,12 +118,12 @@
 			"1. ERROR in X.java (at line 1)\n" + 
 			"	@Foo @Foo public class X { /* Problem */\n" + 
 			"	^^^^\n" + 
-			"The repeatable annotation @Foo is disallowed for this location since its container annotation @FooContainer is disallowed at this location\n" + 
+			"The annotation @Foo cannot be repeated at this location since its container annotation type @FooContainer is disallowed at this location\n" + 
 			"----------\n" + 
 			"2. ERROR in X.java (at line 3)\n" + 
 			"	@Foo @Foo int local = 0; /* Problem! */\n" + 
 			"	^^^^\n" + 
-			"The repeatable annotation @Foo is disallowed for this location since its container annotation @FooContainer is disallowed at this location\n" + 
+			"The annotation @Foo cannot be repeated at this location since its container annotation type @FooContainer is disallowed at this location\n" + 
 			"----------\n");
 	}
 
@@ -148,7 +152,7 @@
 			"1. ERROR in X.java (at line 1)\n" + 
 			"	@Foo @Foo public class X { /* Problem */\n" + 
 			"	^^^^\n" + 
-			"The repeatable annotation @Foo is disallowed for this location since its container annotation @FooContainer is disallowed at this location\n" + 
+			"The annotation @Foo cannot be repeated at this location since its container annotation type @FooContainer is disallowed at this location\n" + 
 			"----------\n",
 			null, false /* don't flush*/);
 	}
@@ -178,7 +182,7 @@
 			"1. ERROR in X.java (at line 3)\n" + 
 			"	@Foo @Foo @FooContainer({@Foo, @Foo}) public class X { /* A problem */ }\n" + 
 			"	^^^^\n" + 
-			"The repeatable annotation @Foo may not be repeated where its container annotation @FooContainer is also used directly\n" + 
+			"The repeatable annotation @Foo may not be repeated where its container annotation type @FooContainer is also used directly\n" + 
 			"----------\n");
 	}
 
@@ -196,7 +200,7 @@
 			"1. ERROR in X.java (at line 4)\n" + 
 			"	@Foo @Foo @FooContainer({@Foo, @Foo}) public class X { /* Still a problem */ }\n" + 
 			"	^^^^\n" + 
-			"The repeatable annotation @Foo may not be repeated where its container annotation @FooContainer is also used directly\n" + 
+			"The repeatable annotation @Foo may not be repeated where its container annotation type @FooContainer is also used directly\n" + 
 			"----------\n");
 	}
 	
@@ -215,7 +219,7 @@
 			"1. ERROR in X.java (at line 5)\n" + 
 			"	@Foo @Foo @Bar @Bar @FooContainer({@Foo, @Foo}) public class X { /* Still a problem */ }\n" + 
 			"	^^^^\n" + 
-			"The repeatable annotation @Foo may not be repeated where its container annotation @FooContainer is also used directly\n" + 
+			"The repeatable annotation @Foo may not be repeated where its container annotation type @FooContainer is also used directly\n" + 
 			"----------\n" + 
 			"2. ERROR in X.java (at line 5)\n" + 
 			"	@Foo @Foo @Bar @Bar @FooContainer({@Foo, @Foo}) public class X { /* Still a problem */ }\n" + 
@@ -289,7 +293,7 @@
 		"1. ERROR in Foo.java (at line 3)\n" + 
 		"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-		"The containing annotation @FooContainer must declare a member value()\n" + 
+		"The container annotation type @FooContainer must declare a member value()\n" + 
 		"----------\n");
 	}
 	// 412151: The collections type's (TC) declaration must have a array of Ts as its value() - with Foo and FooContainer in same compilation round
@@ -307,7 +311,7 @@
 		"1. ERROR in Foo.java (at line 4)\n" + 
 		"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-		"The value method in the containing annotation @FooContainer must be of type Foo[] but is int[]\n" + 
+		"The value method in the container annotation type @FooContainer must be of type Foo[] but is int[]\n" + 
 		"----------\n");
 	}
 	// 412151: The collections type's (TC) declaration must have a array of Ts as its value() - with Foo and FooContainer in same compilation round
@@ -330,7 +334,7 @@
 			"2. ERROR in Foo.java (at line 4)\n" + 
 			"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 			"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-			"The value method in the containing annotation @FooContainer must be of type Foo[] but is Foo[][]\n" + 
+			"The value method in the container annotation type @FooContainer must be of type Foo[] but is Foo[][]\n" + 
 			"----------\n"
 		);
 	}
@@ -351,7 +355,7 @@
 		"1. ERROR in Foo.java (at line 6)\n" + 
 		"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-		"The containing annotation @FooContainer must declare a default value for the annotation attribute \'doesntHaveDefaultValue\'\n" + 
+		"The container annotation type @FooContainer must declare a default value for the annotation attribute \'doesntHaveDefaultValue\'\n" + 
 		"----------\n");
 	}
 	// 412151: The @Retention meta-annotation of TC must at least include the retention of T ()
@@ -409,7 +413,7 @@
 			"1. ERROR in X.java (at line 1)\n" + 
 			"	@Foo @Foo public class X { /* Problem since Foo now uses FooContainer which doesn\'t work anymore*/\n" + 
 			"	^^^^\n" + 
-			"The value method in the containing annotation @FooContainer must be of type Foo[] but is int[]\n" + 
+			"The value method in the container annotation type @FooContainer must be of type Foo[] but is int[]\n" + 
 			"----------\n",
 			null, false /* don't flush*/);
 	}
@@ -432,7 +436,7 @@
 		"1. ERROR in Foo.java (at line 5)\n" + 
 		"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-		"Retention \'RUNTIME\' of @Foo is longer than the retention of the containing annotation @FooContainer, which is \'SOURCE\'\n" + 
+		"Retention \'RUNTIME\' of @Foo is longer than the retention of its container annotation type @FooContainer, which is \'SOURCE\'\n" + 
 		"----------\n");
 	}
 
@@ -453,7 +457,7 @@
 		"1. ERROR in Foo.java (at line 5)\n" + 
 		"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-		"Retention \'CLASS\' of @Foo is longer than the retention of the containing annotation @FooContainer, which is \'SOURCE\'\n" + 
+		"Retention \'CLASS\' of @Foo is longer than the retention of its container annotation type @FooContainer, which is \'SOURCE\'\n" + 
 		"----------\n");
 	}
 
@@ -474,7 +478,7 @@
 		"1. ERROR in Foo.java (at line 4)\n" + 
 		"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-		"Retention \'RUNTIME\' of @Foo is longer than the retention of the containing annotation @FooContainer, which is \'CLASS\'\n" + 
+		"Retention \'RUNTIME\' of @Foo is longer than the retention of its container annotation type @FooContainer, which is \'CLASS\'\n" + 
 		"----------\n");
 	}
 
@@ -520,7 +524,7 @@
 		"1. ERROR in Foo.java (at line 1)\n" + 
 		"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-		"Retention \'CLASS\' of @Foo is longer than the retention of the containing annotation @FooContainer, which is \'SOURCE\'\n" + 
+		"Retention \'CLASS\' of @Foo is longer than the retention of its container annotation type @FooContainer, which is \'SOURCE\'\n" + 
 		"----------\n",
 		null, false /* don't flush*/);
 	}
@@ -553,7 +557,7 @@
 		"1. ERROR in Foo.java (at line 3)\n" + 
 		"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-		"Retention \'RUNTIME\' of @Foo is longer than the retention of the containing annotation @FooContainer, which is \'CLASS\'\n" + 
+		"Retention \'RUNTIME\' of @Foo is longer than the retention of its container annotation type @FooContainer, which is \'CLASS\'\n" + 
 		"----------\n",
 		null, false /* don't flush*/);
 	}
@@ -579,7 +583,7 @@
 		"1. ERROR in Foo.java (at line 3)\n" + 
 		"	public @java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                        ^^^^^^^^^^^^^^^^^^\n" + 
-		"The containing annotation @FooContainer is allowed at targets where the repeatable annotation @Foo is not: TYPE, METHOD\n" + 
+		"The container annotation type @FooContainer is allowed at targets where the repeatable annotation type @Foo is not: TYPE, METHOD\n" + 
 		"----------\n");
 	}
 
@@ -613,7 +617,7 @@
 		"1. ERROR in Foo.java (at line 3)\n" + 
 		"	public @java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                        ^^^^^^^^^^^^^^^^^^\n" + 
-		"The containing annotation @FooContainer is allowed at targets where the repeatable annotation @Foo is not: METHOD\n" + 
+		"The container annotation type @FooContainer is allowed at targets where the repeatable annotation type @Foo is not: METHOD\n" + 
 		"----------\n",
 		null, false /* don't flush*/);
 	}
@@ -656,12 +660,12 @@
 		"1. ERROR in Foo.java (at line 3)\n" + 
 		"	public @java.lang.annotation.Repeatable(FooContainer.class)\n" + 
 		"	                                        ^^^^^^^^^^^^^^^^^^\n" + 
-		"The containing annotation @FooContainer is allowed at targets where the repeatable annotation @Foo is not: TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE\n" + 
+		"The container annotation type @FooContainer is allowed at targets where the repeatable annotation type @Foo is not: TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE\n" + 
 		"----------\n");
 	}
 
 	// 412151: TC's @Targets, if specified, must be a subset or the same as T's @Targets
-	// TC's has no @Targets (=everywhere), but @Foo has, then complain.
+	// TC's has no @Targets (=every SE7 location), but @Foo has, then complain.
 	public void test026() {
 		this.runConformTest(
 			new String[] {
@@ -679,12 +683,12 @@
 				"@java.lang.annotation.Target({ElementType.FIELD})\n" +
 				"@interface Foo { }\n"
 			}, 
-		"----------\n" + 
-		"1. ERROR in Foo.java (at line 3)\n" + 
-		"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
-		"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-		"The repeatable annotation @Foo has a @Target annotation, @FooContainer does not\n" + 
-		"----------\n",
+			"----------\n" + 
+			"1. ERROR in Foo.java (at line 3)\n" + 
+			"	@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
+			"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
+			"The container annotation type @FooContainer is allowed at targets where the repeatable annotation type @Foo is not: TYPE, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE\n" + 
+			"----------\n",
 		null, false /* don't flush*/);
 	}
 
@@ -722,7 +726,7 @@
 			"1. ERROR in Foo.java (at line 1)\n" + 
 			"	@java.lang.annotation.Repeatable(FooContainer.class) @java.lang.annotation.Documented\n" + 
 			"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-			"The repeatable annotation @Foo is marked @Documented, but the containing annotation @FooContainer is not\n" + 
+			"The repeatable annotation type @Foo is marked @Documented, but its container annotation type @FooContainer is not\n" + 
 			"----------\n");
 	}
 
@@ -780,7 +784,7 @@
 			"1. ERROR in Foo.java (at line 1)\n" + 
 			"	@java.lang.annotation.Repeatable(FooContainer.class) @java.lang.annotation.Inherited\n" + 
 			"	                                 ^^^^^^^^^^^^^^^^^^\n" + 
-			"The repeatable annotation @Foo is marked @Inherited, but the containing annotation @FooContainer is not\n" + 
+			"The repeatable annotation type @Foo is marked @Inherited, but its container annotation type @FooContainer is not\n" + 
 			"----------\n");
 	}
 
@@ -829,12 +833,623 @@
 			"1. ERROR in X.java (at line 9)\n" + 
 			"	@Repeatable(TC.class)\n" + 
 			"	            ^^^^^^^^\n" + 
-			"The containing annotation @TC is allowed at targets where the repeatable annotation @T is not: FIELD\n" + 
+			"The container annotation type @TC is allowed at targets where the repeatable annotation type @T is not: FIELD\n" + 
 			"----------\n" + 
 			"2. ERROR in X.java (at line 12)\n" + 
 			"	@T @T // we used to double report here.\n" + 
 			"	^^\n" + 
-			"The repeatable annotation @T is disallowed for this location since its container annotation @TC is disallowed at this location\n" + 
+			"The annotation @T cannot be repeated at this location since its container annotation type @TC is disallowed at this location\n" + 
+			"----------\n");
+	}	
+	// 412149: [1.8][compiler] Emit repeated annotations into the designated container
+	public void test036() {
+		this.runConformTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.Repeatable;\n" +
+				"import java.lang.annotation.Retention;\n" +
+				"import static java.lang.annotation.RetentionPolicy.*;\n" +
+				"\n" +
+				"@Retention(RUNTIME)\n" +
+				"@interface AttrContainer {\n" +
+				"  public Attr[] value();\n" +
+				"}\n" +
+				"@Retention(RUNTIME)\n" +
+				"@Repeatable(AttrContainer.class)\n" + 
+				"@interface Attr {\n" +
+				"  public int value() default -1;\n" +
+				"}\n" +
+				"\n" +
+				"@Attr(1) @Attr(2)\n" +
+				"public class X {\n" +
+				"  public static void main(String args[]) {\n" +
+				"  	Object e[] = X.class.getAnnotationsByType(Attr.class);\n" +
+				"  	for (int i=0; i<e.length;++i) System.out.print(e[i] + \" \");\n" +
+				"  }\n" +
+				"}"
+			},
+			"@Attr(value=1) @Attr(value=2)");
+		
+	}
+	// 412149: [1.8][compiler] Emit repeated annotations into the designated container
+	// Test that only repetitions go into the container 
+	public void test037() {
+		this.runConformTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.Repeatable;\n" +
+				"import java.lang.annotation.Retention;\n" +
+				"import static java.lang.annotation.RetentionPolicy.*;\n" +
+				"\n" +
+				"@Retention(RUNTIME)\n" +
+				"@interface AttrContainer {\n" +
+				"  public Attr[] value();\n" +
+				"}\n" +
+				"@Retention(RUNTIME)\n" +
+				"@Repeatable(AttrContainer.class)\n" + 
+				"@interface Attr {\n" +
+				"  public int value() default -1;\n" +
+				"}\n" +
+				"\n" +
+				"public class X {\n" +
+				"  @Attr(1) class Y1 {}\n" +
+				"  @Attr(1) @Attr(2) class Y2 {} \n" +
+				"  public static void main(String args[]) {\n" +
+				"  	System.out.println(\"Y1: \" + Y1.class.getAnnotation(Attr.class));\n" +
+				"  	System.out.println(\"Y2: \" + Y2.class.getAnnotation(Attr.class));\n" +
+				"  	System.out.println(\"Y1: \" + Y1.class.getAnnotation(AttrContainer.class));\n" +
+				"  	System.out.println(\"Y2: \" + Y2.class.getAnnotation(AttrContainer.class));\n" +
+				"  }\n" +
+				"}"
+			},
+			"Y1: @Attr(value=1)\n" + 
+			"Y2: null\n" + 
+			"Y1: null\n" + 
+			"Y2: @AttrContainer(value=[@Attr(value=1), @Attr(value=2)])");
+		
+	}
+	// 412149: [1.8][compiler] Emit repeated annotations into the designated container
+	// Test that the retention from the containing annotation is used
+	public void test038() {
+		this.runConformTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.Repeatable;\n" +
+				"import java.lang.annotation.Retention;\n" +
+				"import static java.lang.annotation.RetentionPolicy.*;\n" +
+				"\n" +
+				"@Retention(RUNTIME)\n" +
+				"@interface AttrContainer {\n" +
+				"  public Attr[] value();\n" +
+				"}\n" +
+				"@Retention(SOURCE)\n" +
+				"@Repeatable(AttrContainer.class)\n" + 
+				"@interface Attr {\n" +
+				"  public int value() default -1;\n" +
+				"}\n" +
+				"\n" +
+				"public class X {\n" +
+				"  @Attr(1) class Y1 {}\n" +
+				"  @Attr(1) @Attr(2) class Y2 {} \n" +
+				"  public static void main(String args[]) {\n" +
+				"  	System.out.println(\"Y1 has \" + Y1.class.getAnnotationsByType(Attr.class).length);\n" +
+				"  	System.out.println(\"Y2 has \" + Y2.class.getAnnotationsByType(Attr.class).length);\n" +
+				"  }\n" +
+				"}"
+			},
+			"Y1 has 0\n" + 
+			"Y2 has 2");
+		
+	}
+	// 412149: [1.8][compiler] Emit repeated annotations into the designated container
+	// Test that repeated annotations can appear at package targets
+	public void test039() throws Exception {
+		String[] testFiles = {
+				"repeatable/Main.java",
+				"package repeatable;\n" +
+				"public class Main {\n" +
+				"    public static void main (String[] argv) {\n" + 
+				"    };\n" +
+				"}",
+
+			"repeatable/FooContainer.java",
+			"package repeatable;\n" +
+			"@java.lang.annotation.Target(java.lang.annotation.ElementType.PACKAGE)\n" +
+			"@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)\n" +
+			"public @interface FooContainer {\n" +
+			"	Foo[] value();\n" +
+			"}\n",
+
+			"repeatable/Foo.java",
+			"package repeatable;\n" +
+			"@java.lang.annotation.Repeatable(FooContainer.class)\n" + 
+			"public @interface Foo {}\n",
+
+			"repeatable/package-info.java",
+			"@Foo @Foo\n" +
+			"package repeatable;\n" +
+			"import repeatable.Foo;",
+		};
+		runConformTest(testFiles, "");
+		String expectedOutout = 
+				"  RuntimeVisibleAnnotations: \n" + 
+				"    #8 @repeatable.FooContainer(\n" + 
+				"      #9 value=[\n" + 
+				"        annotation value =\n" + 
+				"            #10 @repeatable.Foo(\n" + 
+				"            )\n" + 
+				"        annotation value =\n" + 
+				"            #10 @repeatable.Foo(\n" + 
+				"            )\n" + 
+				"        ]\n" + 
+				"    )\n";
+		checkDisassembledClassFile(OUTPUT_DIR + File.separator + "repeatable" + File.separator + "package-info.class", "package-info", expectedOutout, ClassFileBytesDisassembler.SYSTEM);
+	}
+	// 412149: [1.8][compiler] Emit repeated annotations into the designated container
+	// Test that repeated annotations show up on fields, methods, and parameters
+	public void test040() {
+		this.runConformTest(
+			new String[] {
+				"X.java",
+				"import java.lang.reflect.Field;\n" + 
+				"import java.lang.reflect.Method;\n" + 
+				"import java.lang.reflect.Parameter;\n" + 
+				"import java.lang.annotation.Repeatable;\n" +
+				"import java.lang.annotation.Retention;\n" +
+				"import static java.lang.annotation.RetentionPolicy.*;\n" +
+				"\n" +
+				"@Retention(RUNTIME)\n" +
+				"@interface AttrContainer {\n" +
+				"  public Attr[] value();\n" +
+				"}\n" +
+				"@Retention(RUNTIME)\n" +
+				"@Repeatable(AttrContainer.class)\n" + 
+				"@interface Attr {\n" +
+				"  public int value() default -1;\n" +
+				"}\n" +
+				"\n" +
+				"public class X {\n" +
+				"   @Attr(1) @Attr(2) public int field;\n" + 
+				"\n" + 
+				"   @Attr(3) @Attr(4)\n" + 
+				"   public static void main(@Attr(5) @Attr(6) String args[]) throws Exception {\n" + 
+				"    Field fieldField = X.class.getField(\"field\");\n" + 
+				"    dump(fieldField.getAnnotationsByType(Attr.class));\n" + 
+				"    Method mainMethod = X.class.getMethod(\"main\", (new String[0]).getClass());\n" + 
+				"    dump(mainMethod.getAnnotationsByType(Attr.class));\n" + 
+				"    Parameter argvParameter = mainMethod.getParameters()[0];\n" + 
+				"    dump(argvParameter.getAnnotationsByType(Attr.class));\n" + 
+				"   }\n" + 
+				"   static void dump(Attr[] attrs) {\n" + 
+				"    for (int i=0; i<attrs.length;++i) System.out.print(attrs[i] + \" \");\n" + 
+				"   }\n" +
+				"}"
+			},
+			"@Attr(value=1) @Attr(value=2) @Attr(value=3) @Attr(value=4) @Attr(value=5) @Attr(value=6)");
+	}
+	// Test that repeated annotations show up type parameters properly.
+	public void testTypeParameters() {
+		this.runConformTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.Annotation;\n" +
+				"import java.lang.annotation.ElementType;\n" +
+				"import java.lang.annotation.Repeatable;\n" +
+				"import java.lang.annotation.Retention;\n" +
+				"import java.lang.annotation.Target;\n" +
+				"import java.lang.reflect.AnnotatedElement;\n" +
+				"import java.lang.reflect.AnnotatedType;\n" +
+				"import java.lang.reflect.Field;\n" +
+				"import java.lang.reflect.Method;\n" +
+				"import java.lang.reflect.Type;\n" +
+				"import java.lang.reflect.TypeVariable;\n" +
+				"\n" +
+				"import static java.lang.annotation.RetentionPolicy.*;\n" +
+				"\n" +
+				"@Retention(RUNTIME)\n" +
+				"@Target({ElementType.TYPE_USE, ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER,})\n" +
+				"@interface TC {\n" +
+				"  public T[] value();\n" +
+				"}\n" +
+				"@Retention(RUNTIME)\n" +
+				"@Repeatable(TC.class)\n" +
+				"@Target({ElementType.TYPE_USE, ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.METHOD})\n" +
+				"@interface T {\n" +
+				"  public int value() default -1;\n" +
+				"}\n" +
+				"\n" +
+				"interface I<@T(1) @T(2) K extends @T(3) @T(4) Object & java.lang.@T(5) @T(6) Comparable<?>> {\n" +
+				"}\n" +
+				"\n" +
+				"\n" +
+				"public class X {\n" +
+				"  public static void main(String args[]) {\n" +
+				"	Class<I> ci = I.class;  \n" +
+				"  	printAnnotations(\"I.class\", ci);\n" +
+				"  	TypeVariable<Class<I>>[] typeParameters = ci.getTypeParameters();\n" +
+				"  	for (TypeVariable<?> t: typeParameters) {\n" +
+				"  		printAnnotations(t.getName(), t);\n" +
+				"  		AnnotatedType[] bounds = t.getAnnotatedBounds();\n" +
+				"  		for (AnnotatedType bound : bounds) {\n" +
+				"  			printAnnotations(bound.getType().getTypeName(), bound);\n" +
+				"  		}\n" +
+				"  	}\n" +
+				"  }\n" +
+				"  \n" +
+				"  static void printAnnotations(String name, AnnotatedElement element) {\n" +
+				"	  int [] iterations = { 0, 1 };\n" +
+				"	  for (int i : iterations) {\n" +
+				"		  Class<? extends Annotation> annotation = i == 0 ? T.class : TC.class;\n" +
+				"		  for (int j: iterations) {\n" +
+				"			  Annotation [] annotations = j == 0 ? new Annotation [] { element.getAnnotation(annotation) } : element.getAnnotationsByType(annotation);\n" +
+				"			  if (annotations.length == 0 || (annotations.length == 1 && annotations[0] == null)) continue;\n" +
+				"			  System.out.print(name + (j == 0 ? \".getAnnotation(\" : \".getAnnotationByType(\") + annotation.getName() + \".class): \");\n" +
+				"			  for (Annotation a : annotations) {\n" +
+				"				  System.out.print(a + \" \");\n" +
+				"			  }\n" +
+				"			  System.out.println();\n" +
+				"		  }\n" +
+				"	  }\n" +
+				"  }\n" +
+				"}\n"
+
+			},
+			"K.getAnnotationByType(T.class): @T(value=1) @T(value=2) \n" +
+			"K.getAnnotation(TC.class): @TC(value=[@T(value=1), @T(value=2)]) \n" +
+			"K.getAnnotationByType(TC.class): @TC(value=[@T(value=1), @T(value=2)]) \n" +
+			"java.lang.Object.getAnnotationByType(T.class): @T(value=3) @T(value=4) \n" +
+			"java.lang.Object.getAnnotation(TC.class): @TC(value=[@T(value=3), @T(value=4)]) \n" +
+			"java.lang.Object.getAnnotationByType(TC.class): @TC(value=[@T(value=3), @T(value=4)]) \n" +
+			"java.lang.Comparable<?>.getAnnotationByType(T.class): @T(value=5) @T(value=6) \n" +
+			"java.lang.Comparable<?>.getAnnotation(TC.class): @TC(value=[@T(value=5), @T(value=6)]) \n" +
+			"java.lang.Comparable<?>.getAnnotationByType(TC.class): @TC(value=[@T(value=5), @T(value=6)])",
+			null,
+			true,
+			new String [] { "" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution.
+	}
+	// Test that repeated annotations show up at various sites, both type use and declaration.
+	public void testVariousSites() {
+		this.runConformTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.Annotation;\n" +
+				"import java.lang.annotation.ElementType;\n" +
+				"import java.lang.annotation.Repeatable;\n" +
+				"import java.lang.annotation.Retention;\n" +
+				"import java.lang.annotation.Target;\n" +
+				"import java.lang.reflect.AnnotatedArrayType;\n" +
+				"import java.lang.reflect.AnnotatedElement;\n" +
+				"import java.lang.reflect.AnnotatedParameterizedType;\n" +
+				"import java.lang.reflect.AnnotatedType;\n" +
+				"import java.lang.reflect.Constructor;\n" +
+				"import java.lang.reflect.Field;\n" +
+				"import java.lang.reflect.Method;\n" +
+				"import java.lang.reflect.TypeVariable;\n" +
+				"\n" +
+				"import static java.lang.annotation.RetentionPolicy.*;\n" +
+				"\n" +
+				"@Retention(RUNTIME)\n" +
+				"@Target({ElementType.TYPE_USE, ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.METHOD})\n" +
+				"@interface TC {\n" +
+				"  public T[] value();\n" +
+				"}\n" +
+				"@Retention(RUNTIME)\n" +
+				"@Repeatable(TC.class)\n" +
+				"@Target({ElementType.TYPE_USE, ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.METHOD})\n" +
+				"@interface T {\n" +
+				"  public int value() default -1;\n" +
+				"}\n" +
+				"\n" +
+				"interface I {\n" +
+				"}\n" +
+				"\n" +
+				"@T(1) @T(2)\n" +
+				"public class X<@T(3) @T(4) K extends @T(5) @T(6) Object & java.lang.@T(7) @T(8) Comparable<?>, @T(9) @T(10) V> extends @T(11) @T(12) Object implements @T(13) @T(14) I {\n" +
+				"  public @T(15) @T(16) X<@T(17) @T(18) String, @T(19) @T(20) Integer> field;\n" +
+				"  @T(21) @T(22)\n" +
+				"  public <@T(23) @T(24) Q> X @T(25) @T(26) [] method(@T(27) @T(28) X<K, V> this, \n" +
+				"		                                             @T(29) @T(30) X<@T(31) @T(32) String, String> that) throws @T(33) @T(34) NullPointerException {\n" +
+				"	  return null;\n" +
+				"  }\n" +
+				"  @T(35) @T(36)\n" +
+				"  public X() {\n" +
+				"	  \n" +
+				"  }\n" +
+				"  @T(37) @T(48)\n" +
+				"  public class MemberType {\n" +
+				"	  \n" +
+				"  }\n" +
+				"  \n" +
+				"  public static void main(String args[]) {\n" +
+				"	Class<X> xc = X.class;  \n" +
+				"  	printAnnotations(\"Class: \" + \"X.class\", xc);\n" +
+				"  	TypeVariable<Class<X>>[] typeParameters = xc.getTypeParameters();\n" +
+				"  	for (TypeVariable<?> t: typeParameters) {\n" +
+				"  		printAnnotations(\"Type Parameter: \" + t.getName(), t);\n" +
+				"  		AnnotatedType[] bounds = t.getAnnotatedBounds();\n" +
+				"  		for (AnnotatedType bound : bounds) {\n" +
+				"  			printAnnotations(\"Type parameter bound: \" + bound.getType().getTypeName(), bound);\n" +
+				"  		}\n" +
+				"  	}\n" +
+				"  	AnnotatedType annotatedSuperclass = xc.getAnnotatedSuperclass();\n" +
+				"  	printAnnotations(\"Superclass: \" + annotatedSuperclass.getType().getTypeName(), annotatedSuperclass);\n" +
+				"  	\n" +
+				"  	AnnotatedType [] annotatedSuperInterfaces = xc.getAnnotatedInterfaces();\n" +
+				"  	printAnnotations(\"Superinterface: \" + annotatedSuperInterfaces[0].getType().getTypeName(), annotatedSuperInterfaces[0]);\n" +
+				"  	\n" +
+				"  	for (Field field: xc.getFields()) {\n" +
+				"  		printAnnotations(\"Field: \" + field.getName(), field);\n" +
+				"  		AnnotatedParameterizedType fType = (AnnotatedParameterizedType) field.getAnnotatedType();\n" +
+				"  		for (AnnotatedType typeArgumentType : fType.getAnnotatedActualTypeArguments())\n" +
+				"  			printAnnotations(\"Field Type argument: \" + typeArgumentType.getType().getTypeName(), typeArgumentType);\n" +
+				"  			\n" +
+				"  	}\n" +
+				"  	for (Method method: xc.getMethods()) {\n" +
+				"  		switch (method.getName()) {\n" +
+				"  		case \"method\"  :\n" +
+				"  			printAnnotations(method.getName(), method);\n" +
+				"  			AnnotatedArrayType mType = (AnnotatedArrayType) method.getAnnotatedReturnType();\n" +
+				"  			printAnnotations(\"Method return type: \" + mType.getType().getTypeName(), mType);\n" +
+				"  			AnnotatedType mTypeEtype = mType.getAnnotatedGenericComponentType();\n" +
+				"  			printAnnotations(\"Method return type, element type: \" + mTypeEtype.getType().getTypeName(), mTypeEtype);\n" +
+				"  			TypeVariable<Method>[] typeParameters2 = method.getTypeParameters();\n" +
+				"  		  	for (TypeVariable<?> t: typeParameters2) {\n" +
+				"  		  		printAnnotations(\"Method Type Parameter: \" + t.getName(), t);\n" +
+				"  		  	}\n" +
+				"  		  	AnnotatedType annotatedReceiverType = method.getAnnotatedReceiverType();\n" +
+				"  		  	printAnnotations(\"Receiver: \", annotatedReceiverType);\n" +
+				"  		  	AnnotatedType[] annotatedParameterTypes = method.getAnnotatedParameterTypes();\n" +
+				"  		  	for (AnnotatedType annotatedParameterType : annotatedParameterTypes) {\n" +
+				"  		  		printAnnotations(\"Parameter: \", annotatedParameterType);\n" +
+				"  		  	}\n" +
+				"  		  	AnnotatedType[] annotatedExceptionTypes = method.getAnnotatedExceptionTypes();\n" +
+				"  		  	for (AnnotatedType annotatedType : annotatedExceptionTypes) {\n" +
+				"				printAnnotations(\"Exception type: \", annotatedType);\n" +
+				"			}\n" +
+				"  			break;\n" +
+				"  		}\n" +
+				"  	}\n" +
+				"  	for (Constructor<?> constructor : xc.getConstructors()) {\n" +
+				"  		printAnnotations(\"Constructor: \", constructor);\n" +
+				"  	}\n" +
+				"  	// don't know how to get member classes.\n" +
+				"  }\n" +
+				"  \n" +
+				"  static void printAnnotations(String name, AnnotatedElement element) {\n" +
+				"	  int [] iterations = { 0, 1 };\n" +
+				"	  for (int i : iterations) {\n" +
+				"		  Class<? extends Annotation> annotation = i == 0 ? T.class : TC.class;\n" +
+				"		  for (int j: iterations) {\n" +
+				"			  Annotation [] annotations = j == 0 ? new Annotation [] { element.getAnnotation(annotation) } : element.getAnnotationsByType(annotation);\n" +
+				"			  if (annotations.length == 0 || (annotations.length == 1 && annotations[0] == null)) continue;\n" +
+				"			  System.out.print(name + (j == 0 ? \".getAnnotation(\" : \".getAnnotationByType(\") + annotation.getName() + \".class): \");\n" +
+				"			  for (Annotation a : annotations) {\n" +
+				"				  System.out.print(a + \" \");\n" +
+				"			  }\n" +
+				"			  System.out.println();\n" +
+				"		  }\n" +
+				"	  }\n" +
+				"  }\n" +
+				"}\n"
+
+			},
+			"Class: X.class.getAnnotationByType(T.class): @T(value=1) @T(value=2) \n" +
+			"Class: X.class.getAnnotation(TC.class): @TC(value=[@T(value=1), @T(value=2)]) \n" +
+			"Class: X.class.getAnnotationByType(TC.class): @TC(value=[@T(value=1), @T(value=2)]) \n" +
+			"Type Parameter: K.getAnnotationByType(T.class): @T(value=3) @T(value=4) \n" +
+			"Type Parameter: K.getAnnotation(TC.class): @TC(value=[@T(value=3), @T(value=4)]) \n" +
+			"Type Parameter: K.getAnnotationByType(TC.class): @TC(value=[@T(value=3), @T(value=4)]) \n" +
+			"Type parameter bound: java.lang.Object.getAnnotationByType(T.class): @T(value=5) @T(value=6) \n" +
+			"Type parameter bound: java.lang.Object.getAnnotation(TC.class): @TC(value=[@T(value=5), @T(value=6)]) \n" +
+			"Type parameter bound: java.lang.Object.getAnnotationByType(TC.class): @TC(value=[@T(value=5), @T(value=6)]) \n" +
+			"Type parameter bound: java.lang.Comparable<?>.getAnnotationByType(T.class): @T(value=7) @T(value=8) \n" +
+			"Type parameter bound: java.lang.Comparable<?>.getAnnotation(TC.class): @TC(value=[@T(value=7), @T(value=8)]) \n" +
+			"Type parameter bound: java.lang.Comparable<?>.getAnnotationByType(TC.class): @TC(value=[@T(value=7), @T(value=8)]) \n" +
+			"Type Parameter: V.getAnnotationByType(T.class): @T(value=9) @T(value=10) \n" +
+			"Type Parameter: V.getAnnotation(TC.class): @TC(value=[@T(value=9), @T(value=10)]) \n" +
+			"Type Parameter: V.getAnnotationByType(TC.class): @TC(value=[@T(value=9), @T(value=10)]) \n" +
+			"Superclass: java.lang.Object.getAnnotationByType(T.class): @T(value=11) @T(value=12) \n" +
+			"Superclass: java.lang.Object.getAnnotation(TC.class): @TC(value=[@T(value=11), @T(value=12)]) \n" +
+			"Superclass: java.lang.Object.getAnnotationByType(TC.class): @TC(value=[@T(value=11), @T(value=12)]) \n" +
+			"Superinterface: I.getAnnotationByType(T.class): @T(value=13) @T(value=14) \n" +
+			"Superinterface: I.getAnnotation(TC.class): @TC(value=[@T(value=13), @T(value=14)]) \n" +
+			"Superinterface: I.getAnnotationByType(TC.class): @TC(value=[@T(value=13), @T(value=14)]) \n" +
+			"Field: field.getAnnotationByType(T.class): @T(value=15) @T(value=16) \n" +
+			"Field: field.getAnnotation(TC.class): @TC(value=[@T(value=15), @T(value=16)]) \n" +
+			"Field: field.getAnnotationByType(TC.class): @TC(value=[@T(value=15), @T(value=16)]) \n" +
+			"Field Type argument: java.lang.String.getAnnotationByType(T.class): @T(value=17) @T(value=18) \n" +
+			"Field Type argument: java.lang.String.getAnnotation(TC.class): @TC(value=[@T(value=17), @T(value=18)]) \n" +
+			"Field Type argument: java.lang.String.getAnnotationByType(TC.class): @TC(value=[@T(value=17), @T(value=18)]) \n" +
+			"Field Type argument: java.lang.Integer.getAnnotationByType(T.class): @T(value=19) @T(value=20) \n" +
+			"Field Type argument: java.lang.Integer.getAnnotation(TC.class): @TC(value=[@T(value=19), @T(value=20)]) \n" +
+			"Field Type argument: java.lang.Integer.getAnnotationByType(TC.class): @TC(value=[@T(value=19), @T(value=20)]) \n" +
+			"method.getAnnotationByType(T.class): @T(value=21) @T(value=22) \n" +
+			"method.getAnnotation(TC.class): @TC(value=[@T(value=21), @T(value=22)]) \n" +
+			"method.getAnnotationByType(TC.class): @TC(value=[@T(value=21), @T(value=22)]) \n" +
+			"Method return type: X[].getAnnotationByType(T.class): @T(value=25) @T(value=26) \n" +
+			"Method return type: X[].getAnnotation(TC.class): @TC(value=[@T(value=25), @T(value=26)]) \n" +
+			"Method return type: X[].getAnnotationByType(TC.class): @TC(value=[@T(value=25), @T(value=26)]) \n" +
+			"Method return type, element type: X.getAnnotationByType(T.class): @T(value=21) @T(value=22) \n" +
+			"Method return type, element type: X.getAnnotation(TC.class): @TC(value=[@T(value=21), @T(value=22)]) \n" +
+			"Method return type, element type: X.getAnnotationByType(TC.class): @TC(value=[@T(value=21), @T(value=22)]) \n" +
+			"Method Type Parameter: Q.getAnnotationByType(T.class): @T(value=23) @T(value=24) \n" +
+			"Method Type Parameter: Q.getAnnotation(TC.class): @TC(value=[@T(value=23), @T(value=24)]) \n" +
+			"Method Type Parameter: Q.getAnnotationByType(TC.class): @TC(value=[@T(value=23), @T(value=24)]) \n" +
+			"Receiver: .getAnnotationByType(T.class): @T(value=27) @T(value=28) \n" +
+			"Receiver: .getAnnotation(TC.class): @TC(value=[@T(value=27), @T(value=28)]) \n" +
+			"Receiver: .getAnnotationByType(TC.class): @TC(value=[@T(value=27), @T(value=28)]) \n" +
+			"Parameter: .getAnnotationByType(T.class): @T(value=29) @T(value=30) \n" +
+			"Parameter: .getAnnotation(TC.class): @TC(value=[@T(value=29), @T(value=30)]) \n" +
+			"Parameter: .getAnnotationByType(TC.class): @TC(value=[@T(value=29), @T(value=30)]) \n" +
+			"Exception type: .getAnnotationByType(T.class): @T(value=33) @T(value=34) \n" +
+			"Exception type: .getAnnotation(TC.class): @TC(value=[@T(value=33), @T(value=34)]) \n" +
+			"Exception type: .getAnnotationByType(TC.class): @TC(value=[@T(value=33), @T(value=34)]) \n" +
+			"Constructor: .getAnnotationByType(T.class): @T(value=35) @T(value=36) \n" +
+			"Constructor: .getAnnotation(TC.class): @TC(value=[@T(value=35), @T(value=36)]) \n" +
+			"Constructor: .getAnnotationByType(TC.class): @TC(value=[@T(value=35), @T(value=36)])",
+			null,
+			true,
+			new String [] { "" }); // Not sure, unless we force the VM to not be reused by passing dummy vm argument, the generated program aborts midway through its execution.
+	}
+
+	// Test that bad container specifications are handled properly.
+	public void testBadContainerType() {
+		this.runNegativeTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.Repeatable;\n" +
+				"@Repeatable(X.class)\n" +
+				"@interface T {\n" +
+				"  public int value() default -1;\n" +
+				"}\n" +
+				"public class X {\n" +
+				"}\n"
+			},
+			"----------\n" + 
+			"1. ERROR in X.java (at line 2)\n" + 
+			"	@Repeatable(X.class)\n" + 
+			"	            ^^^^^^^\n" + 
+			"Type mismatch: cannot convert from Class<X> to Class<? extends Annotation>\n" + 
+			"----------\n");
+	}	
+	// Test unspecified target.
+	public void testUnspecifiedTarget() {
+		this.runNegativeTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.ElementType;\n" +
+				"import java.lang.annotation.Repeatable;\n" +
+				"import java.lang.annotation.Target;\n" +
+				"\n" +
+				"@Target(ElementType.TYPE_USE)\n" +
+				"@interface TC {\n" +
+				"	T [] value();\n" +
+				"}\n" +
+				"\n" +
+				"@Repeatable(TC.class)\n" +
+				"@interface T {\n" +
+				"}\n" +
+				"\n" +
+				"@T @T\n" +
+				"public class X { \n" +
+				"	X f;\n" +
+				"}\n"
+			},
+			"----------\n" + 
+			"1. ERROR in X.java (at line 10)\n" + 
+			"	@Repeatable(TC.class)\n" + 
+			"	            ^^^^^^^^\n" + 
+			"The container annotation type @TC is allowed at targets where the repeatable annotation type @T is not: TYPE_USE\n" + 
+			"----------\n");
+	}
+	// Test unspecified target.
+	public void testUnspecifiedTarget2() {
+		this.runNegativeTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.ElementType;\n" +
+				"import java.lang.annotation.Repeatable;\n" +
+				"import java.lang.annotation.Target;\n" +
+				"\n" +
+				"@Target(ElementType.TYPE_PARAMETER)\n" +
+				"@interface TC {\n" +
+				"	T [] value();\n" +
+				"}\n" +
+				"\n" +
+				"@Repeatable(TC.class)\n" +
+				"@interface T {\n" +
+				"}\n" +
+				"\n" +
+				"@T @T\n" +
+				"public class X { \n" +
+				"	X f;\n" +
+				"}\n"
+			},
+			"----------\n" + 
+			"1. ERROR in X.java (at line 10)\n" + 
+			"	@Repeatable(TC.class)\n" + 
+			"	            ^^^^^^^^\n" + 
+			"The container annotation type @TC is allowed at targets where the repeatable annotation type @T is not: TYPE_PARAMETER\n" + 
+			"----------\n" + 
+			"2. ERROR in X.java (at line 14)\n" + 
+			"	@T @T\n" + 
+			"	^^\n" + 
+			"The annotation @T cannot be repeated at this location since its container annotation type @TC is disallowed at this location\n" + 
+			"----------\n");
+	}
+	public void testDeprecation() {
+		this.runNegativeTest(
+			new String[] {
+				"TC.java",
+				"@Deprecated\n" +
+				"public @interface TC {\n" +
+				"  public T[] value();\n" +
+				"}\n",
+				"T.java",
+				"@java.lang.annotation.Repeatable(TC.class)\n" +
+				"@interface T {\n" +
+				"  public int value() default -1;\n" +  
+				"}\n" +
+				"interface I<@T(1) @T(2) K> {\n" +
+				"}\n"
+			},
+			"----------\n" + 
+			"1. WARNING in T.java (at line 1)\n" + 
+			"	@java.lang.annotation.Repeatable(TC.class)\n" + 
+			"	                                 ^^\n" + 
+			"The type TC is deprecated\n" + 
+			"----------\n" + 
+			"2. ERROR in T.java (at line 5)\n" + 
+			"	interface I<@T(1) @T(2) K> {\n" + 
+			"	            ^^\n" + 
+			"Annotation types that do not specify explicit target element types cannot be applied here\n" + 
+			"----------\n" + 
+			"3. WARNING in T.java (at line 5)\n" + 
+			"	interface I<@T(1) @T(2) K> {\n" + 
+			"	            ^^\n" + 
+			"The type TC is deprecated\n" + 
+			"----------\n" + 
+			"4. ERROR in T.java (at line 5)\n" + 
+			"	interface I<@T(1) @T(2) K> {\n" + 
+			"	            ^^\n" + 
+			"Annotation types that do not specify explicit target element types cannot be applied here\n" + 
+			"----------\n" + 
+			"5. ERROR in T.java (at line 5)\n" + 
+			"	interface I<@T(1) @T(2) K> {\n" + 
+			"	                  ^^\n" + 
+			"Annotation types that do not specify explicit target element types cannot be applied here\n" + 
+			"----------\n");
+	}
+	public void testDeprecation2() { // verify that deprecation warning does not show up when the deprecated element is used in the same file defining it.
+		this.runNegativeTest(
+			new String[] {
+				"T.java",
+				"@Deprecated\n" +
+				"@interface TC {\n" +
+				"  public T[] value();\n" +
+				"}\n" +
+				"@java.lang.annotation.Repeatable(TC.class)\n" +
+				"@interface T {\n" +
+				"  public int value() default -1;\n" +  
+				"}\n" +
+				"interface I<@T(1) @T(2) K> {\n" +
+				"}\n"
+			},
+			"----------\n" + 
+			"1. ERROR in T.java (at line 9)\n" + 
+			"	interface I<@T(1) @T(2) K> {\n" + 
+			"	            ^^\n" + 
+			"Annotation types that do not specify explicit target element types cannot be applied here\n" + 
+			"----------\n" + 
+			"2. ERROR in T.java (at line 9)\n" + 
+			"	interface I<@T(1) @T(2) K> {\n" + 
+			"	            ^^\n" + 
+			"Annotation types that do not specify explicit target element types cannot be applied here\n" + 
+			"----------\n" + 
+			"3. ERROR in T.java (at line 9)\n" + 
+			"	interface I<@T(1) @T(2) K> {\n" + 
+			"	                  ^^\n" + 
+			"Annotation types that do not specify explicit target element types cannot be applied here\n" + 
 			"----------\n");
 	}	
 }
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TypeAnnotationTest.java
index 47bd5f5..163a184 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TypeAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TypeAnnotationTest.java
@@ -6023,6 +6023,111 @@
 					"      )\n" + 
 					"}";
 			checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput, ClassFileBytesDisassembler.SYSTEM);
+	}
+	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=419331, [1.8][compiler] Weird error on forward reference to type annotations from type parameter declarations
+	// ENCODES WRONG BEHAVIOR - FIX TEST ALONG WITH FIX
+	public void testForwardReference() {
+		this.runNegativeTest(
+			new String[] {
+				"T.java",
+				"import java.lang.annotation.Annotation;\n" +
+				"import java.lang.annotation.ElementType;\n" +
+				"import java.lang.annotation.Target;\n" +
+				"\n" +
+				"@R(TC.class)\n" +
+				"@Target(ElementType.TYPE_PARAMETER)\n" +
+				"@interface T {\n" +
+				"}\n" +
+				"\n" +
+				"interface I<@T K> {\n" +
+				"}\n" +
+				"\n" +
+				"@Deprecated\n" +
+				"@interface TC {\n" +
+				"\n" +
+				"}\n" +
+				"\n" +
+				"@Target(ElementType.ANNOTATION_TYPE)\n" +
+				"@interface R {\n" +
+				"    Class<? extends Annotation> value();\n" +
+				"}\n",
+			},
+			"----------\n" + 
+			"1. ERROR in T.java (at line 5)\n" + 
+			"	@R(TC.class)\n" + 
+			"	   ^^^^^^^^\n" + 
+			"Type mismatch: cannot convert from Class<TC> to Class<? extends Annotation>\n" + 
+			"----------\n");
+	}
+	public void testHybridTargets() throws Exception {
+		this.runConformTest(
+			new String[] {
+				"X.java",
+				"import java.lang.annotation.ElementType;\n" +
+				"import java.lang.annotation.Target;\n" +
+				"@Target({ElementType.TYPE_USE, ElementType.PACKAGE})\n" +
+				"@interface T {\n" +
+				"}\n" +
+				"@T\n" +
+				"public class X {\n" +
+				"    @T\n" +
+				"    X() {}\n" +
+				"    @T String x;\n" +
+				"    @T \n" +
+				"	int foo(@T int p) { \n" +
+				"      @T int l;\n" +
+				"	   return 0;\n" +
+				"   }\n" +
+				"}\n",
+			},
+			"");
+		String expectedOutput =
+				"  // Field descriptor #6 Ljava/lang/String;\n" + 
+				"  java.lang.String x;\n" + 
+				"    RuntimeInvisibleTypeAnnotations: \n" + 
+				"      #8 @T(\n" + 
+				"        target type = 0x13 FIELD\n" + 
+				"      )\n" + 
+				"  \n" + 
+				"  // Method descriptor #10 ()V\n" + 
+				"  // Stack: 1, Locals: 1\n" + 
+				"  X();\n" + 
+				"    0  aload_0 [this]\n" + 
+				"    1  invokespecial java.lang.Object() [12]\n" + 
+				"    4  return\n" + 
+				"      Line numbers:\n" + 
+				"        [pc: 0, line: 9]\n" + 
+				"      Local variable table:\n" + 
+				"        [pc: 0, pc: 5] local: this index: 0 type: X\n" + 
+				"    RuntimeInvisibleTypeAnnotations: \n" + 
+				"      #8 @T(\n" + 
+				"        target type = 0x14 METHOD_RETURN\n" + 
+				"      )\n" + 
+				"  \n" + 
+				"  // Method descriptor #19 (I)I\n" + 
+				"  // Stack: 1, Locals: 2\n" + 
+				"  int foo(int p);\n" + 
+				"    0  iconst_0\n" + 
+				"    1  ireturn\n" + 
+				"      Line numbers:\n" + 
+				"        [pc: 0, line: 14]\n" + 
+				"      Local variable table:\n" + 
+				"        [pc: 0, pc: 2] local: this index: 0 type: X\n" + 
+				"        [pc: 0, pc: 2] local: p index: 1 type: int\n" + 
+				"    RuntimeInvisibleTypeAnnotations: \n" + 
+				"      #8 @T(\n" + 
+				"        target type = 0x16 METHOD_FORMAL_PARAMETER\n" + 
+				"        method parameter index = 0\n" + 
+				"      )\n" + 
+				"      #8 @T(\n" + 
+				"        target type = 0x14 METHOD_RETURN\n" + 
+				"      )\n" + 
+				"\n" + 
+				"  RuntimeInvisibleAnnotations: \n" + 
+				"    #8 @T(\n" + 
+				"    )\n" + 
+				"}";
+		checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput, ClassFileBytesDisassembler.SYSTEM);
 	}	
 }
 
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava8Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava8Tests.java
index 4aaaa42..e249117 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava8Tests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava8Tests.java
@@ -62,6 +62,9 @@
 				ASTConverter18Test.class,
 				ASTRewritingTest.class,
 				TypeBindingTests308.class,
+/*{ObjectTeams: not included:
+				Java8ElementsTests.class,
+// SH}*/
 		};
 	}
 
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15JLS8Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15JLS8Test.java
index e2c4404..44d5367 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15JLS8Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15JLS8Test.java
@@ -4738,7 +4738,7 @@
     	assertNotNull("No node", node);
     	assertEquals("Not a compilation unit", ASTNode.COMPILATION_UNIT, node.getNodeType());
     	CompilationUnit compilationUnit = (CompilationUnit) node;
-        final String expectedErrors = "The member enum E can only be defined inside a top-level class or interface";
+        final String expectedErrors = "The member enum E can only be defined inside a top-level class or interface or in a static context";
     	assertProblemsSize(compilationUnit, 1, expectedErrors);
 		node = getASTNode(compilationUnit, 0, 0, 0);
    		assertEquals("Not a type declaration statement", ASTNode.TYPE_DECLARATION_STATEMENT, node.getNodeType());
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
index 73afc7c..7af45d8 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
@@ -27,6 +27,7 @@
 import org.eclipse.jdt.core.dom.ArrayCreation;
 import org.eclipse.jdt.core.dom.ArrayType;
 import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.Dimension;
 import org.eclipse.jdt.core.dom.ITypeBinding;
 import org.eclipse.jdt.core.dom.MethodDeclaration;
 import org.eclipse.jdt.core.dom.SimpleType;
@@ -108,6 +109,56 @@
 		annotation = (ASTNode) annotations.get(0);
 		checkSourceRange(annotation, "@Marker", contents);
 	}
+	/*
+	 * Type Annotations on Variable Argument of ArrayType
+	 */
+	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=413569
+	public void test413569() throws JavaModelException {
+		String contents =
+			"import java.lang.annotation.*;\n" +
+			"public class X {\n" +
+			"	@Target(ElementType.TYPE_USE) static @interface A {}\n" + 
+			"	@Target(ElementType.TYPE_USE) static @interface B {}\n" + 
+			"	@Target(ElementType.TYPE_USE) static @interface C { Class<?> value() default Object.class; }\n" + 
+			"	@Target(ElementType.TYPE_USE) static @interface D { Class<?> d(); }\n" + 
+			"	void foo(@A int @B()[] @C(int[].class) [] @D(d=String[].class)... arg) {}\n" +
+			"}";
+		this.workingCopy = getWorkingCopy("/Converter18/src/X.java", true/*resolve*/);
+		ASTNode node = buildAST(
+			contents,
+			this.workingCopy);
+		assertEquals("Not a compilation unit", ASTNode.COMPILATION_UNIT, node.getNodeType());
+		CompilationUnit compilationUnit = (CompilationUnit) node;
+		assertProblemsSize(compilationUnit, 0);
+		node = getASTNode(compilationUnit, 0, 4);
+		assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION);
+		MethodDeclaration methodDeclaration = (MethodDeclaration) node;
+		List parameters = methodDeclaration.parameters();
+		assertEquals("wrong size", 1, parameters.size());
+		SingleVariableDeclaration parameter = (SingleVariableDeclaration) parameters.get(0);
+		
+		ArrayType type = (ArrayType) parameter.getType();
+		List dimensions = type.dimensions();
+		assertEquals(2, dimensions.size());
+		
+		Dimension dimension = (Dimension) dimensions.get(0);
+		List annotations = dimension.annotations();
+		assertEquals("Wrong number of annotations", 1, annotations.size());
+		Annotation annotation = (Annotation) annotations.get(0);
+		checkSourceRange(annotation, "@B()", contents);
+		
+		dimension = (Dimension) dimensions.get(1);
+		annotations = dimension.annotations();
+		assertEquals("Wrong number of annotations", 1, annotations.size());
+		annotation = (Annotation) annotations.get(0);
+		checkSourceRange(annotation, "@C(int[].class)", contents);
+		
+		annotations = parameter.varargsAnnotations();
+		assertEquals("Wrong number of annotations", 1, annotations.size());
+		annotation = (Annotation) annotations.get(0);
+		checkSourceRange(annotation, "@D(d=String[].class)", contents);
+		
+	}
 	/**
 	 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=395886 tests annotations on
 	 * QTR in multiple scenarios of occurrence.
@@ -254,7 +305,7 @@
 	 * 
 	 * @throws JavaModelException
 	 */
-	public void test0004() throws JavaModelException {
+	public void _test0004() throws JavaModelException {
 		this.workingCopy = getWorkingCopy("/Converter18/src/test0004/X.java",
 				true/* resolve */);
 		String contents = "package test0004;"
@@ -405,7 +456,7 @@
 	 * 
 	 * @throws JavaModelException
 	 */
-	public void test0006() throws JavaModelException {
+	public void _test0006() throws JavaModelException {
 		this.workingCopy = getWorkingCopy("/Converter18/src/test0006/X.java",
 				true);
 		String contents = "package test0006;"
@@ -1139,12 +1190,12 @@
 		Type type = creation.getType();
 		assertEquals("Incorrect type", true, type.isArrayType());
 		checkSourceRange(type, "@Marker2 int @Marker @Marker2 [2] @Marker2 @Marker3 [bar()] @Marker3 @Marker []", contents.toCharArray());
-		ExtraDimension extraDimension = ((ArrayType) type).getDimensionAt(0);
-		assertEquals("Incorrect annotations", "@Marker3 @Marker ", convertAnnotationsList(extraDimension.annotations()));
-		extraDimension = ((ArrayType) type).getDimensionAt(1);
-		assertEquals("Incorrect annotations", "@Marker2 @Marker3 ", convertAnnotationsList(extraDimension.annotations()));
-		extraDimension = ((ArrayType) type).getDimensionAt(2);
-		assertEquals("Incorrect annotations", "@Marker @Marker2 ", convertAnnotationsList(extraDimension.annotations()));
+		Dimension dimension = (Dimension) ((ArrayType) type).dimensions().get(2);
+		assertEquals("Incorrect annotations", "@Marker3 @Marker ", convertAnnotationsList(dimension.annotations()));
+		dimension = (Dimension) ((ArrayType) type).dimensions().get(1);
+		assertEquals("Incorrect annotations", "@Marker2 @Marker3 ", convertAnnotationsList(dimension.annotations()));
+		dimension = (Dimension) ((ArrayType) type).dimensions().get(0);
+		assertEquals("Incorrect annotations", "@Marker @Marker2 ", convertAnnotationsList(dimension.annotations()));
 		List dimensions = creation.dimensions();
 		assertEquals("Incorrect expressions", 2, dimensions.size());
 		assertEquals("Incorrect expressions", "2", dimensions.get(0).toString());
@@ -1158,12 +1209,12 @@
 		
 		type = creation.getType();
 		assertEquals("Incorrect type", true, type.isArrayType());
-		extraDimension = ((ArrayType) type).getDimensionAt(0);
-		assertEquals("Incorrect annotations", "@Marker2 @Marker3 ", convertAnnotationsList(extraDimension.annotations()));
-		extraDimension = ((ArrayType) type).getDimensionAt(1);
-		assertEquals("Incorrect annotations", "@Marker @Marker2 ", convertAnnotationsList(extraDimension.annotations()));
-		extraDimension = ((ArrayType) type).getDimensionAt(2);
-		assertEquals("Incorrect annotations", "@Marker3 @Marker ", convertAnnotationsList(extraDimension.annotations()));
+		dimension = (Dimension) ((ArrayType) type).dimensions().get(2);
+		assertEquals("Incorrect annotations", "@Marker2 @Marker3 ", convertAnnotationsList(dimension.annotations()));
+		dimension = (Dimension) ((ArrayType) type).dimensions().get(1);
+		assertEquals("Incorrect annotations", "@Marker @Marker2 ", convertAnnotationsList(dimension.annotations()));
+		dimension = (Dimension) ((ArrayType) type).dimensions().get(0);
+		assertEquals("Incorrect annotations", "@Marker3 @Marker ", convertAnnotationsList(dimension.annotations()));
 		dimensions = creation.dimensions();
 		assertEquals("Incorrect expressions", 2, dimensions.size());
 		assertEquals("Incorrect expressions", "2", dimensions.get(0).toString());
@@ -2939,20 +2990,20 @@
 		checkSourceRange(arrayType, "@NonEmpty(0) int @NonNull(value1 = 1) [] @NonEmpty(1) [ ]", contents);
 		PrimitiveType primitiveType = (PrimitiveType) arrayType.getElementType();
 		checkSourceRange(primitiveType, "@NonEmpty(0) int", contents);
-		ExtraDimension extraDimension = arrayType.getDimensionAt(1);
-		checkSourceRange(extraDimension, "@NonNull(value1 = 1) []", contents);
-		extraDimension = arrayType.getDimensionAt(0);
-		checkSourceRange(extraDimension, "@NonEmpty(1) [ ]", contents);
+		Dimension dimension = (Dimension) arrayType.dimensions().get(0);
+		checkSourceRange(dimension, "@NonNull(value1 = 1) []", contents);
+		dimension = (Dimension) arrayType.dimensions().get(1);
+		checkSourceRange(dimension, "@NonEmpty(1) [ ]", contents);
 		
 		field = (FieldDeclaration) type.bodyDeclarations().get(count++);
 		checkSourceRange(field, "@Annot int @Annot1 [] a1 @Annot2 @Annot3 @NonNull (value = int[].class, value1 = 0)[/* [] */ ] @Annot3 @Annot2 [] @Annot4 [];", contents);
 		arrayType = (ArrayType) field.getType();
 		checkSourceRange(arrayType, "int @Annot1 []", contents);
 		fragment = (VariableDeclarationFragment) field.fragments().get(0);
-		extraDimension = (ExtraDimension) fragment.extraDimensions().get(0);
-		checkSourceRange(extraDimension, "@Annot2 @Annot3 @NonNull (value = int[].class, value1 = 0)[/* [] */ ]", contents);
-		extraDimension = (ExtraDimension) fragment.extraDimensions().get(1);
-		checkSourceRange(extraDimension, "@Annot3 @Annot2 []", contents);
+		dimension = (Dimension) fragment.extraDimensions().get(0);
+		checkSourceRange(dimension, "@Annot2 @Annot3 @NonNull (value = int[].class, value1 = 0)[/* [] */ ]", contents);
+		dimension = (Dimension) fragment.extraDimensions().get(1);
+		checkSourceRange(dimension, "@Annot3 @Annot2 []", contents);
 		
 		field = (FieldDeclaration) type.bodyDeclarations().get(count++);
 		checkSourceRange(field, "int[] xxx[];", contents);
@@ -2996,10 +3047,10 @@
 		checkSourceRange(arrayType, "@TakeType(int[][].class) int @TakeType(float.class) [] @TakeType(double.class) []", contents);
 		checkSourceRange(arrayType.getElementType(), "@TakeType(int[][].class) int", contents);
 		assertTrue(arrayType.getElementType().isPrimitiveType());
-		extraDimension = arrayType.getDimensionAt(1);
-		checkSourceRange(extraDimension, "@TakeType(float.class) []", contents);
-		extraDimension = arrayType.getDimensionAt(0);
-		Annotation annotation = (Annotation) extraDimension.annotations().get(0);
+		dimension = (Dimension) arrayType.dimensions().get(0);
+		checkSourceRange(dimension, "@TakeType(float.class) []", contents);
+		dimension = (Dimension) arrayType.dimensions().get(1);
+		Annotation annotation = (Annotation) dimension.annotations().get(0);
 		assertTrue(annotation.isSingleMemberAnnotation());
 		singleMemberAnnotation = (SingleMemberAnnotation) annotation;
 		typeLiteral = (TypeLiteral) singleMemberAnnotation.getValue();
@@ -3021,9 +3072,9 @@
 		assertTrue(arrayType.getDimensions() == 1);
 		
 		MethodDeclaration method = (MethodDeclaration) type.bodyDeclarations().get(count++);
-		extraDimension = (ExtraDimension) method.extraDimensions().get(0);
-		checkSourceRange(extraDimension, "@TakeType(int[].class) []", contents);
-		singleMemberAnnotation = (SingleMemberAnnotation) extraDimension.annotations().get(0);
+		dimension = (Dimension) method.extraDimensions().get(0);
+		checkSourceRange(dimension, "@TakeType(int[].class) []", contents);
+		singleMemberAnnotation = (SingleMemberAnnotation) dimension.annotations().get(0);
 		typeLiteral = (TypeLiteral) singleMemberAnnotation.getValue();
 		arrayType = (ArrayType) typeLiteral.getType();
 		assertTrue(arrayType.getElementType().isPrimitiveType());
@@ -3038,13 +3089,13 @@
 		ForStatement forStatement = (ForStatement) method.getBody().statements().get(1);
 		VariableDeclarationExpression variableDeclarationExpression = (VariableDeclarationExpression) forStatement.initializers().get(0);
 		fragment = (VariableDeclarationFragment) variableDeclarationExpression.fragments().get(0);
-		extraDimension = (ExtraDimension) fragment.extraDimensions().get(0);
-		checkSourceRange(extraDimension, "@TakeType(int[].class) []", contents);
+		dimension = (Dimension) fragment.extraDimensions().get(0);
+		checkSourceRange(dimension, "@TakeType(int[].class) []", contents);
 		forStatement = (ForStatement) method.getBody().statements().get(1);
 		variableDeclarationExpression = (VariableDeclarationExpression) forStatement.initializers().get(0);
 		fragment = (VariableDeclarationFragment) variableDeclarationExpression.fragments().get(0);
-		extraDimension = (ExtraDimension) fragment.extraDimensions().get(0);
-		checkSourceRange(extraDimension, "@TakeType(int[].class) []", contents);
+		dimension = (Dimension) fragment.extraDimensions().get(0);
+		checkSourceRange(dimension, "@TakeType(int[].class) []", contents);
 		
 		method = (MethodDeclaration) type.bodyDeclarations().get(count++);
 		singleVariableDeclaration = (SingleVariableDeclaration) method.parameters().get(0);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST8Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST8Test.java
index d4130e5..c28118c 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST8Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterAST8Test.java
@@ -2732,7 +2732,7 @@
 		fragment.setName(this.ast.newSimpleName("z"));//$NON-NLS-1$
 		fragment.setInitializer(this.ast.newNullLiteral());
 		fragment.extraDimensions().clear();
-		fragment.extraDimensions().add(this.ast.newExtraDimension());
+		fragment.extraDimensions().add(this.ast.newDimension());
 		statement.fragments().add(fragment);
 		fragment = this.ast.newVariableDeclarationFragment();
 		fragment.setName(this.ast.newSimpleName("i"));//$NON-NLS-1$
@@ -2741,8 +2741,8 @@
 		fragment = this.ast.newVariableDeclarationFragment();
 		fragment.setName(this.ast.newSimpleName("j"));//$NON-NLS-1$
 		fragment.extraDimensions().clear();
-		fragment.extraDimensions().add(this.ast.newExtraDimension());
-		fragment.extraDimensions().add(this.ast.newExtraDimension());
+		fragment.extraDimensions().add(this.ast.newDimension());
+		fragment.extraDimensions().add(this.ast.newDimension());
 		statement.fragments().add(fragment);
 		statement.setType(this.ast.newPrimitiveType(PrimitiveType.INT));
 		assertTrue("Both AST trees should be identical", statement.subtreeMatch(new ASTMatcher(), node));		//$NON-NLS-1$
@@ -2775,7 +2775,7 @@
 		fragment.setName(this.ast.newSimpleName("z"));//$NON-NLS-1$
 		fragment.setInitializer(this.ast.newNullLiteral());
 		fragment.extraDimensions().clear();
-		fragment.extraDimensions().add(this.ast.newExtraDimension());
+		fragment.extraDimensions().add(this.ast.newDimension());
 		statement.fragments().add(fragment);
 		fragment = this.ast.newVariableDeclarationFragment();
 		fragment.setName(this.ast.newSimpleName("i"));//$NON-NLS-1$
@@ -2784,8 +2784,8 @@
 		fragment = this.ast.newVariableDeclarationFragment();
 		fragment.setName(this.ast.newSimpleName("j"));//$NON-NLS-1$
 		fragment.extraDimensions().clear();
-		fragment.extraDimensions().add(this.ast.newExtraDimension());
-		fragment.extraDimensions().add(this.ast.newExtraDimension());
+		fragment.extraDimensions().add(this.ast.newDimension());
+		fragment.extraDimensions().add(this.ast.newDimension());
 		statement.fragments().add(fragment);
 		statement.setType(this.ast.newArrayType(this.ast.newPrimitiveType(PrimitiveType.INT), 1));
 		assertTrue("Both AST trees should be identical", statement.subtreeMatch(new ASTMatcher(), node));		//$NON-NLS-1$
@@ -2812,7 +2812,7 @@
 		variableDeclarationFragment.setName(this.ast.newSimpleName("tab")); //$NON-NLS-1$
 		variableDeclarationFragment.setInitializer(this.ast.newNullLiteral());//$NON-NLS-1$
 		variableDeclarationFragment.extraDimensions().clear();
-		variableDeclarationFragment.extraDimensions().add(this.ast.newExtraDimension());
+		variableDeclarationFragment.extraDimensions().add(this.ast.newDimension());
 		VariableDeclarationExpression variableDeclarationExpression = this.ast.newVariableDeclarationExpression(variableDeclarationFragment);
 		variableDeclarationExpression.setType(this.ast.newArrayType(this.ast.newSimpleType(this.ast.newSimpleName("String")), 1));//$NON-NLS-1$
 		forStatement.initializers().add(variableDeclarationExpression);
@@ -2841,7 +2841,7 @@
 		variableDeclarationFragment.setName(this.ast.newSimpleName("tab")); //$NON-NLS-1$
 		variableDeclarationFragment.setInitializer(this.ast.newNullLiteral());//$NON-NLS-1$
 		variableDeclarationFragment.extraDimensions().clear();
-		variableDeclarationFragment.extraDimensions().add(this.ast.newExtraDimension());
+		variableDeclarationFragment.extraDimensions().add(this.ast.newDimension());
 		VariableDeclarationExpression variableDeclarationExpression = this.ast.newVariableDeclarationExpression(variableDeclarationFragment);
 		variableDeclarationExpression.setType(this.ast.newSimpleType(this.ast.newSimpleName("String")));//$NON-NLS-1$
 		forStatement.initializers().add(variableDeclarationExpression);
@@ -2870,7 +2870,7 @@
 		variableDeclarationFragment.setName(this.ast.newSimpleName("tab")); //$NON-NLS-1$
 		variableDeclarationFragment.setInitializer(this.ast.newNullLiteral());//$NON-NLS-1$
 		variableDeclarationFragment.extraDimensions().clear();
-		variableDeclarationFragment.extraDimensions().add(this.ast.newExtraDimension());
+		variableDeclarationFragment.extraDimensions().add(this.ast.newDimension());
 		VariableDeclarationExpression variableDeclarationExpression = this.ast.newVariableDeclarationExpression(variableDeclarationFragment);
 		variableDeclarationExpression.setType(this.ast.newSimpleType(this.ast.newSimpleName("String")));//$NON-NLS-1$
 		forStatement.initializers().add(variableDeclarationExpression);
@@ -2928,7 +2928,7 @@
 		fragment = this.ast.newVariableDeclarationFragment();
 		fragment.setName(this.ast.newSimpleName("y"));//$NON-NLS-1$
 		fragment.extraDimensions().clear();
-		fragment.extraDimensions().add(this.ast.newExtraDimension());
+		fragment.extraDimensions().add(this.ast.newDimension());
 		fragment.setInitializer(this.ast.newNullLiteral());
 		fieldDeclaration.fragments().add(fragment);
 		fragment = this.ast.newVariableDeclarationFragment();
@@ -2938,8 +2938,8 @@
 		fragment = this.ast.newVariableDeclarationFragment();
 		fragment.setName(this.ast.newSimpleName("j"));//$NON-NLS-1$
 		fragment.extraDimensions().clear();
-		fragment.extraDimensions().add(this.ast.newExtraDimension());
-		fragment.extraDimensions().add(this.ast.newExtraDimension());
+		fragment.extraDimensions().add(this.ast.newDimension());
+		fragment.extraDimensions().add(this.ast.newDimension());
 		fieldDeclaration.fragments().add(fragment);
 		assertTrue("Both AST trees should be identical", fieldDeclaration.subtreeMatch(new ASTMatcher(), node));		//$NON-NLS-1$
 		checkSourceRange(node, "public int x= 10, y[] = null, i, j[][];", source); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocFlattener.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocFlattener.java
index 3f396b9..83d6ec4 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocFlattener.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocFlattener.java
@@ -69,7 +69,7 @@
 	} else {
 		node.getElementType().accept(this);
 		for (int i = 0;  i < node.getDimensions(); ++i) {
-			((ExtraDimension) node.dimensions().get(i)).accept(this);
+			((Dimension) node.dimensions().get(i)).accept(this);
 		}
 	}
 	return false;
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTMatcherTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTMatcherTest.java
index aedf076..c86504d 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTMatcherTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTMatcherTest.java
@@ -558,7 +558,7 @@
 		public boolean match(WildcardType node, Object other) {
 			return standardBody(node, other, this.superMatch ? super.match(node, other) : false);
 		}
-		public boolean match(ExtraDimension node, Object other) {
+		public boolean match(Dimension node, Object other) {
 			return standardBody(node, other, this.superMatch ? super.match(node, other) : false);
 		}
 		public boolean match(InstanceofExpression node, Object other) {
@@ -1615,12 +1615,12 @@
 		}
 		VariableDeclarationFragment x1 = this.ast.newVariableDeclarationFragment();
 		x1.setName(this.N1);
-		ExtraDimension x2 = this.ast.newExtraDimension();
+		Dimension x2 = this.ast.newDimension();
 		Annotation Annot = this.ast.newMarkerAnnotation();
 		Annot.setTypeName(this.ast.newSimpleName("NewAnnot1"));
 		x2.annotations().add(Annot);
 		x1.extraDimensions().add(x2);
-		x2 = this.ast.newExtraDimension();
+		x2 = this.ast.newDimension();
 		Annot = this.ast.newMarkerAnnotation();
 		Annot.setTypeName(this.ast.newSimpleName("NewAnnot2"));
 		x2.annotations().add(Annot);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTTest.java
index 3a5a4ac..a4647cb 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTTest.java
@@ -3225,7 +3225,7 @@
 		if (this.ast.apiLevel() < AST.JLS8) {
 			x.setExtraDimensions(1);
 		} else {
-			x.extraDimensions().add(this.ast.newExtraDimension());
+			x.extraDimensions().add(this.ast.newDimension());
 		}
 		assertTrue(this.ast.modificationCount() > previousCount);
 		assertTrue(x.getExtraDimensions() == 1);
@@ -3336,9 +3336,9 @@
 
 		if (this.ast.apiLevel() >= AST.JLS8) {
 			genericPropertyListTest(x, x.extraDimensions(),
-					new Property("ExtraDimensions", true, ExtraDimension.class) { //$NON-NLS-1$
+					new Property("ExtraDimensions", true, Dimension.class) { //$NON-NLS-1$
 						public ASTNode sample(AST targetAst, boolean parented) {
-							ExtraDimension result = targetAst.newExtraDimension();
+							Dimension result = targetAst.newDimension();
 							if (parented) {
 								targetAst.newMethodDeclaration().extraDimensions().add(result);
 							}
@@ -3395,7 +3395,7 @@
 		if (this.ast.apiLevel() < AST.JLS8) {
 			setExtraDimensions(x, 1);
 		} else {
-			x.extraDimensions().add(this.ast.newExtraDimension());
+			x.extraDimensions().add(this.ast.newDimension());
 		}
 		assertTrue(this.ast.modificationCount() > previousCount);
 		assertTrue(x.getExtraDimensions() == 1);
@@ -3437,9 +3437,9 @@
 
 		if (this.ast.apiLevel() >= AST.JLS8) {
 			genericPropertyListTest(x, x.extraDimensions(),
-					new Property("ExtraDimensions", true, ExtraDimension.class) { //$NON-NLS-1$
+					new Property("ExtraDimensions", true, Dimension.class) { //$NON-NLS-1$
 						public ASTNode sample(AST targetAst, boolean parented) {
-							ExtraDimension result = targetAst.newExtraDimension();
+							Dimension result = targetAst.newDimension();
 							if (parented) {
 								targetAst.newMethodDeclaration().extraDimensions().add(result);
 							}
@@ -3557,7 +3557,7 @@
 		if (this.ast.apiLevel() < AST.JLS8) {
 			x.setExtraDimensions(1);
 		} else {
-			x.extraDimensions().add(this.ast.newExtraDimension());
+			x.extraDimensions().add(this.ast.newDimension());
 		}
 		assertTrue(this.ast.modificationCount() > previousCount);
 		assertTrue(x.getExtraDimensions() == 1);
@@ -3643,9 +3643,9 @@
 
 		if (this.ast.apiLevel() >= AST.JLS8) {
 			genericPropertyListTest(x, x.extraDimensions(),
-					new Property("ExtraDimensions", true, ExtraDimension.class) { //$NON-NLS-1$
+					new Property("ExtraDimensions", true, Dimension.class) { //$NON-NLS-1$
 						public ASTNode sample(AST targetAst, boolean parented) {
-							ExtraDimension result = targetAst.newExtraDimension();
+							Dimension result = targetAst.newDimension();
 							if (parented) {
 								targetAst.newMethodDeclaration().extraDimensions().add(result);
 							}
@@ -8837,7 +8837,7 @@
 			ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION,
 			ASTNode.MODIFIER,
 			ASTNode.UNION_TYPE,
-			ASTNode.EXTRA_DIMENSION,
+			ASTNode.DIMENSION,
 			ASTNode.LAMBDA_EXPRESSION,
 			ASTNode.INTERSECTION_TYPE,
 			ASTNode.PACKAGE_QUALIFIED_TYPE,
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTVisitorTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTVisitorTest.java
index 076d46a..59d8b23 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTVisitorTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTVisitorTest.java
@@ -1094,11 +1094,11 @@
 			ASTVisitorTest.this.b.append("MOD)"); //$NON-NLS-1$
 		}
 
-		public boolean visit(ExtraDimension node) {
+		public boolean visit(Dimension node) {
 			ASTVisitorTest.this.b.append("(@ED"); //$NON-NLS-1$
 			return isVisitingChildren();
 		}
-		public void endVisit(ExtraDimension node) {
+		public void endVisit(Dimension node) {
 			ASTVisitorTest.this.b.append("@ED)"); //$NON-NLS-1$
 		}
 		
@@ -1548,7 +1548,7 @@
 		if (this.ast.apiLevel() < AST.JLS8) {
 			return;
 		}
-		ExtraDimension x1 = this.ast.newExtraDimension();
+		Dimension x1 = this.ast.newDimension();
 		x1.annotations().add(this.ANO1);
 		x1.annotations().add(this.ANO2);
 		TestVisitor v1 = new TestVisitor();
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/AbstractASTTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/AbstractASTTests.java
index cd3cecc..7ef4438 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/AbstractASTTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/AbstractASTTests.java
@@ -60,6 +60,7 @@
 import org.eclipse.jdt.core.tests.util.Util;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.core.dom.SourceRangeVerifier;
 
 public class AbstractASTTests extends ModifyingResourceTests implements DefaultMarkedNodeLabelProviderOptions {
 
@@ -88,6 +89,13 @@
 		super(name);
 	}
 
+	public void setUpSuite() throws Exception {
+		super.setUpSuite();
+		
+		SourceRangeVerifier.DEBUG = true;
+		SourceRangeVerifier.DEBUG_THROW = true;
+	}
+	
 	/*
 	 * Removes the *start* and *end* markers from the given source
 	 * and remembers the positions.
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java
index 076cb30..cde2cc4 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java
@@ -164,7 +164,7 @@
 		StringBuffer buffer = new StringBuffer();
 		Iterator iter = dimensions.iterator();
 		while(iter.hasNext()) {
-			ExtraDimension dim = (ExtraDimension) iter.next();
+			Dimension dim = (Dimension) iter.next();
 			buffer.append(convertAnnotationsList(dim.annotations()));
 			if (iter.hasNext()) {
 				buffer.append("[] ");
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/SampleASTs.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/SampleASTs.java
index 7536623..a2e84df 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/SampleASTs.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/SampleASTs.java
@@ -93,7 +93,7 @@
 			md.setReturnType2(pmt);
 		}
 		if (target.apiLevel() >= AST.JLS8) {
-			ExtraDimension ed = target.newExtraDimension();
+			Dimension ed = target.newDimension();
 			md.extraDimensions().add(ed);
 		}
 
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeAnnotationsConverterTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeAnnotationsConverterTest.java
index c7efeb0..f8015cc 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeAnnotationsConverterTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeAnnotationsConverterTest.java
@@ -110,7 +110,7 @@
 		assertASTNodeEquals(expectedOutput, node);
 	}
 	// Test ParameterizedQualifiedReference
-	public void test0003() throws JavaModelException {
+	public void _test0003() throws JavaModelException {
 		String contents =
 			"public class X<T> {\n" +
 		    "    class Y<R> {\n" +
@@ -139,7 +139,7 @@
 		assertASTNodeEquals(expectedOutput, node);
 	}
 	// Test ParameterizedQualifiedReference with arrays.
-	public void test0004() throws JavaModelException {
+	public void _test0004() throws JavaModelException {
 		String contents =
 			"public class X<T> {\n" +
 		    "    class Y<R> {\n" +
@@ -168,7 +168,7 @@
 		assertASTNodeEquals(expectedOutput, node);
 	}
 	// Test ParameterizedQualifiedReference with arrays.
-	public void test0005() throws JavaModelException {
+	public void _test0005() throws JavaModelException {
 		String contents =
 			"public class X<T> {\n" +
 		    "    class Y<R> {\n" +
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeBindingTests308.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeBindingTests308.java
index f31fe26..25f3f14 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeBindingTests308.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/TypeBindingTests308.java
@@ -1623,5 +1623,142 @@
 		ITypeBinding binding = field.getType().resolveBinding();
 		assertEquals("Wrong Type", "@T X", (binding = binding.getEnclosingType()).toString());
 		assertEquals("Wrong Type", "@T X.Y", (binding = binding.getDeclaredTypes()[0]).toString());
+	}
+	public void testAnnotatedTypeIdentity() throws CoreException, IOException {
+		String contents = 
+				"import java.lang.annotation.ElementType;\n" +
+				"import java.lang.annotation.Target;\n" +
+				"import java.util.List;\n" +
+				"@Target(ElementType.TYPE_USE)\n" +
+				"@interface T {\n" +
+				"}\n" +
+				"public class X {\n" +
+				"    @T List<@T String> ls = (@T List<@T String>) null;\n" +
+				"}\n";
+		this.workingCopy = getWorkingCopy("/Converter18/src/X.java", true);
+		ASTNode node = buildAST(contents, this.workingCopy);
+		assertEquals("Not a compilation unit", ASTNode.COMPILATION_UNIT, node.getNodeType());
+		CompilationUnit compilationUnit = (CompilationUnit) node;
+		assertProblemsSize(compilationUnit, 0);
+		List types = compilationUnit.types();
+		assertEquals("Incorrect no of types", 2, types.size());
+		TypeDeclaration typeDecl = (TypeDeclaration) types.get(1);
+		FieldDeclaration[] fields = typeDecl.getFields();
+		assertEquals("Incorrect no of fields", 1, fields.length);
+		FieldDeclaration field = fields[0];
+		ITypeBinding binding = field.getType().resolveBinding();
+		VariableDeclarationFragment fragment = (VariableDeclarationFragment) field.fragments().get(0);
+		CastExpression cast = (CastExpression) fragment.getInitializer();
+		ITypeBinding binding2 = cast.resolveTypeBinding();
+		assertEquals("Wrong Type", "@T List<@T String>", binding.toString());
+		assertSame("not Equal", binding, binding2);
+	}
+	public void testAnnotatedTypeIdentity2() throws CoreException, IOException {
+		String jarName = "TypeBindingTests308.jar";
+		String srcName = "TypeBindingTests308_src.zip";
+		final IJavaProject javaProject = getJavaProject("Converter18");
+		try {
+			String[] pathAndContents = new String[] {
+				"Outer.java",
+				"public class Outer  {\n" +
+				"	Outer @T [] f @T [];\n" +
+				"}\n" +
+				"@java.lang.annotation.Target (java.lang.annotation.ElementType.TYPE_USE)\n" +
+				"@interface T {\n" +
+				"	int value() default 10;\n" +
+				"}\n"
+			};
+			
+			HashMap libraryOptions = new HashMap(javaProject.getOptions(true));
+			libraryOptions.put(CompilerOptions.OPTION_Store_Annotations, CompilerOptions.ENABLED);
+			addLibrary(javaProject, jarName, srcName, pathAndContents, JavaCore.VERSION_1_8, libraryOptions);
+			
+			String contents = 
+					"public class X {\n" +
+					"	 Outer @T [] f @T [];\n" +
+					"    void foo(Outer o) {\n" +
+					"        o.f = this.f;\n" +
+					"    }\n" +
+					"}";
+			
+			this.workingCopy = getWorkingCopy("/Converter18/src/X.java", true);
+			ASTNode node = buildAST(contents, this.workingCopy);
+			assertEquals("Not a compilation unit", ASTNode.COMPILATION_UNIT, node.getNodeType());
+			CompilationUnit compilationUnit = (CompilationUnit) node;
+			assertProblemsSize(compilationUnit, 0);
+			List types = compilationUnit.types();
+			assertEquals("Incorrect no of types", 1, types.size());
+			TypeDeclaration typeDecl = (TypeDeclaration) types.get(0);
+			
+			MethodDeclaration[] methods = typeDecl.getMethods();
+			assertEquals("Incorrect no of methods", 1, methods.length);
+			MethodDeclaration method = methods[0];
+			Block body = method.getBody();
+			ExpressionStatement stmt = (ExpressionStatement) body.statements().get(0);
+			Assignment assignment = (Assignment) stmt.getExpression();
+			Expression left = assignment.getLeftHandSide();
+			ITypeBinding type = left.resolveTypeBinding();
+			Expression right = assignment.getRightHandSide();
+			ITypeBinding type2 = right.resolveTypeBinding();
+			assertEquals("Wrong type", "Outer @T [] @T []", type.toString());
+			assertSame ("Should be same", type, type2);
+		} finally {
+			removeLibrary(javaProject, jarName, srcName);
+		}
+	}
+	public void testAnnotatedTypeIdentity3() throws CoreException, IOException {
+		String jarName = "TypeBindingTests308.jar";
+		String srcName = "TypeBindingTests308_src.zip";
+		final IJavaProject javaProject = getJavaProject("Converter18");
+		try {
+			String[] pathAndContents = new String[] {
+				"Outer.java",
+				"import java.util.List;\n" +
+				"public class Outer  {\n" +
+				"	@T List<@T String> ls;\n" +
+				"}\n" +
+				"@java.lang.annotation.Target (java.lang.annotation.ElementType.TYPE_USE)\n" +
+				"@interface T {\n" +
+				"	int value() default 10;\n" +
+				"}\n"
+			};
+			
+			HashMap libraryOptions = new HashMap(javaProject.getOptions(true));
+			libraryOptions.put(CompilerOptions.OPTION_Store_Annotations, CompilerOptions.ENABLED);
+			addLibrary(javaProject, jarName, srcName, pathAndContents, JavaCore.VERSION_1_8, libraryOptions);
+			
+			String contents = 
+					"import java.util.List;\n" +
+					"public class X {\n" +
+					"	@T List<@T String> ls;\n" +
+					"    void foo(Outer o) {\n" +
+					"        o.ls = this.ls;\n" +
+					"    }\n" +
+					"}";
+			
+			this.workingCopy = getWorkingCopy("/Converter18/src/X.java", true);
+			ASTNode node = buildAST(contents, this.workingCopy);
+			assertEquals("Not a compilation unit", ASTNode.COMPILATION_UNIT, node.getNodeType());
+			CompilationUnit compilationUnit = (CompilationUnit) node;
+			assertProblemsSize(compilationUnit, 0);
+			List types = compilationUnit.types();
+			assertEquals("Incorrect no of types", 1, types.size());
+			TypeDeclaration typeDecl = (TypeDeclaration) types.get(0);
+			
+			MethodDeclaration[] methods = typeDecl.getMethods();
+			assertEquals("Incorrect no of methods", 1, methods.length);
+			MethodDeclaration method = methods[0];
+			Block body = method.getBody();
+			ExpressionStatement stmt = (ExpressionStatement) body.statements().get(0);
+			Assignment assignment = (Assignment) stmt.getExpression();
+			Expression left = assignment.getLeftHandSide();
+			ITypeBinding type = left.resolveTypeBinding();
+			Expression right = assignment.getRightHandSide();
+			ITypeBinding type2 = right.resolveTypeBinding();
+			assertEquals("Wrong type", "@T List<@T String>", type.toString());
+			assertSame ("Should be same", type, type2);
+		} finally {
+			removeLibrary(javaProject, jarName, srcName);
+		}
 	}	
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingExpressionsTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingExpressionsTest.java
index 144aebc..ce7b0a6 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingExpressionsTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingExpressionsTest.java
@@ -263,19 +263,19 @@
 			memberValuePair.setName(ast.newSimpleName("v"));
 			memberValuePair.setValue(ast.newNumberLiteral("99"));
 			annotationC.values().add(memberValuePair);
-			ExtraDimension dim0 = arrayType.getDimensionAt(0);
+			Dimension dim0 = (Dimension) arrayType.dimensions().get(0);
 			dim0.annotations().add(annotationC);
 			
 			SingleMemberAnnotation annotationB= ast.newSingleMemberAnnotation();
 			annotationB.setTypeName(ast.newSimpleName("B"));
 			annotationB.setValue(ast.newNumberLiteral("0"));
-			ExtraDimension dim1 = ast.newExtraDimension();
+			Dimension dim1 = ast.newDimension();
 			dim1.annotations().add(annotationB);
 			arrayType.dimensions().add(0, dim1);
 			
 			MarkerAnnotation annotationA= ast.newMarkerAnnotation();
 			annotationA.setTypeName(ast.newSimpleName("A"));
-			ExtraDimension dim2 = ast.newExtraDimension();
+			Dimension dim2 = ast.newDimension();
 			dim2.annotations().add(annotationA);
 			arrayType.dimensions().add(0, dim2);
 			
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingMethodDeclTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingMethodDeclTest.java
index 55bd874..89ed05d 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingMethodDeclTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingMethodDeclTest.java
@@ -111,7 +111,7 @@
 				listRewrite.remove(extraDimension, null);
 			}
 			for (int i= 0; i < extraDimensions; i++) {
-				listRewrite.insertFirst(methodDecl.getAST().newExtraDimension(), null);
+				listRewrite.insertFirst(methodDecl.getAST().newDimension(), null);
 			}
 		}
 	}
@@ -344,7 +344,7 @@
 
 
 
-	public void testMethodReturnTypeChanges_only_2() throws Exception {
+	public void _testMethodReturnTypeChanges_only_2() throws Exception {
 		IPackageFragment pack1= this.sourceFolder.createPackageFragment("test1", false, null);
 		StringBuffer buf= new StringBuffer();
 		buf.append("package test1;\n");
@@ -447,7 +447,7 @@
 
 	}
 
-	public void testMethodReturnTypeChanges2_only_2() throws Exception {
+	public void _testMethodReturnTypeChanges2_only_2() throws Exception {
 		IPackageFragment pack1= this.sourceFolder.createPackageFragment("test1", false, null);
 		StringBuffer buf= new StringBuffer();
 		buf.append("package test1;\n");
@@ -3152,13 +3152,13 @@
 			MethodDeclaration methodDecl= findMethodDeclaration(type, "foo1");
 
 			ListRewrite listRewrite= rewrite.getListRewrite(methodDecl, MethodDeclaration.EXTRA_DIMENSIONS2_PROPERTY);
-			ExtraDimension dim= ast.newExtraDimension();
+			Dimension dim= ast.newDimension();
 			MarkerAnnotation markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot1"));
 			dim.annotations().add(markerAnnotation);
 			listRewrite.insertAt(dim, 1, null);
 
-			dim= ast.newExtraDimension();
+			dim= ast.newDimension();
 			markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot2"));
 			dim.annotations().add(markerAnnotation);
@@ -3171,7 +3171,7 @@
 			MethodDeclaration methodDecl= findMethodDeclaration(type, "foo2");
 			ListRewrite listRewrite= rewrite.getListRewrite(methodDecl, MethodDeclaration.EXTRA_DIMENSIONS2_PROPERTY);
 
-			ExtraDimension dim= ast.newExtraDimension();
+			Dimension dim= ast.newDimension();
 			MarkerAnnotation markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot1"));
 			dim.annotations().add(markerAnnotation);
@@ -3185,7 +3185,7 @@
 			MethodDeclaration methodDecl= findMethodDeclaration(type, "foo3");
 			ListRewrite listRewrite= rewrite.getListRewrite(methodDecl, MethodDeclaration.EXTRA_DIMENSIONS2_PROPERTY);
 
-			ExtraDimension dim= ast.newExtraDimension();
+			Dimension dim= ast.newDimension();
 			MarkerAnnotation markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot1"));
 			dim.annotations().add(markerAnnotation);
@@ -3197,15 +3197,15 @@
 		}
 		{
 			MethodDeclaration methodDecl= findMethodDeclaration(type, "foo4");
-			ExtraDimension dim= (ExtraDimension) methodDecl.extraDimensions().get(0);
-			ListRewrite listRewrite= rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			Dimension dim= (Dimension) methodDecl.extraDimensions().get(0);
+			ListRewrite listRewrite= rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 
 			MarkerAnnotation markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot2"));
 			listRewrite.insertAt(markerAnnotation, 0, null);
 
-			dim= (ExtraDimension) methodDecl.extraDimensions().get(1);
-			listRewrite= rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			dim= (Dimension) methodDecl.extraDimensions().get(1);
+			listRewrite= rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 
 			markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot1"));
@@ -3213,33 +3213,33 @@
 		}
 		{
 			MethodDeclaration methodDecl= findMethodDeclaration(type, "foo5");
-			ExtraDimension dim= (ExtraDimension) methodDecl.extraDimensions().get(0);
+			Dimension dim= (Dimension) methodDecl.extraDimensions().get(0);
 			Annotation annot= (Annotation) dim.annotations().get(0);
-			ListRewrite listRewrite= rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			ListRewrite listRewrite= rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			listRewrite.remove(annot, null);
 
-			dim= (ExtraDimension) methodDecl.extraDimensions().get(1);
-			listRewrite= rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			dim= (Dimension) methodDecl.extraDimensions().get(1);
+			listRewrite= rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			listRewrite.insertAt(annot, 1, null);
 		}
 		{
 			MethodDeclaration methodDecl= findMethodDeclaration(type, "foo6");
-			ExtraDimension dim= (ExtraDimension) methodDecl.extraDimensions().get(0);
+			Dimension dim= (Dimension) methodDecl.extraDimensions().get(0);
 			Annotation annot= (Annotation) dim.annotations().get(0);
-			ListRewrite listRewrite= rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			ListRewrite listRewrite= rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			listRewrite.remove(annot, null);
 
-			dim= (ExtraDimension) methodDecl.extraDimensions().get(1);
+			dim= (Dimension) methodDecl.extraDimensions().get(1);
 			annot= (Annotation) dim.annotations().get(0);
-			listRewrite= rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			listRewrite= rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			listRewrite.remove(annot, null);
 		}
 		{
 			MethodDeclaration methodDecl= findMethodDeclaration(type, "foo7");
 			ListRewrite listRewrite= rewrite.getListRewrite(methodDecl, MethodDeclaration.EXTRA_DIMENSIONS2_PROPERTY);
-			ExtraDimension dim= (ExtraDimension) methodDecl.extraDimensions().get(0);
+			Dimension dim= (Dimension) methodDecl.extraDimensions().get(0);
 			listRewrite.remove(dim, null);
-			dim= (ExtraDimension) methodDecl.extraDimensions().get(1);
+			dim= (Dimension) methodDecl.extraDimensions().get(1);
 			listRewrite.remove(dim, null);
 		}
 
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingStatementsTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingStatementsTest.java
index eb8e53b..fe13150 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingStatementsTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingStatementsTest.java
@@ -40,7 +40,7 @@
 import org.eclipse.jdt.core.dom.DoStatement;
 import org.eclipse.jdt.core.dom.Expression;
 import org.eclipse.jdt.core.dom.ExpressionStatement;
-import org.eclipse.jdt.core.dom.ExtraDimension;
+import org.eclipse.jdt.core.dom.Dimension;
 import org.eclipse.jdt.core.dom.ForStatement;
 import org.eclipse.jdt.core.dom.IfStatement;
 import org.eclipse.jdt.core.dom.InfixExpression;
@@ -103,7 +103,7 @@
 			node.setExtraDimensions(dimensions);
 		} else {
 			while (dimensions > 0) {
-				node.extraDimensions().add(node.getAST().newExtraDimension());
+				node.extraDimensions().add(node.getAST().newDimension());
 			}
 		}
 	}
@@ -5942,15 +5942,15 @@
 			ArrayCreation creation = (ArrayCreation) fragment.getInitializer();
 
 			ListRewrite listRewrite= rewrite.getListRewrite(fragment, VariableDeclarationFragment.EXTRA_DIMENSIONS2_PROPERTY);
-			ExtraDimension dim= ast.newExtraDimension();
+			Dimension dim= ast.newDimension();
 			MarkerAnnotation markerAnnotation;
 			listRewrite.insertFirst(dim, null);
 
 			ArrayType creationType = creation.getType();
 			ArrayType newArrayType = (ArrayType) ASTNode.copySubtree(ast, creationType);
-			newArrayType.dimensions().add(ast.newExtraDimension());
+			newArrayType.dimensions().add(ast.newDimension());
 			
-			ExtraDimension dim0 = ast.newExtraDimension();
+			Dimension dim0 = ast.newDimension();
 			markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot3"));
 			dim0.annotations().add(markerAnnotation);
@@ -5981,18 +5981,18 @@
 			Expression exp = (Expression) expressions.get(1);
 			listRewrite.remove(exp, null);
 
-			ExtraDimension dim = creationType.getDimensionAt(2);
-			listRewrite = rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			Dimension dim = (Dimension) creationType.dimensions().get(0);
+			listRewrite = rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			MarkerAnnotation annotation = (MarkerAnnotation) dim.annotations().get(0);
 			listRewrite.remove(annotation, null);
 
-			dim = creationType.getDimensionAt(1);
-			listRewrite = rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			dim = (Dimension) creationType.dimensions().get(1);
+			listRewrite = rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			annotation = (MarkerAnnotation) dim.annotations().get(1);
 			listRewrite.remove(annotation, null);
 
-			dim = creationType.getDimensionAt(0);
-			listRewrite = rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			dim = (Dimension) creationType.dimensions().get(2);
+			listRewrite = rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			annotation = (MarkerAnnotation) dim.annotations().get(1);
 			listRewrite.remove(annotation, null);
 
@@ -6000,22 +6000,22 @@
 
 			creation = (ArrayCreation) fragment.getInitializer();
 			creationType = creation.getType();
-			dim = creationType.getDimensionAt(2);
-			listRewrite = rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			dim = (Dimension) creationType.dimensions().get(0);
+			listRewrite = rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			annotation = (MarkerAnnotation) dim.annotations().get(1);
 			listRewrite.remove(annotation, null);
 			annotation = (MarkerAnnotation) dim.annotations().get(0);
 			listRewrite.remove(annotation, null);
 
-			dim = creationType.getDimensionAt(1);
-			listRewrite = rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			dim = (Dimension) creationType.dimensions().get(1);
+			listRewrite = rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			annotation = (MarkerAnnotation) dim.annotations().get(1);
 			listRewrite.remove(annotation, null);
 			annotation = (MarkerAnnotation) dim.annotations().get(0);
 			listRewrite.remove(annotation, null);
 
-			dim = creationType.getDimensionAt(0);
-			listRewrite = rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			dim = (Dimension) creationType.dimensions().get(2);
+			listRewrite = rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			annotation = (MarkerAnnotation) dim.annotations().get(1);
 			listRewrite.remove(annotation, null);
 			annotation = (MarkerAnnotation) dim.annotations().get(0);
@@ -6090,8 +6090,8 @@
 			ArrayCreation creation = (ArrayCreation) fragment.getInitializer();
 
 			ArrayType arrayType = creation.getType();
-			ExtraDimension dim = arrayType.getDimensionAt(1);
-			ListRewrite listRewrite= rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			Dimension dim = (Dimension) arrayType.dimensions().get(1);
+			ListRewrite listRewrite= rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			listRewrite.remove((ASTNode)dim.annotations().get(0), null);
 			listRewrite.remove((ASTNode)dim.annotations().get(1), null);
 			rewrite.set(creation, ArrayCreation.TYPE_PROPERTY, arrayType, null);
@@ -6105,12 +6105,12 @@
 			assertEquals("Incorrect type", ASTNode.ARRAY_TYPE, type.getNodeType());
 			ArrayCreation creation = (ArrayCreation) fragment.getInitializer();
 			ArrayType creationType = creation.getType();
-			rewrite.remove(creationType.getDimensionAt(0), null);
+			rewrite.remove((ASTNode) creationType.dimensions().get(2), null);
 			fragment = (VariableDeclarationFragment) fragments.get(1);
 			creation = (ArrayCreation) fragment.getInitializer();
 			creationType = creation.getType();
 
-			rewrite.remove(creationType.getDimensionAt(0), null);
+			rewrite.remove((ASTNode) creationType.dimensions().get(2), null);
 		}
 		// Get new code
 		String preview= evaluateRewrite(cu, rewrite);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingTypeDeclTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingTypeDeclTest.java
index 4829a51..eacb130 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingTypeDeclTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingTypeDeclTest.java
@@ -37,7 +37,7 @@
 import org.eclipse.jdt.core.dom.EnumDeclaration;
 import org.eclipse.jdt.core.dom.Expression;
 import org.eclipse.jdt.core.dom.ExpressionStatement;
-import org.eclipse.jdt.core.dom.ExtraDimension;
+import org.eclipse.jdt.core.dom.Dimension;
 import org.eclipse.jdt.core.dom.FieldDeclaration;
 import org.eclipse.jdt.core.dom.ImportDeclaration;
 import org.eclipse.jdt.core.dom.MarkerAnnotation;
@@ -1767,7 +1767,7 @@
 			rewrite.replace(fragment.getName(), name, null);
 
 			ListRewrite listRewrite= rewrite.getListRewrite(fragment, VariableDeclarationFragment.EXTRA_DIMENSIONS2_PROPERTY);
-			ExtraDimension dim= ast.newExtraDimension();
+			Dimension dim= ast.newDimension();
 			MarkerAnnotation markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot1"));
 			dim.annotations().add(markerAnnotation);
@@ -1789,7 +1789,7 @@
 			rewrite.remove(fragment.getInitializer(), null);
 
 			ListRewrite listRewrite= rewrite.getListRewrite(fragment, VariableDeclarationFragment.EXTRA_DIMENSIONS2_PROPERTY);
-			ExtraDimension dim= ast.newExtraDimension();
+			Dimension dim= ast.newDimension();
 			MarkerAnnotation markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot1"));
 			dim.annotations().add(markerAnnotation);
@@ -1807,7 +1807,7 @@
 
 			ListRewrite listRewrite= rewrite.getListRewrite(fragment, VariableDeclarationFragment.EXTRA_DIMENSIONS2_PROPERTY);
 
-			ExtraDimension dim= ast.newExtraDimension();
+			Dimension dim= ast.newDimension();
 			MarkerAnnotation markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot1"));
 			dim.annotations().add(markerAnnotation);
@@ -1820,20 +1820,20 @@
 		{ // remove one dimension and add annotations for the rest of the dimensions
 			VariableDeclarationFragment fragment= (VariableDeclarationFragment) fragments.get(4);
 
-			ExtraDimension dim= (ExtraDimension) fragment.extraDimensions().get(1);
-			ListRewrite listRewrite= rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			Dimension dim= (Dimension) fragment.extraDimensions().get(1);
+			ListRewrite listRewrite= rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			MarkerAnnotation markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot1"));
 			listRewrite.insertAt(markerAnnotation, 0, null);
 
-			dim= (ExtraDimension) fragment.extraDimensions().get(2);
+			dim= (Dimension) fragment.extraDimensions().get(2);
 			markerAnnotation= ast.newMarkerAnnotation();
 			markerAnnotation.setTypeName(ast.newSimpleName("Annot2"));
-			listRewrite= rewrite.getListRewrite(dim, ExtraDimension.ANNOTATIONS_PROPERTY);
+			listRewrite= rewrite.getListRewrite(dim, Dimension.ANNOTATIONS_PROPERTY);
 			listRewrite.insertAt(markerAnnotation, 0, null);
 
 			listRewrite= rewrite.getListRewrite(fragment, VariableDeclarationFragment.EXTRA_DIMENSIONS2_PROPERTY);
-			listRewrite.remove((ExtraDimension) fragment.extraDimensions().get(0), null);
+			listRewrite.remove((Dimension) fragment.extraDimensions().get(0), null);
 		}
 		{ // remove a fragment
 			ListRewrite listRewrite= rewrite.getListRewrite(variableDeclStatement, VariableDeclarationStatement.FRAGMENTS_PROPERTY);
@@ -1887,7 +1887,7 @@
 		{ // add modifier, move extra dimensions from one variable to another
 			SingleVariableDeclaration decl= (SingleVariableDeclaration) arguments.get(0);
 			SingleVariableDeclaration decl2= (SingleVariableDeclaration) arguments.get(1);
-			ExtraDimension dim= (ExtraDimension) decl2.extraDimensions().get(0);
+			Dimension dim= (Dimension) decl2.extraDimensions().get(0);
 			ListRewrite listRewrite= rewrite.getListRewrite(decl, SingleVariableDeclaration.MODIFIERS2_PROPERTY);
 			listRewrite.insertFirst(ast.newModifier(Modifier.ModifierKeyword.FINAL_KEYWORD), null);
 
@@ -1898,21 +1898,21 @@
 		}
 		{ // move annotations from one dim to another
 			SingleVariableDeclaration decl= (SingleVariableDeclaration) arguments.get(2);
-			ExtraDimension dim1= (ExtraDimension) decl.extraDimensions().get(0);
-			ExtraDimension dim2= (ExtraDimension) decl.extraDimensions().get(1);
+			Dimension dim1= (Dimension) decl.extraDimensions().get(0);
+			Dimension dim2= (Dimension) decl.extraDimensions().get(1);
 			Annotation annot1= (Annotation) dim1.annotations().get(0);
 			Annotation annot2= (Annotation) dim2.annotations().get(0);
 
-			ListRewrite listRewrite= rewrite.getListRewrite(dim1, ExtraDimension.ANNOTATIONS_PROPERTY);
+			ListRewrite listRewrite= rewrite.getListRewrite(dim1, Dimension.ANNOTATIONS_PROPERTY);
 			listRewrite.replace(annot1, annot2, null);
 
-			listRewrite= rewrite.getListRewrite(dim2, ExtraDimension.ANNOTATIONS_PROPERTY);
+			listRewrite= rewrite.getListRewrite(dim2, Dimension.ANNOTATIONS_PROPERTY);
 			listRewrite.replace(annot2, annot1, null);
 		}
 		{ // remove extra dim
 			SingleVariableDeclaration decl= (SingleVariableDeclaration) arguments.get(3);
 			ListRewrite listRewrite= rewrite.getListRewrite(decl, SingleVariableDeclaration.EXTRA_DIMENSIONS2_PROPERTY);
-			listRewrite.remove((ExtraDimension) decl.extraDimensions().get(0), null);
+			listRewrite.remove((Dimension) decl.extraDimensions().get(0), null);
 		}
 
 		String preview= evaluateRewrite(cu, rewrite);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index 4fa4be4..37b31f0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -1627,7 +1627,7 @@
 	/** @since 3.9 BETA_JAVA8 */
 	int DuplicateAnnotationNotMarkedRepeatable = TypeRelated + 897;
 	/** @since 3.9 BETA_JAVA8 */
-	int DisallowedTargetForContainerAnnotation = TypeRelated + 898;
+	int DisallowedTargetForContainerAnnotationType = TypeRelated + 898;
 	/** @since 3.9 BETA_JAVA8 */
 	int RepeatedAnnotationWithContainerAnnotation = TypeRelated + 899;
 	
@@ -1644,21 +1644,19 @@
 	int ExternalProblemFixable = 901;
 	
 	/** @since 3.9 BETA_JAVA8 */
-	int ContainingAnnotationHasWrongValueType = TypeRelated + 902;
+	int ContainerAnnotationTypeHasWrongValueType = TypeRelated + 902;
 	/** @since 3.9 BETA_JAVA8 */
-	int ContainingAnnotationMustHaveValue = TypeRelated + 903;
+	int ContainerAnnotationTypeMustHaveValue = TypeRelated + 903;
 	/** @since 3.9 BETA_JAVA8 */
-	int ContainingAnnotationHasNonDefaultMembers = TypeRelated + 904;
+	int ContainerAnnotationTypeHasNonDefaultMembers = TypeRelated + 904;
 	/** @since 3.9 BETA_JAVA8 */
-	int ContainingAnnotationHasShorterRetention = TypeRelated + 905;
+	int ContainerAnnotationTypeHasShorterRetention = TypeRelated + 905;
 	/** @since 3.9 BETA_JAVA8 */
-	int RepeatableAnnotationHasTargets = TypeRelated + 906;
+	int RepeatableAnnotationTypeTargetMismatch = TypeRelated + 906;
 	/** @since 3.9 BETA_JAVA8 */
-	int RepeatableAnnotationTargetMismatch = TypeRelated + 907;
+	int RepeatableAnnotationTypeIsDocumented = TypeRelated + 907;
 	/** @since 3.9 BETA_JAVA8 */
-	int RepeatableAnnotationIsDocumented = TypeRelated + 908;
-	/** @since 3.9 BETA_JAVA8 */
-	int RepeatableAnnotationIsInherited = TypeRelated + 909;
+	int RepeatableAnnotationTypeIsInherited = TypeRelated + 908;
 	
 	/**
 	 * Errors/warnings from annotation based null analysis
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
index 3e39190..a6b606f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
@@ -17,6 +17,7 @@
  *							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335             
  *							Bug 406982 - [1.8][compiler] Generation of MethodParameters Attribute in classfile
  *							Bug 416885 - [1.8][compiler]IncompatibleClassChange error (edit)
+ *							Bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container
  *        Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
  *                          Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
  *                          Bug 409236 - [1.8][compiler] Type annotations on intersection cast types dropped by code generator
@@ -424,7 +425,14 @@
 			if (typeDeclaration != null) {
 				final Annotation[] annotations = typeDeclaration.annotations;
 				if (annotations != null) {
-					attributesNumber += generateRuntimeAnnotations(annotations, true);
+					long targetMask;
+					if (typeDeclaration.isPackageInfo())
+						targetMask = TagBits.AnnotationForPackage;
+					else if (this.referenceBinding.isAnnotationType())
+						targetMask = TagBits.AnnotationForAnnotationType;
+					else
+						targetMask = TagBits.AnnotationForType | TagBits.AnnotationForTypeUse;
+					attributesNumber += generateRuntimeAnnotations(annotations, targetMask); 
 				}
 			}
 		}
@@ -520,7 +528,7 @@
 			if (fieldDeclaration != null) {
 				Annotation[] annotations = fieldDeclaration.annotations;
 				if (annotations != null) {
-					attributesNumber += generateRuntimeAnnotations(annotations, false);
+					attributesNumber += generateRuntimeAnnotations(annotations, TagBits.AnnotationForField);
 				}
 
 				if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) {
@@ -3304,7 +3312,7 @@
 			if (methodDeclaration != null) {
 				Annotation[] annotations = methodDeclaration.annotations;
 				if (annotations != null) {
-					attributesNumber += generateRuntimeAnnotations(annotations, false);
+					attributesNumber += generateRuntimeAnnotations(annotations, methodBinding.isConstructor() ? TagBits.AnnotationForConstructor : TagBits.AnnotationForMethod);
 				}
 				if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) {
 					Argument[] arguments = methodDeclaration.arguments;
@@ -3514,20 +3522,22 @@
 
 	/**
 	 * @param annotations
-	 * @param includeTypeUseAnnotations Used to support JSR308 Section 2.3 special allowance for TYPE_USE annotation used on a type declaration
+	 * @param targetMask allowed targets
 	 * @return the number of attributes created while dumping the annotations in the .class file
 	 */
-	private int generateRuntimeAnnotations(final Annotation[] annotations, final boolean includeTypeUseAnnotations) {
+	private int generateRuntimeAnnotations(final Annotation[] annotations, final long targetMask) {
 		int attributesNumber = 0;
 		final int length = annotations.length;
 		int visibleAnnotationsCounter = 0;
 		int invisibleAnnotationsCounter = 0;
-
 		for (int i = 0; i < length; i++) {
-			Annotation annotation = annotations[i];
-			if (annotation.isRuntimeInvisible() || (includeTypeUseAnnotations && annotation.isRuntimeTypeInvisible())) {
+			Annotation annotation;
+			if ((annotation = annotations[i].getPersistibleAnnotation()) == null) continue; // already packaged into container.
+			long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0;
+			if (annotationMask != 0 && (annotationMask & targetMask) == 0) continue;
+			if (annotation.isRuntimeInvisible() || annotation.isRuntimeTypeInvisible()) {
 				invisibleAnnotationsCounter++;
-			} else if (annotation.isRuntimeVisible() || (includeTypeUseAnnotations && annotation.isRuntimeTypeVisible())) {
+			} else if (annotation.isRuntimeVisible() || annotation.isRuntimeTypeVisible()) {
 				visibleAnnotationsCounter++;
 			}
 		}
@@ -3552,11 +3562,11 @@
 			int counter = 0;
 			loop: for (int i = 0; i < length; i++) {
 				if (invisibleAnnotationsCounter == 0) break loop;
-				Annotation annotation = annotations[i];
-				if (annotation.isRuntimeInvisible() || 
-						// No need to explicitly check it is type_use and not type_parameter, 
-						// that will already have been checked
-						(includeTypeUseAnnotations && annotation.isRuntimeTypeInvisible())) {
+				Annotation annotation;
+				if ((annotation = annotations[i].getPersistibleAnnotation()) == null) continue; // already packaged into container.
+				long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0;
+				if (annotationMask != 0 && (annotationMask & targetMask) == 0) continue;
+				if (annotation.isRuntimeInvisible() || annotation.isRuntimeTypeInvisible()) {
 					int currentAnnotationOffset = this.contentsOffset;
 					generateAnnotation(annotation, currentAnnotationOffset);
 					invisibleAnnotationsCounter--;
@@ -3602,11 +3612,11 @@
 			int counter = 0;
 			loop: for (int i = 0; i < length; i++) {
 				if (visibleAnnotationsCounter == 0) break loop;
-				Annotation annotation = annotations[i];
-				if (annotation.isRuntimeVisible() || 
-					// No need to explicitly check it is type_use and not type_parameter, 
-					// that will already have been checked
-					(includeTypeUseAnnotations && annotation.isRuntimeTypeVisible())) {
+				Annotation annotation;
+				if ((annotation = annotations[i].getPersistibleAnnotation()) == null) continue; // already packaged into container.
+				long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0;
+				if (annotationMask != 0 && (annotationMask & targetMask) == 0) continue;
+				if (annotation.isRuntimeVisible() || annotation.isRuntimeTypeVisible()) {
 					visibleAnnotationsCounter--;
 					int currentAnnotationOffset = this.contentsOffset;
 					generateAnnotation(annotation, currentAnnotationOffset);
@@ -3645,7 +3655,10 @@
 			Annotation[] annotations = argument.annotations;
 			if (annotations != null) {
 				for (int j = 0, max2 = annotations.length; j < max2; j++) {
-					Annotation annotation = annotations[j];
+					Annotation annotation;
+					if ((annotation = annotations[j].getPersistibleAnnotation()) == null) continue; // already packaged into container.
+					long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0;
+					if (annotationMask != 0 && (annotationMask & TagBits.AnnotationForParameter) == 0) continue;
 					if (annotation.isRuntimeInvisible()) {
 						annotationsCounters[i][INVISIBLE_INDEX]++;
 						invisibleParametersAnnotationsCounter++;
@@ -3688,7 +3701,10 @@
 						Argument argument = arguments[i];
 						Annotation[] annotations = argument.annotations;
 						for (int j = 0, max = annotations.length; j < max; j++) {
-							Annotation annotation = annotations[j];
+							Annotation annotation;
+							if ((annotation = annotations[j].getPersistibleAnnotation()) == null) continue; // already packaged into container.
+							long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0;
+							if (annotationMask != 0 && (annotationMask & TagBits.AnnotationForParameter) == 0) continue;
 							if (annotation.isRuntimeInvisible()) {
 								int currentAnnotationOffset = this.contentsOffset;
 								generateAnnotation(annotation, currentAnnotationOffset);
@@ -3746,7 +3762,10 @@
 						Argument argument = arguments[i];
 						Annotation[] annotations = argument.annotations;
 						for (int j = 0, max = annotations.length; j < max; j++) {
-							Annotation annotation = annotations[j];
+							Annotation annotation;
+							if ((annotation = annotations[j].getPersistibleAnnotation()) == null) continue; // already packaged into container.
+							long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0;
+							if (annotationMask != 0 && (annotationMask & TagBits.AnnotationForParameter) == 0) continue;
 							if (annotation.isRuntimeVisible()) {
 								int currentAnnotationOffset = this.contentsOffset;
 								generateAnnotation(annotation, currentAnnotationOffset);
@@ -4601,10 +4620,9 @@
 	}
 	
 	private void generateTypeAnnotation(AnnotationContext annotationContext, int currentOffset) {
-		if (annotationContext.wildcard != null) {
-			generateWildcardTypeAnnotation(annotationContext, currentOffset);
+		Annotation annotation = annotationContext.annotation.getPersistibleAnnotation();
+		if (annotation == null || annotation.resolvedType == null)
 			return;
-		}
 		
 		int targetType = annotationContext.targetType;
 
@@ -4618,27 +4636,9 @@
 		this.contents[this.contentsOffset++] = (byte) targetType;
 		dumpTargetTypeContents(targetType, annotationContext);
 		dumpLocations(locations);
-		
-		// common part between type annotation and annotation
-		generateAnnotation(annotationContext.annotation, currentOffset);
+		generateAnnotation(annotation, currentOffset);
 	}
 
-	private void generateWildcardTypeAnnotation(AnnotationContext annotationContext, int currentOffset) {
-		int targetType = annotationContext.targetType;
-
-		int[] locations = Annotation.getLocations(
-				annotationContext.typeReference,
-				annotationContext.annotation);
-		// reserve enough space
-		if (this.contentsOffset + 5 >= this.contents.length) {
-			resizeContents(5);
-		}
-		this.contents[this.contentsOffset++] = (byte) targetType;
-		dumpTargetTypeContents(targetType, annotationContext);
-		dumpLocations(locations);
-		generateAnnotation(annotationContext.annotation, currentOffset);
-	}
-	
 	private int generateTypeAnnotationAttributeForTypeDeclaration() {
 		TypeDeclaration typeDeclaration = this.referenceBinding.scope.referenceContext;
 		if ((typeDeclaration.bits & ASTNode.HasTypeAnnotations) == 0) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
index 875043a..8e4da1b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
@@ -28,6 +28,7 @@
  *								bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
  *								bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
  *								bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
+ *								bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
@@ -798,6 +799,8 @@
 						break;
 					case Binding.FIELD :
 						FieldBinding field = (FieldBinding) recipient;
+						if (!(annotationRecipient instanceof FieldBinding))
+							break;
 						field.tagBits = ((FieldBinding) annotationRecipient).tagBits;
 						if (annotations != null) {
 							// need to fill the instances array
@@ -809,6 +812,8 @@
 						break;
 					case Binding.LOCAL :
 						LocalVariableBinding local = (LocalVariableBinding) recipient;
+						if (!(annotationRecipient instanceof LocalVariableBinding))
+							break;
 						long otherLocalTagBits = ((LocalVariableBinding) annotationRecipient).tagBits;
 						local.tagBits = otherLocalTagBits;
 						if ((otherLocalTagBits & TagBits.AnnotationSuppressWarnings) == 0) {
@@ -842,11 +847,6 @@
 							}
 						}
 						break;
-					default:
-						if (annotations != null) {
-							annotations[i] = annotation.getCompilerAnnotation();
-						}
-						break;
 				}
 				return annotations;
 			} else {
@@ -862,15 +862,15 @@
 		if (copySE8AnnotationsToType)
 			copySE8AnnotationsToType(scope, recipient, sourceAnnotations);
 
-		if (annotations != null && length > 0 && recipient != null && recipient.isAnnotationType()) {
-			// See if this is meta-annotated as repeatable and if so validate constraints.
+		/* See if the recipient is meta-annotated with @Repeatable and if so validate constraints. We can't do this during resolution of @Repeatable itself as @Target and 
+		   @Retention etc could come later
+		*/   
+		if (recipient != null && recipient.isTaggedRepeatable()) {
 			for (int i = 0; i < length; i++) {
 				Annotation annotation = sourceAnnotations[i];
-				MemberValuePair[] valuePairs = annotation.memberValuePairs();
 				ReferenceBinding annotationType = annotations[i] != null ? annotations[i].getAnnotationType() : null;
-				if (annotationType != null && annotationType.id == TypeIds.T_JavaLangAnnotationRepeatable && valuePairs != null && valuePairs.length > 0) {
-					annotation.checkRepeatableAnnotation(valuePairs[0], scope, valuePairs[0].compilerElementPair.value);
-				}
+				if (annotationType != null && annotationType.id == TypeIds.T_JavaLangAnnotationRepeatable)
+					annotation.checkRepeatableMetaAnnotation(scope);
 			}
 		}
 		
@@ -883,30 +883,35 @@
 				if (annotation == null) continue;
 				ReferenceBinding annotationType = annotation.getAnnotationType();
 				boolean foundDuplicate = false;
+				ContainerAnnotation container = null;
 				for (int j = i+1; j < length; j++) {
 					AnnotationBinding otherAnnotation = distinctAnnotations[j];
 					if (otherAnnotation == null) continue;
 					if (otherAnnotation.getAnnotationType() == annotationType) {
-						if (annotationType.isRepeatableAnnotation()) {
-							ReferenceBinding resolvedContainer = annotationType.resolveContainerAnnotation();
-							if (resolvedContainer != null) {
-								// Since this is a repeated annotation, we need to check if the container is also used - so store it
-								// in a map of (container's ReferenceBinding -> the repeated source Annotation)
+						if (distinctAnnotations == annotations) {
+							System.arraycopy(distinctAnnotations, 0, distinctAnnotations = new AnnotationBinding[length], 0, length);
+						}
+						distinctAnnotations[j] = null; // report/process it only once
+						if (annotationType.isRepeatableAnnotationType()) {
+							Annotation persistibleAnnotation = sourceAnnotations[i].getPersistibleAnnotation();
+							if (persistibleAnnotation instanceof ContainerAnnotation)
+								container = (ContainerAnnotation) persistibleAnnotation;
+							if (container == null) {  // first encounter with a duplicate.
+								ReferenceBinding containerAnnotationType = annotationType.containerAnnotationType();
+								container = new ContainerAnnotation(sourceAnnotations[i], containerAnnotationType, scope);
 								if (implicitContainerAnnotations == null) implicitContainerAnnotations = new HashMap(3);
-								implicitContainerAnnotations.put(resolvedContainer, sourceAnnotations[i]);
-								// Validate the repeated *use* of a repeatable annotation.
-								Annotation.checkContainingAnnotation(sourceAnnotations[i], scope, resolvedContainer, annotationType);
+								implicitContainerAnnotations.put(containerAnnotationType, sourceAnnotations[i]);
 							}
+							container.addContainee(sourceAnnotations[j]);
 						} else {
 							foundDuplicate = true;
-							if (distinctAnnotations == annotations) {
-								System.arraycopy(distinctAnnotations, 0, distinctAnnotations = new AnnotationBinding[length], 0, length);
-							}
-							distinctAnnotations[j] = null; // report it only once
 							scope.problemReporter().duplicateAnnotation(sourceAnnotations[j], scope.compilerOptions().sourceLevel);
 						}
 					}
 				}
+				if (container != null) {
+					container.resolveType(scope);
+				}
 				if (foundDuplicate) {
 					scope.problemReporter().duplicateAnnotation(sourceAnnotations[i], scope.compilerOptions().sourceLevel);
 				}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
index 0f84198..19f0b60 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
@@ -561,12 +561,7 @@
  	}
 	final CompilerOptions compilerOptions = scope.compilerOptions();
 	if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
-//{ObjectTeams: added 2nd arg:
-/* orig:
-		new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations)
-  :giro */
-		new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations, scope.environment())
-// SH}
+		new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations)
 				.checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope);
 	}
 //{ObjectTeams: may need to wrap the resolved type
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
index 317f8f1..f7f2e70 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
@@ -29,7 +29,8 @@
  *                          Bug 414384 - [1.8] type annotation on abbreviated inner class is not marked as inner type
  *      Jesper S Moller <jesper@selskabet.org> -  Contributions for
  *                          Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
-#							Bug 412151 - [1.8][compiler] Check repeating annotation's collection type
+ *                          Bug 412151 - [1.8][compiler] Check repeating annotation's collection type
+ *                          Bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
@@ -53,6 +54,8 @@
  */
 public abstract class Annotation extends Expression {
 	
+	Annotation persistibleAnnotation = this;  // Emit this into class file, unless this is a repeating annotation, in which case package this into the designated container.
+	
 	/**
 	 * Return the location for the corresponding annotation inside the type reference, <code>null</code> if none.
 	 */
@@ -239,7 +242,7 @@
 	/**
 	 *  The representation of this annotation in the type system.
 	 */
-	private AnnotationBinding compilerAnnotation = null;
+	protected AnnotationBinding compilerAnnotation = null;
 
 	public static long getRetentionPolicy(char[] policyName) {
 		if (policyName == null || policyName.length == 0)
@@ -373,6 +376,9 @@
 			case TypeIds.T_JavaLangFunctionalInterface :
 				tagBits |= TagBits.AnnotationFunctionalInterface;
 				break;
+			case TypeIds.T_JavaLangAnnotationRepeatable:
+				tagBits |= TagBits.AnnotationRepeatable;
+				break;
 			case TypeIds.T_JavaLangSuppressWarnings :
 				tagBits |= TagBits.AnnotationSuppressWarnings;
 				break;
@@ -423,18 +429,30 @@
 		// Retention defaults to CLASS
 		return retention != 0 ? retention : TagBits.AnnotationClassRetention;
 	}
-	
-	public void checkRepeatableAnnotation(ASTNode valueAttribute, Scope scope, Object containingBinding) {
-		if (! (this.recipient instanceof ReferenceBinding && containingBinding instanceof ReferenceBinding)) return; // Has deeper problems...
-		ReferenceBinding containing = (ReferenceBinding)containingBinding;
-		ReferenceBinding repeatableAnnotation = (ReferenceBinding) this.recipient;
-		repeatableAnnotation.setContainingAnnotation(containing);
 
-		checkContainingAnnotation(valueAttribute, scope, containing, repeatableAnnotation);
+	public void checkRepeatableMetaAnnotation(BlockScope scope) {
+		
+		// `this' is the @Repeatable meta annotation, its recipient is the *repeatable* annotation type - we are at the declaration site, not the repeating use site.
+		
+		ReferenceBinding repeatableAnnotationType = (ReferenceBinding) this.recipient; // know it to be an annotation type. On target miss we don't get here
+		
+		MemberValuePair[] valuePairs = this.memberValuePairs();
+		if (valuePairs == null || valuePairs.length != 1)
+			return;
+		
+		Object value = valuePairs[0].compilerElementPair.value;
+		if (!(value instanceof ReferenceBinding))
+			return; // Has deeper problems, will bark elsewhere.
+		ReferenceBinding containerAnnotationType = (ReferenceBinding) value;
+		if (!containerAnnotationType.isAnnotationType())
+			return; // Has deeper problems, will bark elsewhere.
+		
+		repeatableAnnotationType.setContainerAnnotationType(containerAnnotationType); // For now. May be reset later to PRB in case of problems.
+		checkContainerAnnotationType(valuePairs[0], scope, containerAnnotationType, repeatableAnnotationType, false); // false => not use site, i.e declaration site error reporting requested.
 	}
 
-	public static void checkContainingAnnotation(ASTNode markerNode, Scope scope, ReferenceBinding container, ReferenceBinding repeatableAnnotation) {
-		MethodBinding[] annotationMethods = container.methods();
+	public static void checkContainerAnnotationType(ASTNode culpritNode, BlockScope scope, ReferenceBinding containerAnnotationType, ReferenceBinding repeatableAnnotationType, boolean useSite) {
+		MethodBinding[] annotationMethods = containerAnnotationType.methods();
 		boolean sawValue = false;
 		for (int i = 0, length = annotationMethods.length; i < length; ++i) {
 			MethodBinding method = annotationMethods[i];
@@ -442,120 +460,118 @@
 				sawValue = true;
 				if (method.returnType.isArrayType() && method.returnType.dimensions() == 1) {
 					ArrayBinding array = (ArrayBinding) method.returnType;
-					if (TypeBinding.equalsEquals(array.elementsType(), repeatableAnnotation)) continue;
+					if (TypeBinding.equalsEquals(array.elementsType(), repeatableAnnotationType)) continue;
 				}
-				scope.problemReporter().containingAnnotationHasWrongValueType(markerNode, container, repeatableAnnotation, method.returnType);
+				repeatableAnnotationType.tagAsHavingDefectiveContainerType();
+				scope.problemReporter().containerAnnotationTypeHasWrongValueType(culpritNode, containerAnnotationType, repeatableAnnotationType, method.returnType);
 			} else {
-				// Not the value() - must have default (or else isn't suitable as container
+				// Not the value() - must have default (or else isn't suitable as container)
 				if ((method.modifiers & ClassFileConstants.AccAnnotationDefault) == 0) {
-					scope.problemReporter().containingAnnotationHasNonDefaultMembers(markerNode, container, method.selector);
+					repeatableAnnotationType.tagAsHavingDefectiveContainerType();
+					scope.problemReporter().containerAnnotationTypeHasNonDefaultMembers(culpritNode, containerAnnotationType, method.selector);
 				}
 			}
 		}
 		if (!sawValue) {
-			scope.problemReporter().containingAnnotationMustHaveValue(markerNode, container);
+			repeatableAnnotationType.tagAsHavingDefectiveContainerType();
+			scope.problemReporter().containerAnnotationTypeMustHaveValue(culpritNode, containerAnnotationType);
+		}
+
+		if (useSite)
+			checkContainingAnnotationTargetAtUse((Annotation) culpritNode, scope, containerAnnotationType, repeatableAnnotationType);
+		else 
+			checkContainerAnnotationTypeTarget(culpritNode, scope, containerAnnotationType, repeatableAnnotationType);
+		
+		long annotationTypeBits = getAnnotationRetention(repeatableAnnotationType);
+		long containerTypeBits = getAnnotationRetention(containerAnnotationType); 
+		// Due to clever layout of the bits, we can compare the absolute value directly
+		if (containerTypeBits < annotationTypeBits) {
+			repeatableAnnotationType.tagAsHavingDefectiveContainerType();
+			scope.problemReporter().containerAnnotationTypeHasShorterRetention(culpritNode, repeatableAnnotationType, getRetentionName(annotationTypeBits), containerAnnotationType, getRetentionName(containerTypeBits));
 		}
 		
-		checkContainingAnnotationRetention(markerNode, scope, container, repeatableAnnotation);
-		if (markerNode instanceof Annotation)
-			checkContainingAnnotationTarget((Annotation) markerNode, (BlockScope) scope, (TypeBinding) container, repeatableAnnotation);
-		else
-			checkContainingAnnotationTarget(markerNode, scope, container, repeatableAnnotation);
-		checkContaintAnnotationDocumented(markerNode, scope, container, repeatableAnnotation);
-		checkContaintAnnotationInherited(markerNode, scope, container, repeatableAnnotation);
-	}
-
-	// This is for error reporting for bad targets at the repeated annotation use site (as opposed to repeatable annotation type declaration site) - Leads to better message.
-	public static void checkContainingAnnotationTarget(Annotation annotation, BlockScope scope, TypeBinding containerAnnotationType, TypeBinding annotationType) {
-		// check (meta)target compatibility
-		if (!annotationType.isValidBinding()) {
-			// no need to check annotation usage if missing
-			return;
+		if ((repeatableAnnotationType.getAnnotationTagBits() & TagBits.AnnotationDocumented) != 0 && (containerAnnotationType.getAnnotationTagBits() & TagBits.AnnotationDocumented) == 0) {
+			repeatableAnnotationType.tagAsHavingDefectiveContainerType();
+			scope.problemReporter().repeatableAnnotationTypeIsDocumented(culpritNode, repeatableAnnotationType, containerAnnotationType);
 		}
-		if (! isAnnotationTargetAllowed(annotation, scope, containerAnnotationType, annotation.recipient.kind())) {
-			scope.problemReporter().disallowedTargetForContainerAnnotation(annotation, containerAnnotationType);
+		
+		if ((repeatableAnnotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) != 0 && (containerAnnotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) == 0) {
+			repeatableAnnotationType.tagAsHavingDefectiveContainerType();
+			scope.problemReporter().repeatableAnnotationTypeIsInherited(culpritNode, repeatableAnnotationType, containerAnnotationType);
 		}
 	}
 	
 	// This is for error reporting for bad targets at annotation type declaration site (as opposed to the repeat site)
-	private static void checkContainingAnnotationTarget(ASTNode markerNode, Scope scope, ReferenceBinding container, ReferenceBinding repeatableAnnotation) {
-		long tagBits = repeatableAnnotation.getAnnotationTagBits();
-		if ((tagBits & TagBits.AnnotationTargetMASK) != 0) { 
-			long containingTagBits = container.getAnnotationTagBits();
-			if ((containingTagBits & TagBits.AnnotationTargetMASK) == 0) {
-				scope.problemReporter().repeatableAnnotationHasTargets(markerNode, repeatableAnnotation, container);
-			} else {
-				final long targets = tagBits & TagBits.AnnotationTargetMASK;
-				final long containingTargets = containingTagBits & TagBits.AnnotationTargetMASK;
-				
-				if ((containingTargets & ~targets) != 0) {
-					class MissingTargetBuilder {
-						StringBuffer targetBuffer = new StringBuffer();
-						void check(long targetMask, char[] targetName) {
-							if ((containingTargets & targetMask & ~targets) != 0) {
-								add(targetName);
-							}
-						}
-						void checkAnnotationType(char[] targetName) {
-							if ((containingTargets & TagBits.AnnotationForAnnotationType) != 0 &&
-									((targets & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType))) == 0) {
-								add(targetName);
-							}
-						}
-						private void add(char[] targetName) {
-							if (this.targetBuffer.length() != 0) {
-								this.targetBuffer.append(", "); //$NON-NLS-1$
-							}
-							this.targetBuffer.append(targetName);
-						}
-						public String toString() {
-							return this.targetBuffer.toString();
-						}
-						public boolean hasError() {
-							return this.targetBuffer.length() != 0;
-						}
-					}
-					MissingTargetBuilder builder = new MissingTargetBuilder();
+	private static void checkContainerAnnotationTypeTarget(ASTNode culpritNode, Scope scope, ReferenceBinding containerType, ReferenceBinding repeatableAnnotationType) {
+		long tagBits = repeatableAnnotationType.getAnnotationTagBits();
+		if ((tagBits & TagBits.AnnotationTargetMASK) == 0)
+			tagBits = TagBits.SE7AnnotationTargetMASK; // absence of @Target meta-annotation implies all SE7 targets not all targets.
+		
+		long containerAnnotationTypeTypeTagBits = containerType.getAnnotationTagBits();
+		if ((containerAnnotationTypeTypeTagBits & TagBits.AnnotationTargetMASK) == 0)
+			containerAnnotationTypeTypeTagBits = TagBits.SE7AnnotationTargetMASK;
 
-					builder.check(TagBits.AnnotationForType, TypeConstants.TYPE);
-					builder.check(TagBits.AnnotationForField, TypeConstants.UPPER_FIELD);
-					builder.check(TagBits.AnnotationForMethod, TypeConstants.UPPER_METHOD);
-					builder.check(TagBits.AnnotationForParameter, TypeConstants.UPPER_PARAMETER);
-					builder.check(TagBits.AnnotationForConstructor, TypeConstants.UPPER_CONSTRUCTOR);
-					builder.check(TagBits.AnnotationForLocalVariable, TypeConstants.UPPER_LOCAL_VARIABLE);
-					builder.checkAnnotationType(TypeConstants.UPPER_ANNOTATION_TYPE);
-					builder.check(TagBits.AnnotationForPackage, TypeConstants.UPPER_PACKAGE);
-					builder.check(TagBits.AnnotationForTypeParameter, TypeConstants.TYPE_PARAMETER_TARGET);
-					builder.check(TagBits.AnnotationForTypeUse, TypeConstants.TYPE_USE_TARGET);
-					if (builder.hasError()) {
-						scope.problemReporter().repeatableAnnotationTargetMismatch(markerNode, repeatableAnnotation, container, builder.toString());
+		final long targets = tagBits & TagBits.AnnotationTargetMASK;
+		final long containerAnnotationTypeTargets = containerAnnotationTypeTypeTagBits & TagBits.AnnotationTargetMASK;
+
+		if ((containerAnnotationTypeTargets & ~targets) != 0) {
+			class MissingTargetBuilder {
+				StringBuffer targetBuffer = new StringBuffer();
+				void check(long targetMask, char[] targetName) {
+					if ((containerAnnotationTypeTargets & targetMask & ~targets) != 0) {
+						add(targetName);
 					}
 				}
+				void checkAnnotationType(char[] targetName) {
+					if ((containerAnnotationTypeTargets & TagBits.AnnotationForAnnotationType) != 0 &&
+							((targets & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType))) == 0) {
+						add(targetName);
+					}
+				}
+				private void add(char[] targetName) {
+					if (this.targetBuffer.length() != 0) {
+						this.targetBuffer.append(", "); //$NON-NLS-1$
+					}
+					this.targetBuffer.append(targetName);
+				}
+				public String toString() {
+					return this.targetBuffer.toString();
+				}
+				public boolean hasError() {
+					return this.targetBuffer.length() != 0;
+				}
+			}
+			MissingTargetBuilder builder = new MissingTargetBuilder();
+
+			builder.check(TagBits.AnnotationForType, TypeConstants.TYPE);
+			builder.check(TagBits.AnnotationForField, TypeConstants.UPPER_FIELD);
+			builder.check(TagBits.AnnotationForMethod, TypeConstants.UPPER_METHOD);
+			builder.check(TagBits.AnnotationForParameter, TypeConstants.UPPER_PARAMETER);
+			builder.check(TagBits.AnnotationForConstructor, TypeConstants.UPPER_CONSTRUCTOR);
+			builder.check(TagBits.AnnotationForLocalVariable, TypeConstants.UPPER_LOCAL_VARIABLE);
+			builder.checkAnnotationType(TypeConstants.UPPER_ANNOTATION_TYPE);
+			builder.check(TagBits.AnnotationForPackage, TypeConstants.UPPER_PACKAGE);
+			builder.check(TagBits.AnnotationForTypeParameter, TypeConstants.TYPE_PARAMETER_TARGET);
+			builder.check(TagBits.AnnotationForTypeUse, TypeConstants.TYPE_USE_TARGET);
+			if (builder.hasError()) {
+				repeatableAnnotationType.tagAsHavingDefectiveContainerType();
+				scope.problemReporter().repeatableAnnotationTypeTargetMismatch(culpritNode, repeatableAnnotationType, containerType, builder.toString());
 			}
 		}
 	}
-
-	private static void checkContaintAnnotationDocumented(ASTNode markerNode, Scope scope, ReferenceBinding containing, ReferenceBinding repeatableAnnotation) {
-		if ((repeatableAnnotation.getAnnotationTagBits() & TagBits.AnnotationDocumented) != 0 && (containing.getAnnotationTagBits() & TagBits.AnnotationDocumented) == 0) {
-			scope.problemReporter().repeatableAnnotationIsDocumented(markerNode, repeatableAnnotation, containing);
-		}
-	}
-
-	private static void checkContaintAnnotationInherited(ASTNode markerNode, Scope scope, ReferenceBinding containing, ReferenceBinding repeatableAnnotation) {
-		if ((repeatableAnnotation.getAnnotationTagBits() & TagBits.AnnotationInherited) != 0 && (containing.getAnnotationTagBits() & TagBits.AnnotationInherited) == 0) {
-			scope.problemReporter().repeatableAnnotationIsInherited(markerNode, repeatableAnnotation, containing);
-		}
-	}
-
-	private static void checkContainingAnnotationRetention(ASTNode markerNode, Scope scope, ReferenceBinding container, ReferenceBinding repeatableAnnotation) {
-		long annotationBits = getAnnotationRetention(repeatableAnnotation);
-		long containerBits = getAnnotationRetention(container); 
-		// Due to clever layout of the bits, we can compare the absolute value directly
-		if (containerBits < annotationBits) {
-			scope.problemReporter().containingAnnotationHasShorterRetention(markerNode, repeatableAnnotation, getRetentionName(annotationBits), container, getRetentionName(containerBits));
-		}
-	}
 	
+	// This is for error reporting for bad targets at the repeated annotation use site (as opposed to repeatable annotation type declaration site) - Leads to better message.
+	public static void checkContainingAnnotationTargetAtUse(Annotation repeatingAnnotation, BlockScope scope, TypeBinding containerAnnotationType, TypeBinding repeatingAnnotationType) {
+		// check (meta)target compatibility
+		if (!repeatingAnnotationType.isValidBinding()) {
+			// no need to check annotation usage if missing
+			return;
+		}
+		if (! isAnnotationTargetAllowed(repeatingAnnotation, scope, containerAnnotationType, repeatingAnnotation.recipient.kind())) {
+			scope.problemReporter().disallowedTargetForContainerAnnotation(repeatingAnnotation, containerAnnotationType);
+		}
+	}
+
 	public AnnotationBinding getCompilerAnnotation() {
 		return this.compilerAnnotation;
 	}
@@ -792,7 +808,8 @@
 					case Binding.TYPE :
 					case Binding.GENERIC_TYPE :
 						SourceTypeBinding sourceType = (SourceTypeBinding) this.recipient;
-						sourceType.tagBits |= tagBits;
+						if ((tagBits & TagBits.AnnotationRepeatable) == 0 || sourceType.isAnnotationType()) // don't set AnnotationRepeatable on non-annotation types.
+							sourceType.tagBits |= tagBits;
 						if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
 							TypeDeclaration typeDeclaration =  sourceType.scope.referenceContext;
 							int start;
@@ -1042,4 +1059,13 @@
 	public abstract void traverse(ASTVisitor visitor, BlockScope scope);
 
 	public abstract void traverse(ASTVisitor visitor, ClassScope scope);
+
+	public Annotation getPersistibleAnnotation() {
+		return this.persistibleAnnotation;      // will be this for non-repeating annotation, the container for the first of the repeating ones and null for the followers.
+	}
+	
+	public void setPersistibleAnnotation(ContainerAnnotation container) {
+		this.persistibleAnnotation = container; // will be a legitimate container for the first of the repeating ones and null for the followers.
+	}
+	
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java
new file mode 100644
index 0000000..ea0de63
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Jesper S Moller and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * Contributors:
+ *     Jesper S Moller <jesper@selskabet.org> - initial API and implementation
+ ********************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+
+public class ContainerAnnotation extends SingleMemberAnnotation {
+	
+	private Annotation [] containees;
+	private ArrayInitializer memberValues;
+	
+	public ContainerAnnotation(Annotation repeatingAnnotation, ReferenceBinding containerAnnotationType, BlockScope scope) {
+		
+		char [][] containerTypeName = containerAnnotationType.compoundName;
+		if (containerTypeName.length == 1) {
+			this.type = new SingleTypeReference(containerTypeName[0], 0);
+		} else {
+			this.type = new QualifiedTypeReference(containerTypeName, new long [containerTypeName.length]);
+		}
+		
+		this.sourceStart = repeatingAnnotation.sourceStart;
+		this.sourceEnd = repeatingAnnotation.sourceEnd;
+		
+		this.resolvedType = containerAnnotationType;
+		this.recipient = repeatingAnnotation.recipient;
+		this.containees = new Annotation[0];
+		this.memberValue = this.memberValues = new ArrayInitializer();
+		addContainee(repeatingAnnotation);
+	}
+	
+	public void addContainee(Annotation repeatingAnnotation) {
+		final int length = this.containees.length;
+		System.arraycopy(this.containees, 0, this.containees = new Annotation[length + 1], 0, length);
+		this.containees[length] = repeatingAnnotation;
+		this.memberValues.expressions = this.containees;
+		repeatingAnnotation.setPersistibleAnnotation(length == 0 ? this : null);
+	}
+	
+	// Resolve the compiler synthesized container annotation.
+	public TypeBinding resolveType(BlockScope scope) {
+
+		if (this.compilerAnnotation != null)
+			return this.resolvedType;
+
+		this.constant = Constant.NotAConstant;
+
+		ReferenceBinding containerAnnotationType = (ReferenceBinding) this.resolvedType;
+		if (!containerAnnotationType.isValidBinding())
+			containerAnnotationType = (ReferenceBinding) containerAnnotationType.closestMatch();
+		Annotation repeatingAnnotation = this.containees[0];
+		ReferenceBinding repeatingAnnotationType = (ReferenceBinding) repeatingAnnotation.resolvedType;
+		if (!repeatingAnnotationType.isDeprecated() && isTypeUseDeprecated(containerAnnotationType, scope)) {
+			scope.problemReporter().deprecatedType(containerAnnotationType, repeatingAnnotation);
+		}
+		checkContainerAnnotationType(repeatingAnnotation, scope, containerAnnotationType, repeatingAnnotationType, true); // true => repeated *use* site error reporting requested.
+		this.resolvedType = containerAnnotationType = repeatingAnnotationType.containerAnnotationType();
+		if (!this.resolvedType.isValidBinding())
+			return this.resolvedType;
+		
+		// OK, the declaration site of the repeating annotation type as well as the use site where the annotations actually repeat pass muster. 
+		MethodBinding[] methods = containerAnnotationType.methods();
+		MemberValuePair pair = memberValuePairs()[0];
+		
+		for (int i = 0, length = methods.length; i < length; i++) {
+			MethodBinding method = methods[i];
+			if (CharOperation.equals(method.selector, TypeConstants.VALUE)) {
+				pair.binding = method;
+				pair.resolveTypeExpecting(scope, method.returnType);
+			}
+		}
+		this.compilerAnnotation = scope.environment().createAnnotation((ReferenceBinding) this.resolvedType, computeElementValuePairs());
+		return this.resolvedType;
+	}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
index bf1905c..693360a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -1110,9 +1110,7 @@
 	if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
 		if ((this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
 			// not interested in reporting problems against this.binding:
-//{ObjectTeams: added 2nd arg:
-			new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations, scope.environment())
-// SH}
+			new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations)
 					.checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope);
 		}
 		if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
index 7bff35e..819decd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
@@ -29,6 +29,7 @@
  *								Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled
  *								Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
  *								Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
+ *								Bug 416267 - NPE in QualifiedAllocationExpression.resolveType
  *     Jesper S Moller <jesper@selskabet.org> - Contributions for
  *								bug 378674 - "The method can be declared as static" is wrong
  *     Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
@@ -358,12 +359,7 @@
 		if(result != null && this.binding != null) {
 			final CompilerOptions compilerOptions = scope.compilerOptions();
 			if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
-//{ObjectTeams: added 2nd arg:
-/* orig:
-				new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations)
-  :giro */
-				new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations, scope.environment())
-// SH}
+				new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations)
 						.checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope);
 			}
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java
index 2eff389..abb6ad5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2013 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,6 +11,8 @@
  * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Jesper Steen Moller - Contributions for:
+ *          Bug 412149: [1.8][compiler] Emit repeated annotations into the designated container
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
@@ -30,6 +32,10 @@
 		this.sourceStart = sourceStart;
 		this.sourceEnd = type.sourceEnd;
 	}
+	
+	public SingleMemberAnnotation() {
+		// for subclasses.
+	}
 
 	public ElementValuePair[] computeElementValuePairs() {
 		return new ElementValuePair[] {memberValuePairs()[0].compilerElementPair};
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
index 4839f51..c51aeb0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
@@ -2323,6 +2323,9 @@
 	}
 }
 
+public boolean isPackageInfo() {
+	return CharOperation.equals(this.name,  TypeConstants.PACKAGE_INFO_NAME);
+}
 /**
  * Returns whether the type is a secondary one or not.
  */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java
index 582af65..227cd72 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java
@@ -142,9 +142,12 @@
 		BlockScope resolutionScope = Scope.typeAnnotationsResolutionScope(scope);
 		if (resolutionScope != null) {
 			AnnotationBinding [] annotationBindings = resolveAnnotations(resolutionScope, this.annotations, this.binding, false);
-			this.binding.setTypeAnnotations(annotationBindings, scope.environment().globalOptions.isAnnotationBasedNullAnalysisEnabled);
-			if (this.binding != null && this.binding.isValidBinding())
-				this.binding.evaluateNullAnnotations(scope, this);
+			if (annotationBindings != null && annotationBindings.length > 0) {
+				this.binding.setTypeAnnotations(annotationBindings, scope.environment().globalOptions.isAnnotationBasedNullAnalysisEnabled);
+				scope.referenceCompilationUnit().compilationResult.hasAnnotations = true;
+				if (this.binding != null && this.binding.isValidBinding())
+					this.binding.evaluateNullAnnotations(scope, this);
+			}
 		}	
 	}
 	/* (non-Javadoc)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java
index f94e742..b2028ac 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java
@@ -16,125 +16,92 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.util.Util;
-import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
 
 /* AnnotatableTypeSystem: Keep track of annotated types so as to provide unique bindings for identically annotated versions identical underlying "naked" types.
-   As of now, we ensure uniqueness only for marker annotated types, i.e two instances of @NonNull String would have the same binding, while @T(1) X and @T(2) X
-   will not. Binding uniqueness is only a memory optimization and is not essential for correctness of compilation. Various subsystems should expect to determine 
-   binding identity/equality by calling TypeBinding.equalsEquals and not by using == operator.
+   As of now, we ensure uniqueness only for marker annotated types and for others that default to all default attribute values, i.e two instances of @NonNull String 
+   would have the same binding, while @T(1) X and @T(2) X will not. Binding uniqueness is only a memory optimization and is not essential for correctness of compilation. 
+   Various subsystems should expect to determine binding identity/equality by calling TypeBinding.equalsEquals and not by using == operator.
  	
-   ATS is a superset of UTS and is not a subclass of UTS for obvious reasons. ATS maintains a handle to the UnannotatedTypeSystem over whose types ATS adds
-   annotations to create annotated types. ATS is AnnotatableTypeSystem and not AnnotatedTypeSystem, various methods may actually return unannotated types if the 
-   input arguments do not specify any annotations and component types of the composite type being constructed are themselves unannotated.
- 	
-   We do not keep track of unannotated types here, that is done by UTS whose handle we maintain.
+   ATS is AnnotatableTypeSystem and not AnnotatedTypeSystem, various methods may actually return unannotated types if the input arguments do not specify any annotations 
+   and component types of the composite type being constructed are themselves also unannotated. We rely on the master type table maintained by TypeSystem and use 
+   getDerivedTypes() and cacheDerivedType() to get/put.
 */
+
 public class AnnotatableTypeSystem extends TypeSystem {
 
-	LookupEnvironment environment;
-	UnannotatedTypeSystem unannotatedTypeSystem;
-	
-	private SimpleLookupTable annotatedTypes; // store of all annotated types created so far. Unlike earlier incarnation of LE, we maintain one look up table for all derived types.  
+	private LookupEnvironment environment;
+	private boolean isAnnotationBasedNullAnalysisEnabled;
 	
 	public AnnotatableTypeSystem(LookupEnvironment environment) {
+		super(environment);
 		this.environment = environment;
-		this.unannotatedTypeSystem = new UnannotatedTypeSystem(environment);
-		this.annotatedTypes = new SimpleLookupTable(16);
+		this.isAnnotationBasedNullAnalysisEnabled = environment.globalOptions.isAnnotationBasedNullAnalysisEnabled;
 	}
 	
-	public TypeBinding getUnannotatedType(TypeBinding type) {
-		return this.unannotatedTypeSystem.getUnannotatedType(type);
-	}
-	
-	// Given a type, return all its variously annotated versions.
+	// Given a type, return all its annotated variants: parameter may be annotated.
 	public TypeBinding[] getAnnotatedTypes(TypeBinding type) {
 		
-		TypeBinding keyType = getUnannotatedType(type);
-		TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(keyType);
-		if (cachedInfo == null)
-			return Binding.NO_TYPES;
-		
-		final int length = cachedInfo.length;
+		TypeBinding[] derivedTypes = getDerivedTypes(type);
+		final int length = derivedTypes.length;
 		TypeBinding [] annotatedVersions = new TypeBinding[length];
 		int versions = 0;
 		for (int i = 0; i < length; i++) {
-			final TypeBinding cachedType = cachedInfo[i];
-			if (cachedType == null)
+			final TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null)
 				break;
-			if (cachedType.id == type.id)
-				annotatedVersions[versions++] = cachedType;
+			if (!derivedType.hasTypeAnnotations())
+				continue;
+			if (derivedType.id == type.id)
+				annotatedVersions[versions++] = derivedType;
 		}
 		
-		if (versions == 0)
-			return Binding.NO_TYPES;
-		
 		if (versions != length)
 			System.arraycopy(annotatedVersions, 0, annotatedVersions = new TypeBinding[versions], 0, versions);
-			
 		return annotatedVersions;
 	}
 	
+	/* This method replaces the version that used to sit in LE. The parameter `annotations' is a flattened sequence of annotations, 
+	   where each dimension's annotations end with a sentinel null. Leaf type can be an already annotated type.
+	*/
+	public ArrayBinding getArrayType(TypeBinding leafType, int dimensions, AnnotationBinding [] annotations) {
+		
+		ArrayBinding nakedType = null;
+		TypeBinding[] derivedTypes = getDerivedTypes(leafType);
+		for (int i = 0, length = derivedTypes.length; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null) break;
+			if (!derivedType.isArrayType() || derivedType.dimensions() != dimensions || derivedType.leafComponentType() != leafType)
+				continue;
+			if (Util.effectivelyEqual(derivedType.getTypeAnnotations(), annotations)) 
+				return (ArrayBinding) derivedType;
+			if (!derivedType.hasTypeAnnotations())
+				nakedType = (ArrayBinding) derivedType;
+		}
+		if (nakedType == null)
+			nakedType = super.getArrayType(leafType, dimensions);
+		
+		if (!haveTypeAnnotations(leafType, annotations))
+			return nakedType;
+
+		ArrayBinding arrayType = new ArrayBinding(leafType, dimensions, this.environment);
+		arrayType.id = nakedType.id;
+		arrayType.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
+		return (ArrayBinding) cacheDerivedType(leafType, nakedType, arrayType);
+	}
+
 	public ArrayBinding getArrayType(TypeBinding leaftType, int dimensions) {
 		return getArrayType(leaftType, dimensions, Binding.NO_ANNOTATIONS);
 	}
 
-	/* This method replaces the version that used to sit in LE. The parameter `annotations' is a flattened sequence of annotations, 
-	   where each dimension's annotations end with a sentinel null.
-	*/
-	public ArrayBinding getArrayType(TypeBinding leafComponentType, int dimensions, AnnotationBinding [] annotations) {
-		
-		if (!haveTypeAnnotations(leafComponentType, annotations))
-			return this.unannotatedTypeSystem.getArrayType(leafComponentType, dimensions);
-		
-		//  Leaf component type can be an annotated type.
-		TypeBinding keyType = getUnannotatedType(leafComponentType);
-		TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(keyType);  // unannotated key promotes better instance sharing.
-		int index = 0;
-		if (cachedInfo != null) {
-			for (int max = cachedInfo.length; index < max; index++) {
-				TypeBinding cachedType = cachedInfo[index];
-				if (cachedType == null) break;
-				if (cachedType.leafComponentType() != leafComponentType) continue;
-				if (cachedType.isArrayType() && cachedType.dimensions() == dimensions && Util.effectivelyEqual(cachedType.getTypeAnnotations(), annotations)) 
-					return (ArrayBinding) cachedType;
-			}
-		} else {
-			this.annotatedTypes.put(keyType, cachedInfo = new TypeBinding[4]);
-		}
-		
-		int length = cachedInfo.length;
-		if (index == length) {
-			System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length);
-			this.annotatedTypes.put(keyType, cachedInfo);
-		}
-		// Add the newcomer, ensuring its identity is the same as the naked version of it.
-		ArrayBinding unannotatedArrayType = this.unannotatedTypeSystem.getArrayType(leafComponentType, dimensions);
-		TypeBinding arrayBinding = new ArrayBinding(leafComponentType, dimensions, this.environment);
-		arrayBinding.id = unannotatedArrayType.id;
-		arrayBinding.setTypeAnnotations(annotations, this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled);
-		return (ArrayBinding) (cachedInfo[index] = arrayBinding);
-	}
-	
 	public ReferenceBinding getMemberType(ReferenceBinding memberType, ReferenceBinding enclosingType) {
 		if (!haveTypeAnnotations(memberType, enclosingType))
-			return this.unannotatedTypeSystem.getMemberType(memberType, enclosingType);
-		return (ReferenceBinding) getAnnotatedType(memberType, enclosingType, memberType.typeArguments(), memberType.getTypeAnnotations());
+			return super.getMemberType(memberType, enclosingType);
+		return (ReferenceBinding) getAnnotatedType(memberType, enclosingType, memberType.getTypeAnnotations());
 	}
 	
-//{ObjectTeams: 2 args added for role types:
-/* orig:
-	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) {
-		return getParameterizedType(genericType, typeArguments, enclosingType, Binding.NO_ANNOTATIONS);
-  :giro */
-	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments,
-			ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType) {
-		return getParameterizedType(genericType, typeArguments, teamAnchor, valueParamPosition, enclosingType, Binding.NO_ANNOTATIONS);
-// SH}
-	}
-
 //{ObjectTeams: more arguments for role types:
 /* orig:
 	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding [] annotations) {
@@ -143,56 +110,54 @@
 			ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType, AnnotationBinding [] annotations) {
 		if (teamAnchor == null && genericType instanceof DependentTypeBinding)
 			teamAnchor = ((DependentTypeBinding) genericType)._teamAnchor;
-/* orig:
-		if (!haveTypeAnnotations(genericType, enclosingType, typeArguments, annotations))
-			return this.unannotatedTypeSystem.getParameterizedType(genericType, typeArguments, enclosingType);
-  :giro */
-		if (!haveTypeAnnotations(genericType, enclosingType, typeArguments, annotations))
-			return this.unannotatedTypeSystem.getParameterizedType(genericType, typeArguments, teamAnchor, valueParamPosition, enclosingType);
 // SH}
 		
-		if (genericType.hasTypeAnnotations())
+		if (genericType.hasTypeAnnotations())   // @NonNull (List<String>) and not (@NonNull List)<String>
 			throw new IllegalStateException();
-		
-		int index = 0;
-		TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(genericType);
-		if (cachedInfo != null) {
-			for (int max = cachedInfo.length; index < max; index++){
-				TypeBinding cachedType = cachedInfo[index];
-				if (cachedType == null) 
-					break;
+
+		ParameterizedTypeBinding nakedType = null;
+		TypeBinding[] derivedTypes = getDerivedTypes(genericType);
+		for (int i = 0, length = derivedTypes.length; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null)
+				break;
 //{ObjectTeams: parameterized and/or anchored?
 /* orig:
-				if (!cachedType.isParameterizedType())
-					continue;
+			if (!derivedType.isParameterizedType() || derivedType.actualType() != genericType)
+				continue;
   :giro */
-				if (!(cachedType instanceof ParameterizedTypeBinding)) // roles might answer 'false' to isParameterized(), still they are valid candidates, here
-					continue;
-				if (cachedType.isRawType() && typeArguments != null)
-					continue;
-				// also match team anchor if given:
-				if (!this.unannotatedTypeSystem.isRoleTypeMatch(teamAnchor, valueParamPosition, cachedType))
-					continue;
+			if (!(derivedType instanceof ParameterizedTypeBinding)) // roles might answer 'false' to isParameterized(), still they are valid candidates, here
+				continue;
+			if (derivedType.actualType() != genericType)
+				continue;
+			if (derivedType.isRawType() && typeArguments != null)
+				continue;
+			// also match team anchor if given:
+			if (!isRoleTypeMatch(teamAnchor, valueParamPosition, derivedType))
+				continue;
+//SH}
+			if (derivedType.enclosingType() != enclosingType || !Util.effectivelyEqual(derivedType.typeArguments(), typeArguments))
+				continue;
+			if (Util.effectivelyEqual(annotations, derivedType.getTypeAnnotations()))
+				return (ParameterizedTypeBinding) derivedType;
+			if (!derivedType.hasTypeAnnotations())
+				nakedType = (ParameterizedTypeBinding) derivedType;
+		}
+		if (nakedType == null)
+//{ObjectTeams: all parameters:
+/* orig:
+			nakedType = super.getParameterizedType(genericType, typeArguments, enclosingType);
+  :orig */
+			nakedType = super.getParameterizedType(genericType, typeArguments, teamAnchor, valueParamPosition, enclosingType);
 // SH}
-				if (cachedType.enclosingType() == enclosingType && Util.effectivelyEqual(annotations, cachedType.getTypeAnnotations()) && Util.effectivelyEqual(cachedType.typeArguments(), typeArguments))
-					return (ParameterizedTypeBinding) cachedType;
-			}
-		} else {
-			this.annotatedTypes.put(genericType, cachedInfo = new TypeBinding[4]);
-		}
-		int length = cachedInfo.length;
-		if (index == length) {
-			System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length);
-			this.annotatedTypes.put(genericType, cachedInfo);
-		}
-		// Add the new comer, retaining the same type binding id as the naked type.
+		
+		if (!haveTypeAnnotations(genericType, enclosingType, typeArguments, annotations))
+			return nakedType;
+		
 //{ObjectTeams: dependent type?
 /* orig:	
-		ParameterizedTypeBinding unannotatedParameterizedType = this.unannotatedTypeSystem.getParameterizedType(genericType, typeArguments, enclosingType);
 		TypeBinding parameterizedType = new ParameterizedTypeBinding(genericType, typeArguments, enclosingType, this.environment);
   :giro */
-		ParameterizedTypeBinding unannotatedParameterizedType = this.unannotatedTypeSystem.getParameterizedType(genericType, typeArguments,
-																	teamAnchor, valueParamPosition, enclosingType);
 		ParameterizedTypeBinding parameterizedType;
 		if (teamAnchor == null) {
 			parameterizedType = new ParameterizedTypeBinding(genericType,typeArguments, enclosingType, this.environment);
@@ -204,129 +169,92 @@
 			}
 		}
 // SH}
-		parameterizedType.id = unannotatedParameterizedType.id;
-		parameterizedType.setTypeAnnotations(annotations, this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled);
-		return (ParameterizedTypeBinding) (cachedInfo[index] = parameterizedType);
+		parameterizedType.id = nakedType.id;
+		parameterizedType.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
+		return (ParameterizedTypeBinding) cacheDerivedType(genericType, nakedType, parameterizedType);
+	}
+	
+	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) {
+//{ObjectTeams: more args (default values):
+/*orig:
+		return getParameterizedType(genericType, typeArguments, enclosingType, Binding.NO_ANNOTATIONS);
+  :giro */
+		return getParameterizedType(genericType, typeArguments, null, -1, enclosingType, Binding.NO_ANNOTATIONS);
+// SH}
+	}
+
+	public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType, AnnotationBinding [] annotations) {
+		
+		if (genericType.hasTypeAnnotations())
+			throw new IllegalStateException();
+		
+		RawTypeBinding nakedType = null;
+		TypeBinding[] derivedTypes = getDerivedTypes(genericType);
+		for (int i = 0, length = derivedTypes.length; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null)
+				break;
+			if (!derivedType.isRawType() || derivedType.actualType() != genericType || derivedType.enclosingType() != enclosingType)
+				continue;
+			if (Util.effectivelyEqual(derivedType.getTypeAnnotations(), annotations))
+				return (RawTypeBinding) derivedType;
+			if (!derivedType.hasTypeAnnotations())
+				nakedType = (RawTypeBinding) derivedType;
+		}
+		if (nakedType == null)
+			nakedType = super.getRawType(genericType, enclosingType);
+		
+		if (!haveTypeAnnotations(genericType, enclosingType, null, annotations))
+			return nakedType;
+	
+		RawTypeBinding rawType = new RawTypeBinding(genericType, enclosingType, this.environment);
+		rawType.id = nakedType.id;
+		rawType.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
+		return (RawTypeBinding) cacheDerivedType(genericType, nakedType, rawType);
 	}
 	
 	public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) {
 		return getRawType(genericType, enclosingType, Binding.NO_ANNOTATIONS);
 	}
 	
-	public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType, AnnotationBinding [] annotations) {
-		
-		if (!haveTypeAnnotations(genericType, enclosingType, null, annotations))
-			return this.unannotatedTypeSystem.getRawType(genericType, enclosingType);
-		
-		if (genericType.hasTypeAnnotations())
-			throw new IllegalStateException();
-		
-		TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(genericType);
-		int index = 0;
-		if (cachedInfo != null) {
-			for (int max = cachedInfo.length; index < max; index++) {
-				TypeBinding cachedType = cachedInfo[index];
-				if (cachedType == null)
-					break;
-				if (cachedType.isRawType() && cachedType.enclosingType() == enclosingType && Util.effectivelyEqual(cachedType.getTypeAnnotations(), annotations))
-					return (RawTypeBinding) cachedType;
-			}
-		} else {
-			this.annotatedTypes.put(genericType, cachedInfo = new TypeBinding[4]);
-		}
-		
-		int length = cachedInfo.length;
-		if (index == length) {
-			System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length);
-			this.annotatedTypes.put(genericType, cachedInfo);
-		}
-		// Add the new comer, retaining the same type binding id as the naked type.
-		RawTypeBinding unannotatedRawType = this.unannotatedTypeSystem.getRawType(genericType, enclosingType);
-		TypeBinding rawType = new RawTypeBinding(genericType, enclosingType, this.environment);
-		rawType.id = unannotatedRawType.id;
-		rawType.setTypeAnnotations(annotations, this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled);
-		return (RawTypeBinding) (cachedInfo[index] = rawType);
-	}
-		
-	public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) {
-		return getWildcard(genericType, rank, bound, otherBounds, boundKind, Binding.NO_ANNOTATIONS);
-	}
-
 	public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind, AnnotationBinding [] annotations) {
 		
-		if (!haveTypeAnnotations(genericType, bound, otherBounds, annotations))
-			return this.unannotatedTypeSystem.getWildcard(genericType, rank, bound, otherBounds, boundKind);
-		
 		if (genericType == null) // pseudo wildcard denoting composite bounds for lub computation
 			genericType = ReferenceBinding.LUB_GENERIC;
 
 		if (genericType.hasTypeAnnotations())
 			throw new IllegalStateException();
 		
-		TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(genericType);  // promotes better instance sharing.
-		int index = 0;
-		if (cachedInfo != null) {
-			for (int max = cachedInfo.length; index < max; index++) {
-				TypeBinding cachedType = cachedInfo[index];
-				if (cachedType == null) 
-					break;
-				if (!cachedType.isWildcard())
-					continue;
-				if (cachedType.rank() != rank || cachedType.boundKind() != boundKind || cachedType.bound() != bound)
-					continue;
-				if (Util.effectivelyEqual(cachedType.additionalBounds(), otherBounds) && Util.effectivelyEqual(cachedType.getTypeAnnotations(), annotations))
-					return (WildcardBinding) cachedType;
-			}
-		} else {
-			this.annotatedTypes.put(genericType, cachedInfo = new TypeBinding[4]);
+		WildcardBinding nakedType = null;
+		TypeBinding[] derivedTypes = getDerivedTypes(genericType);
+		for (int i = 0, length = derivedTypes.length; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null) 
+				break;
+			if (!derivedType.isWildcard() || derivedType.actualType() != genericType || derivedType.rank() != rank)
+				continue;
+			if (derivedType.boundKind() != boundKind || derivedType.bound() != bound || !Util.effectivelyEqual(derivedType.additionalBounds(), otherBounds))
+				continue;
+			if (Util.effectivelyEqual(derivedType.getTypeAnnotations(), annotations))
+				return (WildcardBinding) derivedType;
+			if (!derivedType.hasTypeAnnotations())
+				nakedType = (WildcardBinding) derivedType;
 		}
-
-		int length = cachedInfo.length;
-		if (index == length) {
-			System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length);
-			this.annotatedTypes.put(genericType, cachedInfo);
-		}
-		// Add the new comer, retaining the same type binding id as the naked type.
-		TypeBinding unannotatedWildcard = this.unannotatedTypeSystem.getWildcard(genericType, rank, bound, otherBounds, boundKind);
-		TypeBinding wildcard = new WildcardBinding(genericType, rank, bound, otherBounds, boundKind, this.environment);
-		wildcard.id = unannotatedWildcard.id;
-		wildcard.setTypeAnnotations(annotations, this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled);
-		return (WildcardBinding) (cachedInfo[index] = wildcard);
+		
+		if (nakedType == null)
+			nakedType = super.getWildcard(genericType, rank, bound, otherBounds, boundKind);
+		
+		if (!haveTypeAnnotations(genericType, bound, otherBounds, annotations))
+			return nakedType;
+		
+		WildcardBinding wildcard = new WildcardBinding(genericType, rank, bound, otherBounds, boundKind, this.environment);
+		wildcard.id = nakedType.id;
+		wildcard.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
+		return (WildcardBinding) cacheDerivedType(genericType, nakedType, wildcard);
 	}
 
-	// Private subroutine for public APIs.
-	private TypeBinding getAnnotatedType(TypeBinding type, TypeBinding enclosingType, TypeBinding [] typeArguments, AnnotationBinding[] annotations) {
-		TypeBinding keyType = getUnannotatedType(type);
-		TypeBinding[] cachedInfo = (TypeBinding[]) this.annotatedTypes.get(keyType);
-		int i = 0;
-		if (cachedInfo != null) {
-			for (int length = cachedInfo.length; i < length; i++) {
-				TypeBinding cachedType = cachedInfo[i];
-				if (cachedType == null) break;
-				if (cachedType.enclosingType() == enclosingType) {
-					if (Util.effectivelyEqual(cachedType.getTypeAnnotations(), annotations) && Util.effectivelyEqual(cachedType.typeArguments(), typeArguments)) {
-						return cachedType;
-					}
-				}
-			}
-		} else {
-			this.annotatedTypes.put(keyType, cachedInfo = new TypeBinding[4]);
-		}
-		int length = cachedInfo.length;
-		if (i == length) {
-			System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length);
-			this.annotatedTypes.put(keyType, cachedInfo);
-		}
-		/* Add the new comer, retaining the same type binding id as the naked type. To materialize the new comer we can't use new since this is a general
-		   purpose method designed to deal type bindings of all types. "Clone" the incoming type, specializing for any enclosing type that may itself be 
-		   possibly be annotated. This is so the binding for @Outer Outer.Inner != Outer.@Inner Inner != @Outer Outer.@Inner Inner. Likewise so the bindings 
-		   for @Readonly List<@NonNull String> != @Readonly List<@Nullable String> != @Readonly List<@Interned String> 
-		*/
-		TypeBinding unannotatedType = this.unannotatedTypeSystem.getUnannotatedType(type);
-		TypeBinding annotatedType = type.clone(enclosingType);
-		annotatedType.id = unannotatedType.id;
-		annotatedType.setTypeAnnotations(annotations, this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled);
-		return cachedInfo[i] = annotatedType;
+	public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) {
+		return getWildcard(genericType, rank, bound, otherBounds, boundKind, Binding.NO_ANNOTATIONS);
 	}
 
 	/* Take a type and apply annotations to various components of it. By construction when we see the type reference @Outer Outer.@Middle Middle.@Inner Inner,
@@ -353,9 +281,9 @@
 				/* Taking the binding of QTR as an example, there could be different annotatable components, but we come in a with a single binding, e.g: 
 				   @T Z;                                      type => Z  annotations => [[@T]]
 				   @T Y.@T Z                                  type => Z  annotations => [[@T][@T]]
-				   @T X.@T Y.@T Z                             type => Z  annotations => [[][][@T][@T][@T]] 
-				   java.lang.@T X.@T Y.@T Z
-				   in all these cases the incoming type binding is for Z, but annotations are for different levels. Align their layout for proper attribution.
+				   @T X.@T Y.@T Z                             type => Z  annotations => [[@T][@T][@T]] 
+				   java.lang.@T X.@T Y.@T Z                   type => Z  annotations => [[][][@T][@T][@T]]
+				   in all these cases the incoming type binding is for Z, but annotations are for different levels. We need to align their layout for proper attribution.
 				 */
 				
 				if (type.isUnresolvedType() && CharOperation.indexOf('$', type.sourceName()) > 0)
@@ -383,7 +311,7 @@
 					final TypeBinding currentType = types[j];
 					// while handling annotations from SE7 locations, take care not to drop existing annotations.
 					AnnotationBinding [] currentAnnotations = annotations[i] != null && annotations[i].length > 0 ? annotations[i] : currentType.getTypeAnnotations();
-					annotatedType = getAnnotatedType(currentType, enclosingType, currentType.typeArguments(), currentAnnotations);
+					annotatedType = getAnnotatedType(currentType, enclosingType, currentAnnotations);
 					enclosingType = annotatedType;
 				}
 				break;
@@ -393,8 +321,80 @@
 		return annotatedType;
 	}
 
-	public AnnotationBinding getAnnotationType(ReferenceBinding annotationType, boolean requireResolved) {
-		return this.unannotatedTypeSystem.getAnnotationType(annotationType, requireResolved); // deflect, annotation type uses cannot be type annotated.
+	/* Private subroutine for public APIs. Create an annotated version of the type. To materialize the annotated version, we can't use new since 
+	   this is a general purpose method designed to deal type bindings of all types. "Clone" the incoming type, specializing for any enclosing type 
+	   that may itself be possibly be annotated. This is so the binding for @Outer Outer.Inner != Outer.@Inner Inner != @Outer Outer.@Inner Inner. 
+	   Likewise so the bindings for @Readonly List<@NonNull String> != @Readonly List<@Nullable String> != @Readonly List<@Interned String> 
+	*/
+	private TypeBinding getAnnotatedType(TypeBinding type, TypeBinding enclosingType, AnnotationBinding[] annotations) {
+		TypeBinding nakedType = null;
+		TypeBinding[] derivedTypes = getDerivedTypes(type);
+		for (int i = 0, length = derivedTypes.length; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null) break;
+			
+			if (derivedType.enclosingType() != enclosingType || !Util.effectivelyEqual(derivedType.typeArguments(), type.typeArguments()))
+				continue;
+			
+			switch(type.kind()) {
+				case Binding.ARRAY_TYPE:
+					if (!derivedType.isArrayType() || derivedType.dimensions() != type.dimensions() || derivedType.leafComponentType() != type.leafComponentType())
+						continue;
+					break;
+				case Binding.PARAMETERIZED_TYPE:
+					if (!derivedType.isParameterizedType() || derivedType.actualType() != type.actualType())
+						continue;
+					break;
+				case Binding.RAW_TYPE:
+					if (!derivedType.isRawType() || derivedType.actualType() != type.actualType())
+						continue;
+					break;
+				case Binding.WILDCARD_TYPE:
+					if (!derivedType.isWildcard() || derivedType.actualType() != type.actualType() || derivedType.rank() != type.rank() || derivedType.boundKind() != type.boundKind())
+						continue;
+					if (derivedType.bound() != type.bound() || !Util.effectivelyEqual(derivedType.additionalBounds(), type.additionalBounds()))
+						continue;
+					break;
+				default:
+					switch(derivedType.kind()) {
+						case Binding.ARRAY_TYPE:
+						case Binding.PARAMETERIZED_TYPE:
+						case Binding.RAW_TYPE:
+						case Binding.WILDCARD_TYPE:
+							continue;
+					}
+					break;
+			}
+			if (Util.effectivelyEqual(derivedType.getTypeAnnotations(), annotations)) {
+				return derivedType;
+			}
+			if (!derivedType.hasTypeAnnotations())
+				nakedType = derivedType;
+		}
+		if (nakedType == null)
+			nakedType = getUnannotatedType(type);
+		
+		if (!haveTypeAnnotations(type, enclosingType, null, annotations))
+			return nakedType;
+		
+		TypeBinding annotatedType = type.clone(enclosingType);
+		annotatedType.id = nakedType.id;
+		annotatedType.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
+		TypeBinding keyType;
+		switch (type.kind()) {
+			case Binding.ARRAY_TYPE:
+				keyType = type.leafComponentType();
+				break;
+			case Binding.PARAMETERIZED_TYPE:
+			case Binding.RAW_TYPE:
+			case Binding.WILDCARD_TYPE:
+				keyType = type.actualType();
+				break;
+			default:
+				keyType = nakedType;
+				break;
+		}
+		return cacheDerivedType(keyType, nakedType, annotatedType);
 	}
 
 	private boolean haveTypeAnnotations(TypeBinding baseType, TypeBinding someType, TypeBinding[] someTypes, AnnotationBinding[] annotations) {
@@ -451,25 +451,7 @@
 		return series;
 	}
 
-	public final void reset() { // develop amnesia 
-		this.annotatedTypes = new SimpleLookupTable(16);
-		this.unannotatedTypeSystem.reset();
-	}
-
-	public void updateCaches(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) {
-		if (this.annotatedTypes.get(unresolvedType) != null) { // update the key
-			Object[] keys = this.annotatedTypes.keyTable;
-			for (int i = 0, l = keys.length; i < l; i++) {
-				if (keys[i] == unresolvedType) {
-					keys[i] = resolvedType; // hashCode is based on compoundName so this works.
-					break;
-				}
-			}
-		}
-		this.unannotatedTypeSystem.updateCaches(unresolvedType.prototype, unresolvedType.prototype.resolvedType);
-	}
-	
 	public boolean isAnnotatedTypeSystem() {
 		return true;
 	}
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java
index e9f1d86..b2c9001 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java
@@ -171,7 +171,7 @@
 			});
 }
 
-AnnotationBinding(ReferenceBinding type, ElementValuePair[] pairs) {
+public AnnotationBinding(ReferenceBinding type, ElementValuePair[] pairs) {
 	this.type = type;
 	this.pairs = pairs;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
index 5238d00..72b2335 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
@@ -19,7 +19,7 @@
 
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 
-public final class BaseTypeBinding extends TypeBinding {
+public class BaseTypeBinding extends TypeBinding {
 
 	public static final int[] CONVERSIONS;
 	public static final int IDENTITY = 1;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
index 4c92d8b..efb4b8e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
@@ -142,7 +142,7 @@
 
 	protected SimpleLookupTable storedAnnotations = null; // keys are this ReferenceBinding & its fields and methods, value is an AnnotationHolder
 
-	private ReferenceBinding containingAnnotation;
+	private ReferenceBinding containerAnnotationType;
 
 //{ObjectTeams: support callout-to-field
 
@@ -239,7 +239,7 @@
 
 	char[] typeName = annotationInfo.getTypeName();
 	ReferenceBinding annotationType = env.getTypeFromConstantPoolName(typeName, 1, typeName.length - 1, false, missingTypeNames);
-	return new UnresolvedAnnotationBinding(annotationType, pairs, env);
+	return env.createUnresolvedAnnotation(annotationType, pairs);
 }
 
 public static AnnotationBinding[] createAnnotations(IBinaryAnnotation[] annotationInfos, LookupEnvironment env, char[][][] missingTypeNames) {
@@ -366,7 +366,7 @@
  */
 public FieldBinding[] availableFields() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.AreFieldsComplete) != 0)
 			return this.fields;
 		return this.prototype.availableFields();
@@ -398,7 +398,7 @@
 }
 
 private TypeVariableBinding[] addMethodTypeVariables(TypeVariableBinding[] methodTypeVars) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.typeVariables == null || this.typeVariables == Binding.NO_TYPE_VARIABLES) {
 		return methodTypeVars;
 	} 
@@ -428,7 +428,7 @@
  */
 public MethodBinding[] availableMethods() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.AreMethodsComplete) != 0)
 			return this.methods;
 		return this.prototype.availableMethods();
@@ -460,7 +460,7 @@
 }
 
 void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	try {
 		// default initialization for super-interfaces early, in case some aborting compilation error occurs,
 		// and still want to use binaries passed that point (e.g. type hierarchy resolver, see bug 63748).
@@ -674,7 +674,7 @@
 }
 
 private TypeAnnotationWalker getTypeAnnotationWalker(IBinaryTypeAnnotation[] annotations) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (annotations == null || annotations.length == 0)
 		return TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER;
 	
@@ -682,7 +682,7 @@
 }
 
 private void createFields(IBinaryField[] iFields, long sourceLevel, char[][][] missingTypeNames) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	this.fields = Binding.NO_FIELDS;
 	if (iFields != null) {
 		int size = iFields.length;
@@ -775,7 +775,7 @@
   MethodBinding result = null;
   try {
 // SH}
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	int methodModifiers = method.getModifiers() | ExtraCompilerModifiers.AccUnresolved;
 	if (sourceLevel < ClassFileConstants.JDK1_5)
 		methodModifiers &= ~ClassFileConstants.AccVarargs; // vararg methods are not recognized until 1.5
@@ -1031,7 +1031,7 @@
  * iMethods for which MethodBindings have been created; indices match those in this.methods.
  */
 private IBinaryMethod[] createMethods(IBinaryMethod[] iMethods, long sourceLevel, char[][][] missingTypeNames) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	int total = 0, initialTotal = 0, iClinit = -1;
 	int[] toSkip = null;
 	if (iMethods != null) {
@@ -1110,7 +1110,7 @@
 private TypeVariableBinding[] createTypeVariables(SignatureWrapper wrapper, boolean assignVariables, char[][][] missingTypeNames,
 													TypeAnnotationWalker walker, boolean isClassTypeParameter)
 {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	// detect all type variables first
 	char[] typeSignature = wrapper.signature;
 	int depth = 0, length = typeSignature.length;
@@ -1176,7 +1176,7 @@
 // NOTE: the type of each field of a binary type is resolved when needed
 public FieldBinding[] fields() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.AreFieldsComplete) != 0)
 			return this.fields;
 		this.fields = this.prototype.fields();
@@ -1201,7 +1201,7 @@
 }
 
 private MethodBinding findMethod(char[] methodDescriptor, char[][][] missingTypeNames) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	int index = -1;
 	while (methodDescriptor[++index] != Util.C_PARAM_START) {
 		// empty
@@ -1267,7 +1267,7 @@
  * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#genericTypeSignature()
  */
 public char[] genericTypeSignature() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.computeGenericTypeSignature(this.typeVariables);
 	return computeGenericTypeSignature(this.typeVariables);
 }
@@ -1275,7 +1275,7 @@
 //NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
 public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
 
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getExactConstructor(argumentTypes);
 
 	// lazily sort methods
@@ -1313,7 +1313,7 @@
 public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes, CompilationUnitScope refScope) {
 	// sender from refScope calls recordTypeReference(this)
 
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getExactMethod(selector, argumentTypes, refScope);
 
 	// lazily sort methods
@@ -1379,7 +1379,7 @@
 //NOTE: the type of a field of a binary type is resolved when needed
 public FieldBinding getField(char[] fieldName, boolean needResolve) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getField(fieldName, needResolve);
 
 	// lazily sort fields
@@ -1397,7 +1397,7 @@
  */
 public ReferenceBinding getMemberType(char[] typeName) {
 
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		ReferenceBinding memberType = this.prototype.getMemberType(typeName);
 		return memberType == null ? null : this.environment.createMemberType(memberType, this);
 	}
@@ -1452,7 +1452,7 @@
 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
 public MethodBinding[] getMethods(char[] selector) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getMethods(selector);
 
 	if ((this.tagBits & TagBits.AreMethodsComplete) != 0) {
@@ -1492,7 +1492,7 @@
 // The suggested parameter length is optional and may not be guaranteed by every type.
 public MethodBinding[] getMethods(char[] selector, int suggestedParameterLength) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getMethods(selector, suggestedParameterLength);
 
 	if ((this.tagBits & TagBits.AreMethodsComplete) != 0)
@@ -1538,7 +1538,7 @@
 }
 // NOTE: member types of binary types are resolved when needed
 public TypeVariableBinding getTypeVariable(char[] variableName) {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getTypeVariable(variableName);
 
 	TypeVariableBinding variable = super.getTypeVariable(variableName);
@@ -1547,7 +1547,7 @@
 }
 public boolean hasTypeBit(int bit) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.hasTypeBit(bit);
 	
 	// ensure hierarchy is resolved, which will propagate bits down to us
@@ -1562,7 +1562,7 @@
 	return (this.typeBits & bit) != 0;
 }
 private void initializeTypeVariable(TypeVariableBinding variable, TypeVariableBinding[] existingVariables, SignatureWrapper wrapper, char[][][] missingTypeNames, TypeAnnotationWalker walker) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	// ParameterSignature = Identifier ':' TypeSignature
 	//   or Identifier ':' TypeSignature(optional) InterfaceBound(s)
 	// InterfaceBound = ':' TypeSignature
@@ -1631,25 +1631,25 @@
 }
 public boolean isGenericType() {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.isGenericType();
 	
     return this.typeVariables != Binding.NO_TYPE_VARIABLES;
 }
 public boolean isHierarchyConnected() {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.isHierarchyConnected();
 	
 	return (this.tagBits & (TagBits.HasUnresolvedSuperclass | TagBits.HasUnresolvedSuperinterfaces)) == 0;
 }
-public boolean isRepeatableAnnotation() {
-	if (this != this.prototype) throw new IllegalStateException();
-	return this.containingAnnotation != null;
+public boolean isRepeatableAnnotationType() {
+	if (!isPrototype()) throw new IllegalStateException();
+	return this.containerAnnotationType != null;
 }
 public int kind() {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.kind();
 	
 	if (this.typeVariables != Binding.NO_TYPE_VARIABLES)
@@ -1658,7 +1658,7 @@
 }
 // NOTE: member types of binary types are resolved when needed
 public ReferenceBinding[] memberTypes() {
- 	if (this != this.prototype) {
+ 	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.HasUnresolvedMemberTypes) == 0)
 			return this.memberTypes;
 		ReferenceBinding [] members = this.prototype.memberTypes();
@@ -1683,7 +1683,7 @@
 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
 public MethodBinding[] methods() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.AreMethodsComplete) != 0)
 			return this.methods;
 		this.methods = this.prototype.methods();
@@ -1711,17 +1711,21 @@
 	return this.prototype;
 }
 
-public ReferenceBinding resolveContainerAnnotation() {
-	if (this != this.prototype) throw new IllegalStateException();
-	if (this.containingAnnotation instanceof UnresolvedReferenceBinding) {
-		this.containingAnnotation = (ReferenceBinding) BinaryTypeBinding.resolveType(this.containingAnnotation, this.environment, false);
+private boolean isPrototype() {
+	return this == this.prototype; //$IDENTITY-COMPARISON$
+}
+
+public ReferenceBinding containerAnnotationType() {
+	if (!isPrototype()) throw new IllegalStateException();
+	if (this.containerAnnotationType instanceof UnresolvedReferenceBinding) {
+		this.containerAnnotationType = (ReferenceBinding) BinaryTypeBinding.resolveType(this.containerAnnotationType, this.environment, false);
 	}
-	return this.containingAnnotation;
+	return this.containerAnnotationType;
 }
 
 private FieldBinding resolveTypeFor(FieldBinding field) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.resolveTypeFor(field);
 	
 	if ((field.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)
@@ -1755,7 +1759,7 @@
 }
 MethodBinding resolveTypesFor(MethodBinding method) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.resolveTypesFor(method);
 	
 	if ((method.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)
@@ -1806,18 +1810,25 @@
 // SH}
 AnnotationBinding[] retrieveAnnotations(Binding binding) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.retrieveAnnotations(binding);
 	
 	return AnnotationBinding.addStandardAnnotations(super.retrieveAnnotations(binding), binding.getAnnotationTagBits(), this.environment);
 }
-public void setContainingAnnotation(ReferenceBinding value) {
-	if (this != this.prototype) throw new IllegalStateException();
-	this.containingAnnotation = value;
+
+public void setContainerAnnotationType(ReferenceBinding value) {
+	if (!isPrototype()) throw new IllegalStateException();
+	this.containerAnnotationType = value;
 }
+
+public void tagAsHavingDefectiveContainerType() {
+	if (this.containerAnnotationType != null && this.containerAnnotationType.isValidBinding())
+		this.containerAnnotationType = new ProblemReferenceBinding(this.containerAnnotationType.compoundName, this.containerAnnotationType, ProblemReasons.DefectiveContainerAnnotationType);
+}
+
 SimpleLookupTable storedAnnotations(boolean forceInitialize) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.storedAnnotations(forceInitialize);
 	
 	if (forceInitialize && this.storedAnnotations == null) {
@@ -1832,7 +1843,7 @@
 }
 
 private void scanFieldForNullAnnotation(IBinaryField field, FieldBinding fieldBinding) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.environment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8) {
 		TypeBinding fieldType = fieldBinding.type;
 		if (fieldType != null
@@ -1879,7 +1890,7 @@
 }
 
 private void scanMethodForNullAnnotation(IBinaryMethod method, MethodBinding methodBinding) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (!this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled)
 		return;
 	boolean useTypeAnnotations = this.environment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8;
@@ -1950,7 +1961,7 @@
 	}
 }
 private void scanTypeForNullDefaultAnnotation(IBinaryType binaryType, PackageBinding packageBinding, BinaryTypeBinding binaryBinding) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	char[][] nonNullByDefaultAnnotationName = this.environment.getNonNullByDefaultAnnotationName();
 	if (nonNullByDefaultAnnotationName == null)
 		return; // not well-configured to use null annotations
@@ -2027,7 +2038,7 @@
 }
 
 private void scanTypeForContainerAnnotation(IBinaryType binaryType, char[][][] missingTypeNames) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	IBinaryAnnotation[] annotations = binaryType.getAnnotations();
 	if (annotations != null) {
 		int length = annotations.length;
@@ -2038,7 +2049,7 @@
 				if (elementValuePairs != null && elementValuePairs.length == 1) {
 					Object value = elementValuePairs[0].getValue();
 					if (value instanceof ClassSignature) {
-						this.containingAnnotation = (ReferenceBinding) this.environment.getTypeFromSignature(((ClassSignature)value).getTypeName(), 0, -1, false, null, missingTypeNames, TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER);
+						this.containerAnnotationType = (ReferenceBinding) this.environment.getTypeFromSignature(((ClassSignature)value).getTypeName(), 0, -1, false, null, missingTypeNames, TypeAnnotationWalker.EMPTY_ANNOTATION_WALKER);
 					}
 				}
 				break;
@@ -2053,7 +2064,7 @@
 */
 public ReferenceBinding superclass() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.HasUnresolvedSuperclass) == 0)
 			return this.superclass;
 		this.superclass = this.prototype.superclass();
@@ -2105,7 +2116,7 @@
 // NOTE: superInterfaces of binary types are resolved when needed
 public ReferenceBinding[] superInterfaces() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.HasUnresolvedSuperinterfaces) == 0)
 			return this.superInterfaces;
 		this.superInterfaces = this.prototype.superInterfaces();
@@ -2137,7 +2148,7 @@
 }
 public TypeVariableBinding[] typeVariables() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.HasUnresolvedTypeVariables) == 0)
 			return this.typeVariables;
 		this.typeVariables = this.prototype.typeVariables();
@@ -2259,7 +2270,7 @@
 
 MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.unResolvedMethods();
 	
 	return this.methods;
@@ -2267,7 +2278,7 @@
 
 public FieldBinding[] unResolvedFields() {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.unResolvedFields();
 	
 	return this.fields;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
index 56b0e85..3c39254 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
@@ -139,6 +139,9 @@
 	public boolean isVolatile() {
 		return false;
 	}
+	public boolean isTaggedRepeatable() {
+		return false;
+	}
 	public boolean isParameter() {
 		return false;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
index feffe9d..7434c19 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
@@ -53,23 +53,21 @@
 	// can be 'this', but is never a MethodVerifier (to avoid infinite recursion).
 	ImplicitNullAnnotationVerifier buddyImplicitNullAnnotationsVerifier;
 	private boolean inheritNullAnnotations;
+	protected LookupEnvironment environment;
 
-//{ObjectTeams: added field and 2nd ctor arg:
-	private LookupEnvironment environment;
 
-	public ImplicitNullAnnotationVerifier(boolean inheritNullAnnotations, LookupEnvironment environment) {
-		this.environment = environment;
-// SH}
+	public ImplicitNullAnnotationVerifier(LookupEnvironment environment, boolean inheritNullAnnotations) {
 		this.buddyImplicitNullAnnotationsVerifier = this;
 		this.inheritNullAnnotations = inheritNullAnnotations;
+		this.environment = environment;
 	}
 
 	// for sub-classes:
-//{ObjectTeams: added 2nd arg:
-	ImplicitNullAnnotationVerifier(CompilerOptions options, LookupEnvironment environment) {
-		this.buddyImplicitNullAnnotationsVerifier = new ImplicitNullAnnotationVerifier(options.inheritNullAnnotations, environment);
-// SH}
+	ImplicitNullAnnotationVerifier(LookupEnvironment environment) {
+		CompilerOptions options = environment.globalOptions;
+		this.buddyImplicitNullAnnotationsVerifier = new ImplicitNullAnnotationVerifier(environment, options.inheritNullAnnotations);
 		this.inheritNullAnnotations = options.inheritNullAnnotations;
+		this.environment = environment;
 	}
 
 	/**
@@ -206,9 +204,7 @@
 			MethodBinding currentMethod = ifcMethods[i];
 			if (currentMethod.isStatic())
 				continue;
-//{ObjectTeams: added 3. argument:
-			if (areParametersEqual(original, currentMethod, this.environment)) {
-// SH}
+			if (MethodVerifier.doesMethodOverride(original, currentMethod, this.environment)) {
 				result.add(currentMethod);
 				return; // at most one method is overridden from any supertype
 			}
@@ -247,8 +243,7 @@
 			// TODO (stephan): even here we may need to report problems? How to discriminate?
 			this.buddyImplicitNullAnnotationsVerifier.checkImplicitNullAnnotations(inheritedMethod, null, false, scope);
 		}
-		LookupEnvironment environment = scope.environment();
-		boolean useTypeAnnotations = environment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8;
+		boolean useTypeAnnotations = this.environment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8;
 		long inheritedNullnessBits = getReturnTypeNullnessTagBits(inheritedMethod, useTypeAnnotations);
 		long currentNullnessBits = getReturnTypeNullnessTagBits(currentMethod, useTypeAnnotations);
 		
@@ -273,14 +268,14 @@
 									inheritedMethod, Boolean.valueOf(inheritedNullnessBits == TagBits.AnnotationNonNull), inheritedNonNullnessInfos[0]);
 						} else {
 							// no need to defer, record this info now:
-							applyReturnNullBits(currentMethod, inheritedNullnessBits, environment);
+							applyReturnNullBits(currentMethod, inheritedNullnessBits);
 						}	
 						break returnType; // compatible by construction, skip complain phase below
 					}
 				}
 				if (hasNonNullDefault) { // conflict with inheritance already checked
 					currentNullnessBits = TagBits.AnnotationNonNull;
-					applyReturnNullBits(currentMethod, currentNullnessBits, environment);
+					applyReturnNullBits(currentMethod, currentNullnessBits);
 				}
 			}
 			if (shouldComplain) {
@@ -289,7 +284,7 @@
 				{
 					if (srcMethod != null) {
 						scope.problemReporter().illegalReturnRedefinition(srcMethod, inheritedMethod,
-																	environment.getNonNullAnnotationName());
+																	this.environment.getNonNullAnnotationName());
 					} else {
 						scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod);
 						return;
@@ -341,7 +336,7 @@
 							if (!useTypeAnnotations)
 								recordArgNonNullness(currentMethod, length, i, currentArgument, inheritedNonNullNess);
 							else
-								recordArgNonNullness18(currentMethod, i, currentArgument, inheritedNonNullNess, environment);
+								recordArgNonNullness18(currentMethod, i, currentArgument, inheritedNonNullNess, this.environment);
 						}
 						continue; // compatible by construction, skip complain phase below
 					}
@@ -351,15 +346,15 @@
 					if (!useTypeAnnotations)
 						recordArgNonNullness(currentMethod, length, i, currentArgument, Boolean.TRUE);
 					else
-						recordArgNonNullness18(currentMethod, i, currentArgument, Boolean.TRUE, environment);
+						recordArgNonNullness18(currentMethod, i, currentArgument, Boolean.TRUE, this.environment);
 				}
 			}
 			if (shouldComplain) {
 				char[][] annotationName;
 				if (inheritedNonNullNess == Boolean.TRUE) {
-					annotationName = environment.getNonNullAnnotationName();
+					annotationName = this.environment.getNonNullAnnotationName();
 				} else {
-					annotationName = environment.getNullableAnnotationName();
+					annotationName = this.environment.getNullableAnnotationName();
 				}
 				if (inheritedNonNullNess != Boolean.TRUE		// super parameter is not restricted to @NonNull
 						&& currentNonNullNess == Boolean.TRUE)	// current parameter is restricted to @NonNull 
@@ -369,7 +364,7 @@
 						scope.problemReporter().illegalRedefinitionToNonNullParameter(
 								currentArgument,
 								inheritedMethod.declaringClass,
-								(inheritedNonNullNess == null) ? null : environment.getNullableAnnotationName());
+								(inheritedNonNullNess == null) ? null : this.environment.getNullableAnnotationName());
 					} else {
 						scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod);
 					}
@@ -397,12 +392,12 @@
 		}
 	}
 
-	void applyReturnNullBits(MethodBinding method, long nullnessBits, LookupEnvironment environment) {
-		if (environment.globalOptions.sourceLevel < ClassFileConstants.JDK1_8) {
+	void applyReturnNullBits(MethodBinding method, long nullnessBits) {
+		if (this.environment.globalOptions.sourceLevel < ClassFileConstants.JDK1_8) {
 			method.tagBits |= nullnessBits;
 		} else {
 			if (!method.returnType.isBaseType()) {
-				method.returnType = environment.createAnnotatedType(method.returnType, environment.nullAnnotationsFromTagBits(nullnessBits));
+				method.returnType = this.environment.createAnnotatedType(method.returnType, this.environment.nullAnnotationsFromTagBits(nullnessBits));
 			}
 		}
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
index 80eed02..73b42bd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
@@ -129,7 +129,6 @@
 	private int stepCompleted;
 	public ITypeRequestor typeRequestor;
 
-	private IntersectionCastTypeBinding[][] uniqueIntersectionCastTypeBindings;
 	private SimpleLookupTable uniqueParameterizedGenericMethodBindings;
 	
 	// key is a string with the method selector value is an array of method bindings
@@ -183,7 +182,6 @@
 	this.defaultImports = null;
 	this.nameEnvironment = nameEnvironment;
 	this.knownPackages = new HashtableOfPackage();
-	this.uniqueIntersectionCastTypeBindings = new IntersectionCastTypeBinding[0][0];
 	this.uniqueParameterizedGenericMethodBindings = new SimpleLookupTable(3);
 	this.uniquePolymorphicMethodBindings = new SimpleLookupTable(3);
 	this.missingTypes = null;
@@ -194,7 +192,7 @@
 	if (this.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8 && (stillTesting || this.globalOptions.storeAnnotations)) {
 		this.typeSystem = new AnnotatableTypeSystem(this);
 	} else {
-		this.typeSystem = new UnannotatedTypeSystem(this);
+		this.typeSystem = new TypeSystem(this);
 	}
 }
 
@@ -905,46 +903,9 @@
 }
 
 public TypeBinding createIntersectionCastType(ReferenceBinding[] intersectingTypes) {
-	
-	// this is perhaps an overkill, but since what is worth doing is worth doing well ...
-	
-	int count = intersectingTypes.length;
-	int length = this.uniqueIntersectionCastTypeBindings.length;
-	IntersectionCastTypeBinding[] intersectionCastTypeBindings;
+	return this.typeSystem.getIntersectionCastType(intersectingTypes);
+}	
 
-	if (count < length) {
-		if ((intersectionCastTypeBindings = this.uniqueIntersectionCastTypeBindings[count]) == null)
-			this.uniqueIntersectionCastTypeBindings[count] = intersectionCastTypeBindings = new IntersectionCastTypeBinding[4];
-	} else {
-		System.arraycopy(
-			this.uniqueIntersectionCastTypeBindings, 0,
-			this.uniqueIntersectionCastTypeBindings = new IntersectionCastTypeBinding[count + 1][], 0,
-			length);
-		this.uniqueIntersectionCastTypeBindings[count] = intersectionCastTypeBindings = new IntersectionCastTypeBinding[4];
-	}
-
-	int index = -1;
-	length = intersectionCastTypeBindings.length;
-	next:while (++index < length) {
-		IntersectionCastTypeBinding priorBinding = intersectionCastTypeBindings[index];
-		if (priorBinding == null) // no matching intersection type, but space left
-			return intersectionCastTypeBindings[index] = new IntersectionCastTypeBinding(intersectingTypes, this);
-		ReferenceBinding [] priorIntersectingTypes = priorBinding.intersectingTypes;
-		for (int i = 0; i < count; i++) {
-			if (intersectingTypes[i] != priorIntersectingTypes[i])
-				continue next;
-		}	
-		return priorBinding;
-	}
-
-	// no matching cached binding & no space left
-	System.arraycopy(
-		intersectionCastTypeBindings, 0,
-		(intersectionCastTypeBindings = new IntersectionCastTypeBinding[length * 2]), 0,
-		length);
-	this.uniqueIntersectionCastTypeBindings[count] = intersectionCastTypeBindings;
-	return intersectionCastTypeBindings[length] = new IntersectionCastTypeBinding(intersectingTypes, this);
-}
 public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
 	return createBinaryTypeFrom(binaryType, packageBinding, true, accessRestriction);
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
index 3a0b8c3..3c4ed92 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
@@ -77,7 +77,6 @@
 	SourceTypeBinding type;
 	HashtableOfObject inheritedMethods;
 	HashtableOfObject currentMethods;
-	LookupEnvironment environment;
 /*
 Binding creation is responsible for reporting all problems with types:
 	- all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - abstract/final)
@@ -96,13 +95,10 @@
 		- defining an interface as a local type (local types can only be classes)
 */
 MethodVerifier(LookupEnvironment environment) {
-//{ObjectTeams: added 2nd arg:
-	super(environment.globalOptions, environment);
-// SH}
+	super(environment);
 	this.type = null;  // Initialized with the public method verify(SourceTypeBinding)
 	this.inheritedMethods = null;
 	this.currentMethods = null;
-	this.environment = environment;
 }
 boolean areMethodsCompatible(MethodBinding one, MethodBinding two) {
 	return areMethodsCompatible(one, two, this.environment);
@@ -926,31 +922,26 @@
 		environment.createParameterizedGenericMethod(inheritedMethod, arguments);
 	for (int i = 0; i < inheritedLength; i++) {
 		TypeVariableBinding inheritedTypeVariable = inheritedTypeVariables[i];
-		TypeBinding argument = arguments[i];
-		if (argument instanceof TypeVariableBinding) {
-			TypeVariableBinding typeVariable = (TypeVariableBinding) argument;
-			if (typeVariable.firstBound == inheritedTypeVariable.firstBound) {
-				if (typeVariable.firstBound == null)
-					continue; // both are null
-			} else if (typeVariable.firstBound != null && inheritedTypeVariable.firstBound != null) {
-				if (typeVariable.firstBound.isClass() != inheritedTypeVariable.firstBound.isClass())
-					return inheritedMethod; // not a match
-			}
-			if (Scope.substitute(substitute, inheritedTypeVariable.superclass) != typeVariable.superclass)
+		TypeVariableBinding typeVariable = (TypeVariableBinding) arguments[i]; // cast is safe by construction: arguments is copied from TypeVariableBinding[]
+		if (typeVariable.firstBound == inheritedTypeVariable.firstBound) {
+			if (typeVariable.firstBound == null)
+				continue; // both are null
+		} else if (typeVariable.firstBound != null && inheritedTypeVariable.firstBound != null) {
+			if (typeVariable.firstBound.isClass() != inheritedTypeVariable.firstBound.isClass())
 				return inheritedMethod; // not a match
-			int interfaceLength = inheritedTypeVariable.superInterfaces.length;
-			ReferenceBinding[] interfaces = typeVariable.superInterfaces;
-			if (interfaceLength != interfaces.length)
-				return inheritedMethod; // not a match
-			next : for (int j = 0; j < interfaceLength; j++) {
-				TypeBinding superType = Scope.substitute(substitute, inheritedTypeVariable.superInterfaces[j]);
-				for (int k = 0; k < interfaceLength; k++)
-					if (superType == interfaces[k])
-						continue next;
-				return inheritedMethod; // not a match
-			}
-		} else if (inheritedTypeVariable.boundCheck(substitute, argument, null) != TypeConstants.OK) {
-	    	return inheritedMethod;
+		}
+		if (Scope.substitute(substitute, inheritedTypeVariable.superclass) != typeVariable.superclass)
+			return inheritedMethod; // not a match
+		int interfaceLength = inheritedTypeVariable.superInterfaces.length;
+		ReferenceBinding[] interfaces = typeVariable.superInterfaces;
+		if (interfaceLength != interfaces.length)
+			return inheritedMethod; // not a match
+		next : for (int j = 0; j < interfaceLength; j++) {
+			TypeBinding superType = Scope.substitute(substitute, inheritedTypeVariable.superInterfaces[j]);
+			for (int k = 0; k < interfaceLength; k++)
+				if (superType == interfaces[k])
+					continue next;
+			return inheritedMethod; // not a match
 		}
 	}
    return substitute;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
index 9c3bad1..d7317d2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
@@ -27,7 +27,6 @@
  *								bug 391376 - [1.8] check interaction of default methods with bridge methods and generics
  *								bug 395681 - [compiler] Improve simulation of javac6 behavior from bug 317719 after fixing bug 388795
  *								bug 409473 - [compiler] JDT cannot compile against JRE 1.8
- *								Bug 410325 - [1.7][compiler] Generified method override different between javac and eclipse compiler
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
@@ -408,7 +407,7 @@
 	if (currentMethod.declaringClass != this.type 
 			&& (currentMethod.tagBits & TagBits.IsNullnessKnown) == 0) 
 	{
-		this.buddyImplicitNullAnnotationsVerifier.checkImplicitNullAnnotations(currentMethod, srcMethod, complain, this.type.scope);
+		this.buddyImplicitNullAnnotationsVerifier.checkImplicitNullAnnotations(currentMethod, srcMethod, complain, scope);
 	}
 	super.checkNullSpecInheritance(currentMethod, srcMethod, hasNonNullDefault, complain, inheritedMethod, scope, inheritedNonNullnessInfos);
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java
index 3281d43..2824440 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MissingTypeBinding.java
@@ -43,6 +43,10 @@
 	this.methods = Binding.NO_METHODS;
 }
 
+public TypeBinding clone(TypeBinding outerType) {
+	throw new IllegalStateException(); // shouldn't get here.
+}
+
 //{ObjectTeams: missing o.o.Team cannot be further initialized:
 @Override
 protected void setupOrgObjectteamsTeamModel() {
@@ -81,6 +85,10 @@
 	this.superclass = missingSuperclass;
 }
 
+public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
+	return; // reject misguided attempts.
+}
+
 public String toString() {
 		return "[MISSING:" + new String(CharOperation.concatWith(this.compoundName, '.')) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NullTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NullTypeBinding.java
new file mode 100644
index 0000000..bc5630b
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NullTypeBinding.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2013 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.lookup;
+
+// Give it an identity of its own to discriminate the fact that this type is not annotatable and so is a singleton.
+public class NullTypeBinding extends BaseTypeBinding {
+
+	NullTypeBinding() {
+		super(TypeIds.T_null, TypeConstants.NULL, new char[] { 'N' }); // N stands for null even if it is never internally used);
+	}
+	
+	public TypeBinding clone(TypeBinding enclosingType) {
+		return this;  // enforce solitude.
+	}
+	
+	public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
+		return; // reject misguided attempt.
+	}
+	
+	public TypeBinding unannotated() {
+		return this;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
index 52f8733..697028f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
@@ -475,9 +475,6 @@
 	 */
 	public char[] genericTypeSignature() {
 		if (this.genericTypeSignature == null) {
-			if (isAnnotatedTypeWithoutArguments())
-				return this.genericTypeSignature = this.type.genericTypeSignature();
-
 			if ((this.modifiers & ExtraCompilerModifiers.AccGenericSignature) == 0) {
 		    	this.genericTypeSignature = this.type.signature();
 			} else {
@@ -893,14 +890,6 @@
 		return isRawType();
 	}
 
-	public boolean isAnnotatedTypeWithoutArguments() {
-		if (this.arguments != null || !hasNullTypeAnnotations())
-			return false;
-		if (this.enclosingType != null && this.enclosingType instanceof ParameterizedTypeBinding)
-			return this.enclosingType.isAnnotatedTypeWithoutArguments();
-		return true;
-	}
-
 	public TypeBinding unannotated() {
 		return this.hasTypeAnnotations() ? this.environment.getUnannotatedType(this) : this;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java
index 331fd32..75c8101 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java
@@ -39,11 +39,12 @@
 	final int IntersectionHasMultipleFunctionalInterfaces = 19;
 	final int NonStaticOrAlienTypeReceiver = 20;
 	final int AttemptToBypassDirectSuper = 21; // super access within default method
+	final int DefectiveContainerAnnotationType = 22;
 //{ObjectTeams;
-    final int NoTeamContext = 22;
-    final int AnchorNotFinal = 23;
-    final int AnchorNotATeam = 24;
-    final int AnchorNotFound = 25;
+    final int NoTeamContext = 23;
+    final int AnchorNotFinal = 24;
+    final int AnchorNotATeam = 25;
+    final int AnchorNotFound = 26;
     final int ProblemAlreadyReported = 27;
 // SH}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
index 0d4270a..6402ff7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
@@ -39,6 +39,9 @@
 	this.problemReason = problemReason;
 }
 
+public TypeBinding clone(TypeBinding enclosingType) {
+	throw new IllegalStateException(); // shouldn't get here.
+}
 /**
  * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#closestMatch()
  */
@@ -102,10 +105,13 @@
 	return "unknown"; //$NON-NLS-1$
 }
 
+public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
+	return; // reject misguided attempts.
+}
+//{ObjectTeams: try to squeeze more info out of closestMatch:
 /**
  * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#readableName()
  */
-//{ObjectTeams: try to squeeze more info out of closestMatch:
 public char[] readableName() {
 	if (this.closestMatch != null && !(this.closestMatch instanceof MissingTypeBinding))
 		return this.closestMatch.readableName();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
index 4013dc5..55dbdb9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
@@ -91,10 +91,6 @@
 		return this.environment.createParameterizedGenericMethod(originalMethod, this);
 	}
 
-	public boolean isAnnotatedTypeWithoutArguments() {
-		return false; // here rawness is the reason for not having arguments.
-	}
-
 	public int kind() {
 		return RAW_TYPE;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index e1c7e1d..0834d07 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -1770,13 +1770,6 @@
 }
 
 /**
- * Answer true if the receiver is an annotation which may be repeatable. Overridden as appropriate.
- */
-public boolean isRepeatableAnnotation() {
-	return false;
-}
-
-/**
  * Answer true if the receiver is a static member type (or toplevel)
  */
 public final boolean isStatic() {
@@ -1940,10 +1933,6 @@
 	return readableName;
 }
 
-public ReferenceBinding resolveContainerAnnotation() {
-	return null;
-}
-
 protected void appendNullAnnotation(StringBuffer nameBuffer, CompilerOptions options) {
 	if (options.isAnnotationBasedNullAnalysisEnabled) {
 		// restore applied null annotation from tagBits:
@@ -1973,7 +1962,10 @@
 public void setAnnotations(AnnotationBinding[] annotations) {
 	storeAnnotations(this, annotations);
 }
-public void setContainingAnnotation(ReferenceBinding value) {
+public void setContainerAnnotationType(ReferenceBinding value) {
+	// Leave this to subclasses
+}
+public void tagAsHavingDefectiveContainerType() {
 	// Leave this to subclasses
 }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index 7bc5429..08f0cd9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -157,7 +157,7 @@
     	MultipleCasts.compoundName = new char[][] { "multiple".toCharArray(), "casts".toCharArray(), "required".toCharArray() }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
     }
 
-	protected SourceTypeBinding() { super(); } // default ctor for Singleton membertypes NoBaseclass, ProblemBaseclass
+	protected SourceTypeBinding() { super(); this.prototype = this; } // default ctor for Singleton membertypes NoBaseclass, ProblemBaseclass
 
 //Markus Witte}
 	
@@ -166,7 +166,7 @@
 	private int defaultNullness;
 	private int nullnessDefaultInitialized = 0; // 0: nothing; 1: type; 2: package
 	private int lambdaOrdinal = 0;
-	private ReferenceBinding containingAnnotation = null;
+	private ReferenceBinding containerAnnotationType = null;
 	
 public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) {
 //{ObjectTeams:	// share model from TypeDeclaration:
@@ -219,7 +219,7 @@
 	this.defaultNullness = prototype.defaultNullness;
 	this.nullnessDefaultInitialized= prototype.nullnessDefaultInitialized;
 	this.lambdaOrdinal = prototype.lambdaOrdinal;
-	this.containingAnnotation = prototype.containingAnnotation;
+	this.containerAnnotationType = prototype.containerAnnotationType;
 	this.tagBits |= TagBits.HasUnresolvedMemberTypes; // see memberTypes()
 	
 //{ObjectTeams: team?
@@ -230,7 +230,7 @@
 
 private void addDefaultAbstractMethods() {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	if ((this.tagBits & TagBits.KnowsDefaultAbstractMethods) != 0) return;
 
@@ -307,7 +307,7 @@
 */
 public FieldBinding addSyntheticFieldForInnerclass(LocalVariableBinding actualOuterLocalVariable) {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
@@ -356,7 +356,7 @@
 */
 public FieldBinding addSyntheticFieldForInnerclass(ReferenceBinding enclosingType) {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
@@ -476,7 +476,7 @@
 */
 public FieldBinding addSyntheticFieldForClassLiteral(TypeBinding targetType, BlockScope blockScope) {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
@@ -518,7 +518,7 @@
 */
 public FieldBinding addSyntheticFieldForAssert(BlockScope blockScope) {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
@@ -565,7 +565,7 @@
 */
 public FieldBinding addSyntheticFieldForEnumValues() {
 
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
@@ -642,7 +642,7 @@
  :giro*/
 public SyntheticMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess, boolean isSuperAccess, boolean externalizedReceiver) {
 // SH}
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
@@ -702,7 +702,7 @@
  * char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF
 */
 public SyntheticMethodBinding addSyntheticEnumMethod(char[] selector) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
@@ -726,7 +726,7 @@
  * Add a synthetic field to handle the cache of the switch translation table for the corresponding enum type
  */
 public SyntheticFieldBinding addSyntheticFieldForSwitchEnum(char[] fieldName, String key) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
@@ -771,7 +771,7 @@
  * char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF
 */
 public SyntheticMethodBinding addSyntheticMethodForSwitchEnum(TypeBinding enumBinding) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
@@ -799,7 +799,7 @@
 	return accessMethod;
 }
 public SyntheticMethodBinding addSyntheticMethodForEnumInitialization(int begin, int end) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
@@ -812,7 +812,7 @@
 	return accessMethod;
 }
 public SyntheticMethodBinding addSyntheticMethod(LambdaExpression lambda) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
@@ -843,7 +843,7 @@
 								isSuperAccess);
 	}
 // SH}
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
@@ -875,6 +875,7 @@
 //{ObjectTeams: add OT-specific synthetic bridges:
 // (mostly empty) basecall surrogate
 public SyntheticMethodBinding addSyntheticBaseCallSurrogate(MethodBinding callinMethod) {
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
@@ -896,6 +897,7 @@
 }
 // bridges towards a private role method
 public SyntheticMethodBinding addSyntheticRoleMethodBridge(SourceTypeBinding declaringRole, ReferenceBinding originalRole, MethodBinding targetMethod, int bridgeKind) {
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.ROLE_BRIDGE] == null)
@@ -926,7 +928,7 @@
 }
 // SH}
 public SyntheticMethodBinding addSyntheticArrayMethod(ArrayBinding arrayType, int purpose) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
@@ -949,7 +951,7 @@
 	return arrayMethod;
 }
 public SyntheticMethodBinding addSyntheticFactoryMethod(MethodBinding privateConstructor, MethodBinding publicConstructor, TypeBinding [] enclosingInstances) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null)
 		this.synthetics = new HashMap[MAX_SYNTHETICS];
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
@@ -964,7 +966,7 @@
  * Record the fact that bridge methods need to be generated to override certain inherited methods
  */
 public SyntheticMethodBinding addSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge, MethodBinding targetMethod) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (isInterface()) return null; // only classes & enums get bridge methods
 	// targetMethod may be inherited
 //{ObjectTeams: retrieve callin method's real return type:
@@ -1017,7 +1019,7 @@
  * from a non-public class into a public class (only in 1.6 or greater)
  */
 public SyntheticMethodBinding addSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.scope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_5) {
 		return null;
 	}
@@ -1060,17 +1062,17 @@
 	return accessMethod;
 }
 boolean areFieldsInitialized() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.areFieldsInitialized();
 	return this.fields != Binding.UNINITIALIZED_FIELDS;
 }
 boolean areMethodsInitialized() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.areMethodsInitialized();
 	return this.methods != Binding.UNINITIALIZED_METHODS;
 }
 public int kind() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.kind();
 	if (this.typeVariables != Binding.NO_TYPE_VARIABLES) return Binding.GENERIC_TYPE;
 	return Binding.TYPE;
@@ -1081,7 +1083,7 @@
 }
 
 public char[] computeUniqueKey(boolean isLeaf) {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.computeUniqueKey();
 //{ObjectTeams: don't use __OT__R names for keys (TODO(SH): nested roles?)
 	if (isRole()) {
@@ -1138,7 +1140,7 @@
 public
 // SH}
 void faultInTypesForFieldsAndMethods() {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	// check @Deprecated annotation
 	getAnnotationTagBits(); // marks as deprecated by side effect
 	ReferenceBinding enclosingType = enclosingType();
@@ -1161,7 +1163,7 @@
 // NOTE: the type of each field of a source type is resolved when needed
 public FieldBinding[] fields() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.AreFieldsComplete) != 0)
 			return this.fields;
 		this.tagBits |= TagBits.AreFieldsComplete;
@@ -1234,7 +1236,7 @@
  * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#genericTypeSignature()
  */
 public char[] genericTypeSignature() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.genericTypeSignature();
 	
     if (this.genericReferenceTypeSignature == null)
@@ -1246,7 +1248,7 @@
  * <T:LY<TT;>;U:Ljava/lang/Object;V::Ljava/lang/Runnable;:Ljava/lang/Cloneable;:Ljava/util/Map;>Ljava/lang/Exception;Ljava/lang/Runnable;
  */
 public char[] genericSignature() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.genericSignature();
 	
     StringBuffer sig = null;
@@ -1283,7 +1285,7 @@
  * @see org.eclipse.jdt.internal.compiler.lookup.Binding#getAnnotationTagBits()
  */
 public long getAnnotationTagBits() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getAnnotationTagBits();
 	
 	if ((this.tagBits & TagBits.AnnotationResolved) == 0 && this.scope != null) {
@@ -1307,7 +1309,7 @@
 	return this.tagBits;
 }
 public MethodBinding[] getDefaultAbstractMethods() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getDefaultAbstractMethods();
 	
 	int count = 0;
@@ -1325,7 +1327,7 @@
 }
 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
 public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getExactConstructor(argumentTypes);
 	
 	int argCount = argumentTypes.length;
@@ -1380,7 +1382,7 @@
 //NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
 //searches up the hierarchy as long as no potential (but not exact) match was found.
 public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes, CompilationUnitScope refScope) {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getExactMethod(selector, argumentTypes, refScope);
 	
 	// sender from refScope calls recordTypeReference(this)
@@ -1479,7 +1481,7 @@
 //NOTE: the type of a field of a source type is resolved when needed
 public FieldBinding getField(char[] fieldName, boolean needResolve) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getField(fieldName, needResolve);
 //{ObjectTeams: could be called before fields are present
 //              (from ClassScope.findSupertype if supertyperef is a QualifiedTypeReference),
@@ -1567,7 +1569,7 @@
 
 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
 public MethodBinding[] getMethods(char[] selector) {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.getMethods(selector);
 	
 	if ((this.tagBits & TagBits.AreMethodsComplete) != 0) {
@@ -1742,7 +1744,7 @@
 *	or null if one does not exist.
 */
 public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null || this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) return null;
 	return (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(actualOuterLocalVariable);
 }
@@ -1774,7 +1776,7 @@
 *	or null if one does not exist.
 */
 public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null || this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) return null;
 	FieldBinding field = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(targetEnclosingType);
 	if (field != null) return field;
@@ -1797,7 +1799,7 @@
  * Answer the bridge method associated for an  inherited methods or null if one does not exist
  */
 public SyntheticMethodBinding getSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge) {
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	if (this.synthetics == null) return null;
 	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) return null;
 	SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(inheritedMethodToBridge);
@@ -1806,7 +1808,7 @@
 }
 
 public boolean hasTypeBit(int bit) {
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		return this.prototype.hasTypeBit(bit);
 	}
 	// source types initialize type bits during connectSuperclass/interfaces()
@@ -1817,7 +1819,7 @@
  * @see org.eclipse.jdt.internal.compiler.lookup.Binding#initializeDeprecatedAnnotationTagBits()
  */
 public void initializeDeprecatedAnnotationTagBits() {
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		this.prototype.initializeDeprecatedAnnotationTagBits();
 		return;
 	}
@@ -1843,7 +1845,7 @@
 protected
 // SH}
 void initializeForStaticImports() {
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		this.prototype.initializeForStaticImports();
 		return;
 	}
@@ -1857,7 +1859,7 @@
 
 private int getNullDefault() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		return this.prototype.getNullDefault();
 	}
 	// ensure nullness defaults are initialized at all enclosing levels:
@@ -1877,7 +1879,7 @@
  * or for generic types, true if compared to its raw type.
  */
 public boolean isEquivalentTo(TypeBinding otherType) {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.isEquivalentTo(otherType);
 	
 	if (TypeBinding.equalsEquals(this, otherType)) return true;
@@ -1922,21 +1924,26 @@
 	return false;
 }
 public boolean isGenericType() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.isGenericType();
     return this.typeVariables != Binding.NO_TYPE_VARIABLES;
 }
 public boolean isHierarchyConnected() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.isHierarchyConnected();
 	return (this.tagBits & TagBits.EndHierarchyCheck) != 0;
 }
-public boolean isRepeatableAnnotation() {
-	if (this != this.prototype) throw new IllegalStateException();
-	return this.containingAnnotation != null;
+public boolean isRepeatableAnnotationType() {
+	if (!isPrototype()) throw new IllegalStateException();
+	return this.containerAnnotationType != null;
 }
+
+public boolean isTaggedRepeatable() {  // tagged but not necessarily repeatable. see isRepeatableAnnotationType.
+	return (this.tagBits & TagBits.AnnotationRepeatable) != 0;
+}
+
 public ReferenceBinding[] memberTypes() {
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.HasUnresolvedMemberTypes) == 0)
 			return this.memberTypes;
 		ReferenceBinding [] members = this.memberTypes = this.prototype.memberTypes();
@@ -1951,7 +1958,7 @@
 }
 
 public boolean hasMemberTypes() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.hasMemberTypes();
     return this.memberTypes.length > 0;
 }
@@ -1959,7 +1966,7 @@
 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
 public MethodBinding[] methods() {
 	
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		if ((this.tagBits & TagBits.AreMethodsComplete) != 0)
 			return this.methods;
 		this.tagBits |= TagBits.AreMethodsComplete;
@@ -2207,19 +2214,23 @@
 	return this.prototype;
 }
 
-public ReferenceBinding resolveContainerAnnotation() {
+public boolean isPrototype() {
+	return this == this.prototype;  //$IDENTITY-COMPARISON$
+}
+
+public ReferenceBinding containerAnnotationType() {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
-	if (this.containingAnnotation instanceof UnresolvedReferenceBinding) {
-		this.containingAnnotation = (ReferenceBinding)BinaryTypeBinding.resolveType(this.containingAnnotation, this.scope.environment(), false);
+	if (this.containerAnnotationType instanceof UnresolvedReferenceBinding) {
+		this.containerAnnotationType = (ReferenceBinding)BinaryTypeBinding.resolveType(this.containerAnnotationType, this.scope.environment(), false);
 	}
-	return this.containingAnnotation;
+	return this.containerAnnotationType;
 }
 
 public FieldBinding resolveTypeFor(FieldBinding field) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.resolveTypeFor(field);
 
 	if ((field.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)
@@ -2344,7 +2355,7 @@
 public MethodBinding resolveTypesFor(MethodBinding method, boolean fromSynthetic) {
 // SH}
 
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.resolveTypesFor(method);
 	
 	if ((method.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)
@@ -2699,7 +2710,7 @@
 
 private void createArgumentBindings(MethodBinding method, CompilerOptions compilerOptions) {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	getNullDefault(); // ensure initialized
 	AbstractMethodDeclaration methodDecl = method.sourceMethod();
@@ -2709,16 +2720,14 @@
 			methodDecl.createArgumentBindings();
 		// add implicit annotations (inherited(?) & default):
 		if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
-//{ObjectTeams: added 2nd ctor arg:
-			new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations, this.scope.environment()).checkImplicitNullAnnotations(method, methodDecl, true, this.scope);
-// SH}
+			new ImplicitNullAnnotationVerifier(this.scope.environment()).checkImplicitNullAnnotations(method, methodDecl, true, this.scope);
 		}
 	}
 }
 
 private void evaluateNullAnnotations(long annotationTagBits) {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	if (this.nullnessDefaultInitialized > 0 || !this.scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled)
 		return;
@@ -2767,7 +2776,7 @@
 
 protected void checkRedundantNullnessDefaultRecurse(ASTNode location, Annotation[] annotations, long annotationTagBits) {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	if (this.fPackage.defaultNullness != NO_NULL_DEFAULT) {
 		if ((this.fPackage.defaultNullness == NONNULL_BY_DEFAULT
@@ -2781,7 +2790,7 @@
 // return: should caller continue searching?
 protected boolean checkRedundantNullnessDefaultOne(ASTNode location, Annotation[] annotations, long annotationTagBits) {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	int thisDefault = getNullDefault();
 	if (thisDefault == NONNULL_BY_DEFAULT) {
@@ -2795,7 +2804,7 @@
 
 boolean hasNonNullDefault() {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	// find the applicable default inside->out:
 
@@ -2843,22 +2852,27 @@
 }
 // SH}
 public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.retrieveAnnotationHolder(binding, forceInitialization);
 	if (forceInitialization)
 		binding.getAnnotationTagBits(); // ensure annotations are up to date
 	return super.retrieveAnnotationHolder(binding, false);
 }
 
-public void setContainingAnnotation(ReferenceBinding value) {
-	if (this != this.prototype) throw new IllegalStateException();
-	this.containingAnnotation  = value;
+public void setContainerAnnotationType(ReferenceBinding value) {
+	if (!isPrototype()) throw new IllegalStateException();
+	this.containerAnnotationType  = value;
+}
+
+public void tagAsHavingDefectiveContainerType() {
+	if (this.containerAnnotationType != null && this.containerAnnotationType.isValidBinding())
+		this.containerAnnotationType = new ProblemReferenceBinding(this.containerAnnotationType.compoundName, this.containerAnnotationType, ProblemReasons.DefectiveContainerAnnotationType);
 }
 
 // Propagate writes to all annotated variants so the clones evolve along.
 public FieldBinding [] setFields(FieldBinding[] fields) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.setFields(fields);
 
 	if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) {
@@ -2884,7 +2898,7 @@
 // We need to specialize member types, can't just propagate. Can't specialize here, clones could created post setMemberTypes()
 public ReferenceBinding [] setMemberTypes(ReferenceBinding[] memberTypes) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.setMemberTypes(memberTypes);
 
 	this.memberTypes = memberTypes;
@@ -2902,7 +2916,7 @@
 // Propagate writes to all annotated variants so the clones evolve along.
 public MethodBinding [] setMethods(MethodBinding[] methods) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.setMethods(methods);
 	
 	if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) {
@@ -2929,7 +2943,7 @@
 // Propagate writes to all annotated variants so the clones evolve along.
 public ReferenceBinding setSuperClass(ReferenceBinding superClass) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.setSuperClass(superClass);
 	
 	if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) {
@@ -2945,7 +2959,7 @@
 // Propagate writes to all annotated variants so the clones evolve along.
 public ReferenceBinding [] setSuperInterfaces(ReferenceBinding [] superInterfaces) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.setSuperInterfaces(superInterfaces);
 	
 	if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) {
@@ -2961,7 +2975,7 @@
 // Propagate writes to all annotated variants so the clones evolve along.
 public TypeVariableBinding [] setTypeVariables(TypeVariableBinding [] typeVariables) {
 	
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.setTypeVariables(typeVariables);
 	
 	if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) {
@@ -3151,19 +3165,19 @@
 
 //Markus Witte}
 public final int sourceEnd() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.sourceEnd();
 
 	return this.scope.referenceContext.sourceEnd;
 }
 public final int sourceStart() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.sourceStart();
 
 	return this.scope.referenceContext.sourceStart;
 }
 SimpleLookupTable storedAnnotations(boolean forceInitialize) {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.storedAnnotations(forceInitialize);
 
 	if (forceInitialize && this.storedAnnotations == null && this.scope != null) { // scope null when no annotation cached, and type got processed fully (159631)
@@ -3180,20 +3194,20 @@
 }
 
 public ReferenceBinding superclass() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.superclass = this.prototype.superclass();
 	return this.superclass;
 }
 
 public ReferenceBinding[] superInterfaces() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.superInterfaces = this.prototype.superInterfaces();
 	return this.superInterfaces;
 }
 
 public SyntheticMethodBinding[] syntheticMethods() {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 //{ObjectTeams: two different kinds of synthetics:
 /* orig:
@@ -3257,7 +3271,7 @@
  */
 public FieldBinding[] syntheticFields() {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 	if (this.synthetics == null) return null;
 	int fieldSize = this.synthetics[SourceTypeBinding.FIELD_EMUL] == null ? 0 : this.synthetics[SourceTypeBinding.FIELD_EMUL].size();
@@ -3390,13 +3404,13 @@
 	return buffer.toString();
 }
 public TypeVariableBinding[] typeVariables() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.typeVariables = this.prototype.typeVariables();
 	return this.typeVariables != null ? this.typeVariables : Binding.NO_TYPE_VARIABLES;
 }
 void verifyMethods(MethodVerifier verifier) {
 	
-	if (this != this.prototype) throw new IllegalStateException();
+	if (!isPrototype()) throw new IllegalStateException();
 	
 //{ObjectTeams: shortcut for predefined confined types (override final methods???)
 	if (TypeAnalyzer.isTopConfined(this))
@@ -3426,13 +3440,13 @@
 }
 
 public FieldBinding[] unResolvedFields() {
-	if (this != this.prototype)
+	if (!isPrototype())
 		return this.prototype.unResolvedFields();
 	return this.fields;
 }
 
 public void tagIndirectlyAccessibleMembers() {
-	if (this != this.prototype) {
+	if (!isPrototype()) {
 		this.prototype.tagIndirectlyAccessibleMembers();
 		return;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
index 6fc901a..7d8a08c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
@@ -159,6 +159,8 @@
 	long AnnotationNullUnspecifiedByDefault = ASTNode.Bit59L;
 	/** From Java 8 */
 	long AnnotationFunctionalInterface = ASTNode.Bit60L;
+	/** From Java 8 */
+	long AnnotationRepeatable = ASTNode.Bit61L; // Only for annotation types and since these cannot have constructors, we can overload HasNonPrivateConstructor.
 
 //{ObjectTeams: one more standard annotation:
 	long AnnotationInstantiation = ASTNode.Bit64L;
@@ -180,7 +182,9 @@
 				| AnnotationNullable
 				| AnnotationNonNull
 				| AnnotationNonNullByDefault
-				| AnnotationNullUnspecifiedByDefault;
+				| AnnotationNullUnspecifiedByDefault
+				| AnnotationRepeatable;
+	
 	long AnnotationNullMASK = AnnotationNullable | AnnotationNonNull;
 	/** @since 3.9_BETA_JAVA8 marks a type that has a nullness annotation directly or on a detail (array dimension/type argument). */
 	long HasNullTypeAnnotation = ASTNode.Bit21;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
index 199ce23..248db97 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
@@ -92,11 +92,9 @@
 	public final static BaseTypeBinding BOOLEAN = new BaseTypeBinding(
 			TypeIds.T_boolean, TypeConstants.BOOLEAN, new char[] { 'Z' });
 
-	public final static BaseTypeBinding NULL = new BaseTypeBinding(
-			TypeIds.T_null, TypeConstants.NULL, new char[] { 'N' }); //N stands for null even if it is never internally used
+	public final static NullTypeBinding NULL = new NullTypeBinding();
 
-	public final static BaseTypeBinding VOID = new BaseTypeBinding(
-			TypeIds.T_void, TypeConstants.VOID, new char[] { 'V' });
+	public final static VoidTypeBinding VOID = new VoidTypeBinding();
 
 
 public TypeBinding() {
@@ -174,6 +172,10 @@
 	return -1; // overridden in WildcardBinding
 }
 
+public ReferenceBinding containerAnnotationType() {
+	return null;
+}
+
 /* Answer true if the receiver can be instantiated
  */
 public boolean canBeInstantiated() {
@@ -670,17 +672,7 @@
 public final boolean isParameterizedType() {
 	return kind() == Binding.PARAMETERIZED_TYPE;
 }
-/**
- * Returns true for those ParameterizedTypeBindings, which represent an annotated type
- * yet without any type parameters (neither locally nor in any enclosing type).
- */
-public boolean isAnnotatedTypeWithoutArguments() {
-	return false;
-}
 
-public int hashCode() {
-	return this.id != TypeIds.NoId ? this.id : super.hashCode();
-}
 /**
  * Does this type or any of its details (array dimensions, type arguments)
  * have a null type annotation?
@@ -1039,6 +1031,13 @@
 	}
 }
 
+/**
+ * Answer true if the receiver is an annotation which may be repeatable. Overridden as appropriate.
+ */
+public boolean isRepeatableAnnotationType() {
+	return false;
+}
+
 public final boolean isRawType() {
 	return kind() == Binding.RAW_TYPE;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
index c33f02e..1be22f6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
@@ -14,67 +14,437 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
+import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
+import org.eclipse.jdt.internal.compiler.util.Util;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
 
-public abstract class TypeSystem {
+/* TypeSystem: An abstraction responsible for keeping track of types that undergo "derivation" of some sort and the derived types produced thus.
+   Here we use the term derivation in the Pascal sense and not per object oriented parlance.
+   
+   As of Java SE8, a type can undergo derivation in a bunch of ways:
+   
+       - By being created arrays out of,
+       - By being parameterized,
+       - By being created raw forms of,
+       - By being the generic type which a wildcard type or an intersection type parameterizes,
+       - By being annotated.
+       
+   It is the responsibility of the TypeSystem to serve as the factory and ensure that unique types are created and maintained. Most of the
+   compiler depends on object identity given the derivation parameters are the same. E.g: If we dole out non-unique ParameterizedTypeBinding's
+   for two attempts to create List<String>, then one cannot be assigned to the other.
+   
+   Till Java SE7, we could manage to create a single binding for a type - not so with annotations coming into the picture. In order for
+   two uses of the same type to be annotated differently, the bindings for them need to be distinct and cannot be shared. If we start
+   doling out different bindings, then validating type identity and equivalence becomes an issue.
+   
+   What we do to solve the problem is produce different bindings when they need to be annotated differently, but stamp them with the
+   same id (TypeBinding#id). Thus types that fail == or != could quickly be ascertained to be mere annotation variants by comparing
+   the id field.
+       
+   This class is responsible for id stamping unique types. Only those types that are "derived from" in some form or participate in the 
+   derivation in some form (by being type arguments say) get tracked and id'd here. A type which is not thus derived from in one form or 
+   the other or participate in the derivation thus - we are completely oblivious to.
+   
+   TypeBinding.id computation: For primitive types and certain "well known" types, id assignment happens elsewhere. Here we start with an 
+   id value that is suitably high and proceed monotonically upwards so we will not accidentally collide with the id space in use already. 
+   id assignments happens in such a way that a naked type and its annotated variants - variously annotated - would all share the same id. 
+   Example: @T1 Map<@T2 String, @T3 Object> and Map<@T4 String, @T5 Object> and @T6 Map<String, Object> and @T7 Map<String, @T8 Object> and 
+   Map<String, @T9 Object> would all share the same id since the unadorned naked type in each case is the same: Map<String, Object>. None 
+   of this would share the id with Map<String, String>. Briefly put, if you take a certain annotated type and strip it of all annotations 
+   to come up with the naked type, that naked type and the annotated type would have the same id. Alternately, if you take a certain naked 
+   type and arrive at the universe of all differently annotated types, they would all share the same id while their bindings could be different - 
+   would be different unless they are identically annotated.
+   
+   Thus subsystems that are annotation agnostic could quickly ascertain binding equality by comparing the id field.
+*/
+public class TypeSystem {
 	
-	public boolean isAnnotatedTypeSystem() {
-		return false;
+	private int typeid = TypeIds.T_LastWellKnownTypeId;
+	private TypeBinding [][] types; 
+	private SimpleLookupTable annotationTypes; // cannot store in types, since AnnotationBinding is not a TypeBinding and we don't want types to operate at Binding level.
+	private LookupEnvironment environment;
+	
+	public TypeSystem(LookupEnvironment environment) {
+		this.environment = environment;
+		this.annotationTypes = new SimpleLookupTable(16);
+		this.typeid = TypeIds.T_LastWellKnownTypeId;
+		this.types = new TypeBinding[TypeIds.T_LastWellKnownTypeId * 2][]; 
 	}
 
-	public abstract AnnotationBinding getAnnotationType(ReferenceBinding annotationType, boolean requireResolved);
+	// Given a type, answer its unannotated aka naked prototype. This is also a convenient way to "register" a type with TypeSystem and have it id stamped.
+	public final TypeBinding getUnannotatedType(TypeBinding type) {
+		if (type.id == TypeIds.NoId) {
+			if (type.hasTypeAnnotations())
+				throw new IllegalStateException();
+			int typesLength = this.types.length;
+			if (this.typeid == typesLength)
+				System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
+			this.types[type.id = this.typeid++] = new TypeBinding[4];
+		} else {
+			TypeBinding nakedType = this.types[type.id] == null ? null : this.types[type.id][0];
+			if (type.hasTypeAnnotations() && nakedType == null)
+				throw new IllegalStateException();
+			if (nakedType != null)
+				return nakedType;
+			this.types[type.id] = new TypeBinding[4];  // well known type, assigned id elsewhere.
+		}
 	
-	public abstract ArrayBinding getArrayType(TypeBinding leafComponentType, int dimensions);
+		return this.types[type.id][0] = type;
+	}
+	
+	// Given a type, return all its variously annotated versions.
+	public TypeBinding[] getAnnotatedTypes(TypeBinding type) {
+		return Binding.NO_TYPES;
+	}
+
+	/* Note: parameters will not have type type annotations if lookup environment directly uses TypeSystem as its typeSystem. When ATS is used however
+	   they may be annotated and we need to materialize the unannotated versions and work on them.
+	*/ 
+	public ArrayBinding getArrayType(TypeBinding leafType, int dimensions) {
+		TypeBinding unannotatedLeafType = getUnannotatedType(leafType);
+		TypeBinding[] derivedTypes = this.types[unannotatedLeafType.id];
+		int i, length = derivedTypes.length;
+		for (i = 0; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null) 
+				break;
+			if (!derivedType.isArrayType() || derivedType.hasTypeAnnotations())
+				continue;
+			if (derivedType.leafComponentType() == unannotatedLeafType && derivedType.dimensions() == dimensions)
+				return (ArrayBinding) derivedType;
+		}
+		if (i == length) {
+			System.arraycopy(derivedTypes, 0, derivedTypes = new TypeBinding[length * 2], 0, length);
+			this.types[unannotatedLeafType.id] = derivedTypes;
+		}
+		TypeBinding arrayType = derivedTypes[i] = new ArrayBinding(unannotatedLeafType, dimensions, this.environment);
+		int typesLength = this.types.length;
+		if (this.typeid == typesLength)
+			System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
+		this.types[this.typeid] = new TypeBinding[1];
+		return (ArrayBinding) (this.types[arrayType.id = this.typeid++][0] = arrayType);
+	}
 	
 	public ArrayBinding getArrayType(TypeBinding leafComponentType, int dimensions, AnnotationBinding[] annotations) {
 		return getArrayType(leafComponentType, dimensions);
 	}
-//{ObjectTeams: 2 parameters added:
+
+	public ReferenceBinding getMemberType(ReferenceBinding memberType, ReferenceBinding enclosingType) {
+		return memberType;  // nothing to do for plain vanilla type system, they are already hooked.
+	}
+
+	/* Note: parameters will not have type type annotations if lookup environment directly uses TypeSystem. When AnnotatableTypeSystem is in use
+	   they may and we need to materialize the unannotated versions and work on them.
+	*/ 
+	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) {
+//{ObjectTeams: more arguments for role types:
+		return getParameterizedType(genericType, typeArguments, null, -1, enclosingType);
+	}
+	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments,
+										ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType) {
+		if (teamAnchor == null && genericType instanceof DependentTypeBinding)
+			teamAnchor = ((DependentTypeBinding) genericType)._teamAnchor;
+// SH}
+
+		ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
+		int typeArgumentsLength = typeArguments == null ? 0: typeArguments.length;
+		TypeBinding [] unannotatedTypeArguments = typeArguments == null ? null : new TypeBinding[typeArgumentsLength];
+		for (int i = 0; i < typeArgumentsLength; i++) {
+			unannotatedTypeArguments[i] = getUnannotatedType(typeArguments[i]);
+		}
+		ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
+		
+		TypeBinding[] derivedTypes = this.types[unannotatedGenericType.id];
+		int i, length = derivedTypes.length;
+		for (i = 0 ; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null) 
+				break;
+//{ObjectTeams: parameterized and/or anchored?
 /* orig:
-	public abstract ParameterizedTypeBinding getParameterizedType (ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType);
+			if (!derivedType.isParameterizedType() || derivedType.actualType() != unannotatedGenericType || derivedType.hasTypeAnnotations())
+				continue;
   :giro */
-	public abstract ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments,
-												ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType);
+			if (!(derivedType instanceof ParameterizedTypeBinding)) // roles might answer 'false' to isParameterized(), still they are valid candidates, here
+				continue;
+			if (derivedType.actualType() != unannotatedGenericType)
+				continue;
+			if (derivedType.isRawType() && unannotatedTypeArguments != null)
+				continue;
+			// also match team anchor if given:
+			if (!isRoleTypeMatch(teamAnchor, valueParamPosition, derivedType))
+				continue;
+//SH}
+
+			if (derivedType.enclosingType() == unannotatedEnclosingType && Util.effectivelyEqual(derivedType.typeArguments(), unannotatedTypeArguments))
+				return (ParameterizedTypeBinding) derivedType;
+		}
+
+		if (i == length) {
+			System.arraycopy(derivedTypes, 0, derivedTypes = new TypeBinding[length * 2], 0, length);
+			this.types[unannotatedGenericType.id] = derivedTypes;
+		}
+//{ObjectTeams: dependent type?
+/* orig:	
+		TypeBinding parameterizedType = derivedTypes[i] = new ParameterizedTypeBinding(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, this.environment);
+  :giro */
+		ParameterizedTypeBinding parameterizedType;
+		if (teamAnchor == null) {
+			parameterizedType = new ParameterizedTypeBinding(unannotatedGenericType,unannotatedTypeArguments, unannotatedEnclosingType, this.environment);
+		} else {
+			if (genericType.isRole()) {
+				parameterizedType = new RoleTypeBinding(unannotatedGenericType, unannotatedTypeArguments, teamAnchor, unannotatedEnclosingType, this.environment);
+			} else {
+				parameterizedType = new DependentTypeBinding(unannotatedGenericType, unannotatedTypeArguments, teamAnchor, valueParamPosition, unannotatedEnclosingType, this.environment);
+			}
+		}
+		derivedTypes[i] = parameterizedType;
+// SH}
+
 	
+		int typesLength = this.types.length;
+		if (this.typeid == typesLength)
+			System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
+		this.types[this.typeid] = new TypeBinding[1];
+		return (ParameterizedTypeBinding) (this.types[parameterizedType.id = this.typeid++][0] = parameterizedType);
+	}
+	
+//{ObjectTeams: more parameters:
 /* orig:
 	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding[] annotations) {
 		return getParameterizedType(genericType, typeArguments, enclosingType);
   :giro */
 	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments,
-										ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType, AnnotationBinding[] annotations) {
+					ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType, AnnotationBinding[] annotations) {
 		return getParameterizedType(genericType, typeArguments, teamAnchor, valueParamPosition, enclosingType);
 // SH}
 	}
 
-	public abstract RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType);
+	/* Note: Parameters will not have type type annotations if lookup environment directly uses TypeSystem. However when AnnotatableTypeSystem is in use,
+	   they may and we need to materialize the unannotated versions and work on them.
+	*/ 
+	public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) {
+		ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
+		ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
+	
+		TypeBinding[] derivedTypes = this.types[unannotatedGenericType.id];
+		int i, length = derivedTypes.length;
+		for (i = 0; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null) 
+				break;
+			if (!derivedType.isRawType() || derivedType.actualType() != unannotatedGenericType || derivedType.hasTypeAnnotations())
+				continue;
+			if (derivedType.enclosingType() == unannotatedEnclosingType)
+				return (RawTypeBinding) derivedType;
+		}
+
+		if (i == length) {
+			System.arraycopy(derivedTypes, 0, derivedTypes = new TypeBinding[length * 2], 0, length);
+			this.types[unannotatedGenericType.id] = derivedTypes;
+		}
+		
+		TypeBinding rawTytpe = derivedTypes[i] = new RawTypeBinding(unannotatedGenericType, unannotatedEnclosingType, this.environment);
+		int typesLength = this.types.length;
+		if (this.typeid == typesLength)
+			System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
+		this.types[this.typeid] = new TypeBinding[1];
+		return (RawTypeBinding) (this.types[rawTytpe.id = this.typeid++][0] = rawTytpe);
+	}
 	
 	public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType, AnnotationBinding[] annotations) {
 		return getRawType(genericType, enclosingType);
 	}
 
-	public abstract WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind);
+	/* Parameters will not have type type annotations if lookup environment directly uses TypeSystem. When AnnotatableTypeSystem is in use,
+	   they may and we need to materialize the unannotated versions and work on them.
+	*/ 
+	public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) {
+		if (genericType == null) // pseudo wildcard denoting composite bounds for lub computation
+			genericType = ReferenceBinding.LUB_GENERIC;
+		
+		ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
+		int otherBoundsLength = otherBounds == null ? 0: otherBounds.length;
+		TypeBinding [] unannotatedOtherBounds = otherBounds == null ? null : new TypeBinding[otherBoundsLength];
+		for (int i = 0; i < otherBoundsLength; i++) {
+			unannotatedOtherBounds[i] = getUnannotatedType(otherBounds[i]);
+		}
+		TypeBinding unannotatedBound = bound == null ? null : getUnannotatedType(bound);
+
+		TypeBinding[] derivedTypes = this.types[unannotatedGenericType.id];  // by construction, cachedInfo != null now.
+		int i, length = derivedTypes.length;
+		for (i = 0; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null) 
+				break;
+			if (!derivedType.isWildcard() || derivedType.actualType() != unannotatedGenericType || derivedType.hasTypeAnnotations())
+				continue;
+			if (derivedType.rank() != rank || derivedType.boundKind() != boundKind || derivedType.bound() != unannotatedBound)
+				continue;
+			if (Util.effectivelyEqual(derivedType.additionalBounds(), unannotatedOtherBounds))
+				return (WildcardBinding) derivedType;
+		}
+		
+		if (i == length) {
+			System.arraycopy(derivedTypes, 0, derivedTypes = new TypeBinding[length * 2], 0, length);
+			this.types[unannotatedGenericType.id] = derivedTypes;
+		}
+		TypeBinding wildcard = derivedTypes[i] = new WildcardBinding(unannotatedGenericType, rank, unannotatedBound, unannotatedOtherBounds, boundKind, this.environment);
+	
+		int typesLength = this.types.length;
+		if (this.typeid == typesLength)
+			System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
+		this.types[this.typeid] = new TypeBinding[1];
+		return (WildcardBinding) (this.types[wildcard.id = this.typeid++][0] = wildcard);
+	}
 	
 	public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind, AnnotationBinding[] annotations) {
 		return getWildcard(genericType, rank, bound, otherBounds, boundKind);
 	}
 
 	public TypeBinding getAnnotatedType(TypeBinding type, AnnotationBinding[][] annotations) {
-		return type;
+		return type; // Nothing to do for plain vanilla type system.
 	}
-
 	
-	public abstract void reset();
-
-	public abstract void updateCaches(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType);
-
-	public abstract TypeBinding getUnannotatedType(TypeBinding type);
-
-	// Given a type, return all its variously annotated versions.
-	public TypeBinding[] getAnnotatedTypes(TypeBinding type) {
-		return Binding.NO_TYPES;
+	protected final TypeBinding /* @NonNull */ [] getDerivedTypes(TypeBinding keyType) {
+		keyType = getUnannotatedType(keyType);
+		return this.types[keyType.id];
+	}
+	
+	private TypeBinding cacheDerivedType(TypeBinding keyType, TypeBinding derivedType) {
+		if (keyType == null || derivedType == null || keyType.id == TypeIds.NoId)
+			throw new IllegalStateException();
+		
+		TypeBinding[] derivedTypes = this.types[keyType.id];
+		int i = 0, length = derivedTypes.length;
+		while (i < length && derivedTypes[i] != null) {
+			i++;
+		}
+		if (i == length) {
+			System.arraycopy(derivedTypes, 0, derivedTypes = new TypeBinding[length * 2], 0, length);
+			this.types[keyType.id] = derivedTypes;
+		}
+		return derivedTypes[i] = derivedType;
+	}
+	
+	protected final TypeBinding cacheDerivedType(TypeBinding keyType, TypeBinding nakedType, TypeBinding derivedType) {
+		
+		/* Cache the derived type, tagging it as a derivative of both the key type and the naked type.
+		   E.g: int @NonNull [] would be tagged as a derived type of both int and int []. This is not
+		   needed for correctness, but for annotated object reuse. We provide two alternate ways to
+		   annotate a type: 
+		   
+		   Taking parameterized types as an example, a call to getParamaterizedType can be made with annotations
+		   to create @NonNull List<@NonNull String> in one stroke. Or a parameterized type can be created first
+		   and then annotated via getAnnotatedType. In the former case, the tables get looked up with List as
+		   the key, in the latter with List<String> as the key.
+		   
+		   Binary vs source, substitutions, annotation re-attribution from SE7 locations etc trigger these
+		   alternate code paths. Unless care is exercised, we will end up with duplicate objects (that share
+		   the same TypeBinding.id => correctness is not an issue, but memory wastage is)
+		*/
+		cacheDerivedType(keyType, derivedType);
+		if (nakedType.id != keyType.id) {
+			cacheDerivedType(nakedType, derivedType);
+		}
+		return derivedType;
+	}
+	
+	/* Return a unique annotation binding for an annotation with either no or all default element-value pairs.
+	   We may return a resolved annotation when requested for unresolved one, but not vice versa. 
+	*/
+	public final AnnotationBinding getAnnotationType(ReferenceBinding annotationType, boolean requiredResolved) {
+		AnnotationBinding annotation = (AnnotationBinding) this.annotationTypes.get(annotationType);
+		if (annotation == null) {
+			if (requiredResolved)
+				annotation = new AnnotationBinding(annotationType, Binding.NO_ELEMENT_VALUE_PAIRS);
+			else 
+				annotation = new UnresolvedAnnotationBinding(annotationType, Binding.NO_ELEMENT_VALUE_PAIRS, this.environment);
+			this.annotationTypes.put(annotationType, annotation);
+		}
+		if (requiredResolved)
+			annotation.resolve();
+		return annotation;
 	}
 
-	public ReferenceBinding getMemberType(ReferenceBinding memberType, ReferenceBinding enclosingType) {
-		return memberType;  // nothing to do for plain vanilla type system.
+	public boolean isAnnotatedTypeSystem() {
+		return false;
 	}
-}
+
+	public void reset() {
+		this.annotationTypes = new SimpleLookupTable(16);
+		this.typeid = TypeIds.T_LastWellKnownTypeId;
+		this.types = new TypeBinding[TypeIds.T_LastWellKnownTypeId * 2][];
+	}
+	
+	public void updateCaches(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) {
+		final int unresolvedTypeId = unresolvedType.id;
+		if (unresolvedTypeId != TypeIds.NoId) {
+			if (this.types[unresolvedTypeId] != null && this.types[unresolvedTypeId][0] == unresolvedType) {
+				resolvedType.id = unresolvedTypeId;
+				this.types[unresolvedTypeId][0] = resolvedType;
+			}
+		}
+		if (this.annotationTypes.get(unresolvedType) != null) { // update the key
+			Object[] keys = this.annotationTypes.keyTable;
+			for (int i = 0, l = keys.length; i < l; i++) {
+				if (keys[i] == unresolvedType) {
+					keys[i] = resolvedType; // hashCode is based on compoundName so this works.
+					break;
+				}
+			}
+		}
+	}
+
+	public final TypeBinding getIntersectionCastType(ReferenceBinding[] intersectingTypes) {
+		int intersectingTypesLength = intersectingTypes == null ? 0 : intersectingTypes.length;
+		if (intersectingTypesLength == 0)
+			return null;
+		TypeBinding keyType = intersectingTypes[0];
+		if (keyType == null || intersectingTypesLength == 1)
+			return keyType;
+					
+		TypeBinding[] derivedTypes = getDerivedTypes(keyType);
+		int i, length = derivedTypes.length;
+		next:
+		for (i = 0; i < length; i++) {
+			TypeBinding derivedType = derivedTypes[i];
+			if (derivedType == null) 
+				break;
+			if (!derivedType.isIntersectionCastType())
+				continue;
+			ReferenceBinding [] priorIntersectingTypes = derivedType.getIntersectingTypes();
+			if (priorIntersectingTypes.length != intersectingTypesLength)
+				continue;
+			for (int j = 0; j < intersectingTypesLength; j++) {
+				if (intersectingTypes[j] != priorIntersectingTypes[j])
+					continue next;
+			}	
+			return derivedType;
+		}
+		return cacheDerivedType(keyType, new IntersectionCastTypeBinding(intersectingTypes, this.environment));
+	}
+
+//{ObjectTeams: compare role types:
+	boolean isRoleTypeMatch(ITeamAnchor teamAnchor, int valueParamPosition, TypeBinding cachedType) {
+		if (teamAnchor != null) {
+			if (!(cachedType instanceof DependentTypeBinding))
+				return false;
+			if (!((DependentTypeBinding)cachedType)._teamAnchor.hasSameBestNameAs(teamAnchor))
+				return false;
+		}
+		if (   valueParamPosition > -1 							// position specified, requires dependent type
+		    && !(cachedType instanceof DependentTypeBinding))
+			return false;
+		if (   (cachedType instanceof DependentTypeBinding)		// dependent type specified, positions must match
+		    && ((DependentTypeBinding)cachedType)._valueParamPosition != valueParamPosition)
+			return false;
+		if (teamAnchor == null && RoleTypeBinding.isRoleType(cachedType)) // role type found though not requested?
+			return false;
+		return true;
+	}
+//SH}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnannotatedTypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnannotatedTypeSystem.java
deleted file mode 100644
index 601165b..0000000
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnannotatedTypeSystem.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2013 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- * 
- * This is an implementation of an early-draft specification developed under the Java
- * Community Process (JCP) and is made available for testing and evaluation purposes
- * only. The code is not compatible with any specification of the JCP.
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.compiler.lookup;
-
-import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
-import org.eclipse.jdt.internal.compiler.util.Util;
-import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
-import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
-import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
-
-/* UnannotatedTypeSystem: An abstraction responsible for keeping track of naked a.k.a unannotated types. This piece is also responsible for id stamping unique
-   types. Only those types that are "derived from" in some form or participate in the derivation in some form (by being type arguments say) get tracked and 
-   id'd here. At Java 8 time, a new type can be derived from another type by (a) parameterizing it (b) creating arrays of it, (c) by creating raw forms of it, 
-   (d) by creating a wild card that could parameterize it or finally by (e) annotating it. A type which is not thus derived from in one form or the other or
-   participate in the derivation thus - UTS is completely oblivious to.
-   
-   TypeBinding.id computation: For primitive types and certain "well known" types, id assignment happens elsewhere. Here we start with an id value that is
-   suitably high and proceed monotonically upwards so we will not accidentally collide with the id space in use already. id assignments happens in such a
-   way that a naked type and its annotated variants - variously annotated - would all share the same id. Example: @T1 Map<@T2 String, @T3 Object> and
-   Map<@T4 String, @T5 Object> and @T6 Map<String, Object> and @T7 Map<String, @T8 Object> and Map<String, @T9 Object> would all share the same id since
-   the unadorned naked type in each case is the same: Map<String, Object>. None of this would share the id with Map<String, String>. Briefly put, if you
-   take a certain annotated type and strip it of all annotations to come up with the naked type, that naked type and the annotated type would have the
-   same id. Alternately, if you take a certain naked type and arrive at the universe of all differently annotated types, they would all share the same id while
-   their bindings could be different - would be different unless they are identically annotated.
-   
-   Thus subsystems that are annotation agnostic could quickly ascertain binding equality by comparing the id field.
-*/
-public class UnannotatedTypeSystem extends TypeSystem {
-	
-	private int typeid = TypeIds.T_LastWellKnownTypeId;
-	private TypeBinding [][] types; 
-	private SimpleLookupTable annotationTypes;
-	private LookupEnvironment environment;
-	
-	public UnannotatedTypeSystem(LookupEnvironment environment) {
-		this.environment = environment;
-		this.annotationTypes = new SimpleLookupTable(16);
-		this.typeid = TypeIds.T_LastWellKnownTypeId;
-		this.types = new TypeBinding[TypeIds.T_LastWellKnownTypeId * 2][]; 
-	}
-
-	public TypeBinding getUnannotatedType(TypeBinding type) {
-		if (type.id == TypeIds.NoId) {
-			if (type.hasTypeAnnotations())
-				throw new IllegalStateException();
-			int typesLength = this.types.length;
-			if (this.typeid == typesLength)
-				System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
-			this.types[type.id = this.typeid++] = new TypeBinding[4];
-		} else {
-			TypeBinding nakedType = this.types[type.id] == null ? null : this.types[type.id][0];
-			if (type.hasTypeAnnotations() && nakedType == null)
-				throw new IllegalStateException();
-			if (nakedType != null)
-//{ObjectTeams: keep role information
-			// FIXME(SH): mix role info into naked of annotated type
-			{
-				if (!type.hasTypeAnnotations() && DependentTypeBinding.isDependentType(type))
-					return type; 
-// orig:
-				return nakedType;
-// :giro
-			}
-// SH}
-			this.types[type.id] = new TypeBinding[4];  // well known type, assigned id elsewhere.
-		}
-	
-		return this.types[type.id][0] = type;
-	}
-	
-	/* Note: parameters will not have type type annotations if lookup environment directly uses UTS as its typeSystem. However if this UTS is the underlying type system
-	   for an ATS, they may and we need to materialize the unannotated versions and work on them.
-	*/ 
-	public ArrayBinding getArrayType(TypeBinding leafType, int dimensions) {
-		TypeBinding unannotatedLeafType = getUnannotatedType(leafType);
-		TypeBinding[] cachedInfo = this.types[unannotatedLeafType.id];  // by construction, cachedInfo != null now.
-		int index = 0;
-		for (int max = cachedInfo.length; index < max; index++) {
-			TypeBinding cachedType = cachedInfo[index];
-			if (cachedType == null) 
-				break;
-			if (!cachedType.isArrayType())
-				continue;
-			if (cachedType.leafComponentType() == unannotatedLeafType && cachedType.dimensions() == dimensions)
-				return (ArrayBinding) cachedType;
-		}
-
-		int length = cachedInfo.length;
-		if (index == length) {
-			System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length);
-			this.types[unannotatedLeafType.id] = cachedInfo;
-		}
-		// Add the new array type id stamping it.
-		TypeBinding arrayType = cachedInfo[index] = new ArrayBinding(unannotatedLeafType, dimensions, this.environment);
-		int typesLength = this.types.length;
-		if (this.typeid == typesLength)
-			System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
-		this.types[this.typeid] = new TypeBinding[1];
-		return (ArrayBinding) (this.types[arrayType.id = this.typeid++][0] = arrayType);
-	}
-
-	/* Note: parameters will not have type type annotations if lookup environment directly uses UTS as its typeSystem. However if this UTS is the underlying type system
-	   for an ATS, they may and we need to materialize the unannotated versions and work on them.
-	*/ 
-//{ObjectTeams: 2 parameters added:
-/* orig:
-	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) {
-  :giro */
-	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments,
-												ITeamAnchor teamAnchor, int valueParamPosition, ReferenceBinding enclosingType) {
-		if (teamAnchor == null && genericType instanceof DependentTypeBinding)
-			teamAnchor = ((DependentTypeBinding) genericType)._teamAnchor;
-// SH}
-		ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
-		int typeArgumentsLength = typeArguments == null ? 0: typeArguments.length;
-		TypeBinding [] unannotatedTypeArguments = typeArguments == null ? null : new TypeBinding[typeArgumentsLength];
-		for (int i = 0; i < typeArgumentsLength; i++) {
-			unannotatedTypeArguments[i] = getUnannotatedType(typeArguments[i]);
-		}
-		ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
-		
-		TypeBinding[] cachedInfo = this.types[unannotatedGenericType.id];  // by construction, cachedInfo != null now.
-		int index = 0;
-		for (int max = cachedInfo.length; index < max; index++) {
-			TypeBinding cachedType = cachedInfo[index];
-			if (cachedType == null) 
-				break;
-//{ObjectTeams: parameterized and/or anchored?
-/* orig:
-			if (!cachedType.isParameterizedType())
-				continue;
-  :giro */
-			if (!(cachedType instanceof ParameterizedTypeBinding)) // roles might answer 'false' to isParameterized(), still they are valid candidates, here
-				continue;
-			if (cachedType.isRawType() && unannotatedTypeArguments != null)
-				continue;
-			// also match team anchor if given:
-			if (!isRoleTypeMatch(teamAnchor, valueParamPosition, cachedType))
-				continue;
-//SH}
-			if (cachedType.enclosingType() == unannotatedEnclosingType && Util.effectivelyEqual(cachedType.typeArguments(), unannotatedTypeArguments))
-				return (ParameterizedTypeBinding) cachedType;
-		}
-
-		int length = cachedInfo.length;
-		if (index == length) {
-			System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length);
-			this.types[unannotatedGenericType.id] = cachedInfo;
-		}
-//{ObjectTeams: dependent type?
-/* orig:	
-		TypeBinding parameterizedType = cachedInfo[index] = new ParameterizedTypeBinding(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, this.environment);
-  :giro */
-		TypeBinding parameterizedType;
-		if (teamAnchor == null) {
-			parameterizedType =  new ParameterizedTypeBinding(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, this.environment);
-		} else {
-			if (genericType.isRole()) {
-				parameterizedType = new RoleTypeBinding(genericType, typeArguments, teamAnchor, enclosingType, this.environment);
-			} else {
-				parameterizedType = new DependentTypeBinding(genericType, typeArguments, teamAnchor, valueParamPosition, enclosingType, this.environment);
-			}
-		}
-		cachedInfo[index] = parameterizedType;
-// SH}
-		
-		int typesLength = this.types.length;
-		if (this.typeid == typesLength)
-			System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
-		this.types[this.typeid] = new TypeBinding[1];
-		return (ParameterizedTypeBinding) (this.types[parameterizedType.id = this.typeid++][0] = parameterizedType);
-	}
-
-//{ObjectTeams: compare role types:
-	boolean isRoleTypeMatch(ITeamAnchor teamAnchor, int valueParamPosition, TypeBinding cachedType) {
-		if (teamAnchor != null) {
-			if (!(cachedType instanceof DependentTypeBinding))
-				return false;
-			if (!((DependentTypeBinding)cachedType)._teamAnchor.hasSameBestNameAs(teamAnchor))
-				return false;
-		}
-		if (   valueParamPosition > -1 							// position specified, requires dependent type
-		    && !(cachedType instanceof DependentTypeBinding))
-			return false;
-		if (   (cachedType instanceof DependentTypeBinding)		// dependent type specified, positions must match
-		    && ((DependentTypeBinding)cachedType)._valueParamPosition != valueParamPosition)
-			return false;
-		if (teamAnchor == null && RoleTypeBinding.isRoleType(cachedType)) // role type found though not requested?
-			return false;
-		return true;
-	}
-//SH}
-
-	/* Note: parameters will not have type type annotations if lookup environment directly uses UTS as its typeSystem. However if this UTS is the underlying type system
-	   for an ATS, they may and we need to materialize the unannotated versions and work on them.
-	*/ 
-	public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) {
-		ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
-		ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
-	
-		TypeBinding[] cachedInfo = this.types[unannotatedGenericType.id];  // by construction, cachedInfo != null now.
-		int index = 0;
-		for (int max = cachedInfo.length; index < max; index++) {
-			TypeBinding cachedType = cachedInfo[index];
-			if (cachedType == null) 
-				break;
-			if (!cachedType.isRawType())
-				continue;
-			if (cachedType.enclosingType() == unannotatedEnclosingType)
-				return (RawTypeBinding) cachedType;
-		}
-
-		int length = cachedInfo.length;
-		if (index == length) {
-			System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length);
-			this.types[unannotatedGenericType.id] = cachedInfo;
-		}
-		
-		TypeBinding rawTytpe = cachedInfo[index] = new RawTypeBinding(unannotatedGenericType, unannotatedEnclosingType, this.environment);
-		int typesLength = this.types.length;
-		if (this.typeid == typesLength)
-			System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
-		this.types[this.typeid] = new TypeBinding[1];
-		return (RawTypeBinding) (this.types[rawTytpe.id = this.typeid++][0] = rawTytpe);
-	}
-
-	/* Note: parameters will not have type type annotations if lookup environment directly uses UTS as its typeSystem. However if this UTS is the underlying type system
-	   for an ATS, they may and we need to materialize the unannotated versions and work on them.
-	*/ 
-	public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) {
-		if (genericType == null) // pseudo wildcard denoting composite bounds for lub computation
-			genericType = ReferenceBinding.LUB_GENERIC;
-		
-		ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
-		int otherBoundsLength = otherBounds == null ? 0: otherBounds.length;
-		TypeBinding [] unannotatedOtherBounds = otherBounds == null ? null : new TypeBinding[otherBoundsLength];
-		for (int i = 0; i < otherBoundsLength; i++) {
-			unannotatedOtherBounds[i] = getUnannotatedType(otherBounds[i]);
-		}
-		TypeBinding unannotatedBound = bound == null ? null : getUnannotatedType(bound);
-
-		TypeBinding[] cachedInfo = this.types[unannotatedGenericType.id];  // by construction, cachedInfo != null now.
-		int index = 0;
-		for (int max = cachedInfo.length; index < max; index++) {
-			TypeBinding cachedType = cachedInfo[index];
-			if (cachedType == null) 
-				break;
-			if (!cachedType.isWildcard())
-				continue;
-			if (cachedType.rank() != rank || cachedType.boundKind() != boundKind || cachedType.bound() != unannotatedBound)
-				continue;
-			if (Util.effectivelyEqual(cachedType.additionalBounds(), unannotatedOtherBounds))
-				return (WildcardBinding) cachedType;
-		}
-
-		int length = cachedInfo.length;
-		if (index == length) {
-			System.arraycopy(cachedInfo, 0, cachedInfo = new TypeBinding[length * 2], 0, length);
-			this.types[unannotatedGenericType.id] = cachedInfo;
-		}
-		TypeBinding wildcard = cachedInfo[index] = new WildcardBinding(unannotatedGenericType, rank, unannotatedBound, unannotatedOtherBounds, boundKind, this.environment);
-	
-		int typesLength = this.types.length;
-		if (this.typeid == typesLength)
-			System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
-		this.types[this.typeid] = new TypeBinding[1];
-		return (WildcardBinding) (this.types[wildcard.id = this.typeid++][0] = wildcard);
-	}
-
-	/* Return a unique annotation binding for an annotation with either no or all default element-value pairs.
-	   We may return a resolved annotation when requested for unresolved one, but not vice versa. 
-	*/
-	public AnnotationBinding getAnnotationType(ReferenceBinding annotationType, boolean requiredResolved) {
-		AnnotationBinding annotation = (AnnotationBinding) this.annotationTypes.get(annotationType);
-		if (annotation == null) {
-			if (requiredResolved)
-				annotation = new AnnotationBinding(annotationType, Binding.NO_ELEMENT_VALUE_PAIRS);
-			else 
-				annotation = new UnresolvedAnnotationBinding(annotationType, Binding.NO_ELEMENT_VALUE_PAIRS, this.environment);
-			this.annotationTypes.put(annotationType, annotation);
-		}
-		if (requiredResolved)
-			annotation.resolve();
-		return annotation;
-	}
-
-	public void reset() {
-		this.annotationTypes = new SimpleLookupTable(16);
-		this.typeid = TypeIds.T_LastWellKnownTypeId;
-		this.types = new TypeBinding[TypeIds.T_LastWellKnownTypeId * 2][];
-	}
-	
-	public void updateCaches(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) {
-		final int unresolvedTypeId = unresolvedType.id;
-		if (unresolvedTypeId == TypeIds.NoId)
-			return;
-		if (this.types[unresolvedTypeId] != null && this.types[unresolvedTypeId][0] == unresolvedType) {
-			resolvedType.id = unresolvedTypeId;
-			this.types[unresolvedTypeId][0] = resolvedType;
-		}
-		if (this.annotationTypes.get(unresolvedType) != null) { // update the key
-			Object[] keys = this.annotationTypes.keyTable;
-			for (int i = 0, l = keys.length; i < l; i++) {
-				if (keys[i] == unresolvedType) {
-					keys[i] = resolvedType; // hashCode is based on compoundName so this works.
-					break;
-				}
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VoidTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VoidTypeBinding.java
new file mode 100644
index 0000000..0d12fa1
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VoidTypeBinding.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2013 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.lookup;
+
+// Give it an identity of its own to discriminate the fact that this type is not annotatable and so is a singleton.
+public class VoidTypeBinding extends BaseTypeBinding {
+
+	VoidTypeBinding() {
+		super(TypeIds.T_void, TypeConstants.VOID, new char[] { 'V' });
+	}
+	
+	public TypeBinding clone(TypeBinding enclosingType) {
+		return this;  // enforce solitude.
+	}
+	
+	public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
+		return; // reject misguided attempt.
+	}
+	
+	public TypeBinding unannotated() {
+		return this;
+	}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index d7c8b71..1f5f9cb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -7702,67 +7702,59 @@
 		annotation.sourceStart,
 		annotation.sourceEnd);
 }
-public void containingAnnotationMustHaveValue(ASTNode markerNode, ReferenceBinding containerAnnotationType) {
+public void containerAnnotationTypeMustHaveValue(ASTNode markerNode, ReferenceBinding containerAnnotationType) {
 	this.handle(
-		IProblem.ContainingAnnotationMustHaveValue,
+		IProblem.ContainerAnnotationTypeMustHaveValue,
 		new String[] {new String(containerAnnotationType.readableName())},
 		new String[] {new String(containerAnnotationType.shortReadableName())},
 		markerNode.sourceStart,
 		markerNode.sourceEnd);
 }
-public void containingAnnotationHasWrongValueType(ASTNode markerNode, ReferenceBinding containerAnnotationType, ReferenceBinding annotationType, TypeBinding returnType) {
+public void containerAnnotationTypeHasWrongValueType(ASTNode markerNode, ReferenceBinding containerAnnotationType, ReferenceBinding annotationType, TypeBinding returnType) {
 	this.handle(
-		IProblem.ContainingAnnotationHasWrongValueType,
+		IProblem.ContainerAnnotationTypeHasWrongValueType,
 		new String[] {new String(containerAnnotationType.readableName()), new String(annotationType.readableName()), new String(returnType.readableName())},
 		new String[] {new String(containerAnnotationType.shortReadableName()), new String(annotationType.shortReadableName()), new String(returnType.shortReadableName())},
 		markerNode.sourceStart,
 		markerNode.sourceEnd);
 }
-public void containingAnnotationHasNonDefaultMembers(ASTNode markerNode, ReferenceBinding containerAnnotationType, char[] selector) {
+public void containerAnnotationTypeHasNonDefaultMembers(ASTNode markerNode, ReferenceBinding containerAnnotationType, char[] selector) {
 	this.handle(
-		IProblem.ContainingAnnotationHasNonDefaultMembers,
+		IProblem.ContainerAnnotationTypeHasNonDefaultMembers,
 		new String[] {new String(containerAnnotationType.readableName()), new String(selector)},
 		new String[] {new String(containerAnnotationType.shortReadableName()), new String(selector)},
 		markerNode.sourceStart,
 		markerNode.sourceEnd);
 }
-public void containingAnnotationHasShorterRetention(ASTNode markerNode, ReferenceBinding annotationType, String annotationRetention, ReferenceBinding containerAnnotationType, String containerRetention) {
+public void containerAnnotationTypeHasShorterRetention(ASTNode markerNode, ReferenceBinding annotationType, String annotationRetention, ReferenceBinding containerAnnotationType, String containerRetention) {
 	this.handle(
-		IProblem.ContainingAnnotationHasShorterRetention,
+		IProblem.ContainerAnnotationTypeHasShorterRetention,
 		new String[] {new String(annotationType.readableName()), annotationRetention, new String(containerAnnotationType.readableName()), containerRetention},
 		new String[] {new String(annotationType.shortReadableName()), annotationRetention, new String(containerAnnotationType.shortReadableName()), containerRetention},
 		markerNode.sourceStart,
 		markerNode.sourceEnd);
 }
-public void repeatableAnnotationHasTargets(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType) {
+public void repeatableAnnotationTypeTargetMismatch(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType, String unmetTargets) {
 	this.handle(
-		IProblem.RepeatableAnnotationHasTargets,
-		new String[] {new String(annotationType.readableName()), new String(containerAnnotationType.readableName())},
-		new String[] {new String(annotationType.shortReadableName()), new String(containerAnnotationType.shortReadableName())},
-		markerNode.sourceStart,
-		markerNode.sourceEnd);
-}
-public void repeatableAnnotationTargetMismatch(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType, String unmetTargets) {
-	this.handle(
-		IProblem.RepeatableAnnotationTargetMismatch,
+		IProblem.RepeatableAnnotationTypeTargetMismatch,
 		new String[] {new String(annotationType.readableName()), new String(containerAnnotationType.readableName()), unmetTargets},
 		new String[] {new String(annotationType.shortReadableName()), new String(containerAnnotationType.shortReadableName()), unmetTargets},
 		markerNode.sourceStart,
 		markerNode.sourceEnd);
 }
 
-public void repeatableAnnotationIsDocumented(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType) {
+public void repeatableAnnotationTypeIsDocumented(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType) {
 	this.handle(
-		IProblem.RepeatableAnnotationIsDocumented,
+		IProblem.RepeatableAnnotationTypeIsDocumented,
 		new String[] {new String(annotationType.readableName()), new String(containerAnnotationType.readableName())},
 		new String[] {new String(annotationType.shortReadableName()), new String(containerAnnotationType.shortReadableName())},
 		markerNode.sourceStart,
 		markerNode.sourceEnd);
 }
 
-public void repeatableAnnotationIsInherited(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType) {
+public void repeatableAnnotationTypeIsInherited(ASTNode markerNode, ReferenceBinding annotationType, ReferenceBinding containerAnnotationType) {
 	this.handle(
-		IProblem.RepeatableAnnotationIsInherited,
+		IProblem.RepeatableAnnotationTypeIsInherited,
 		new String[] {new String(annotationType.readableName()), new String(containerAnnotationType.readableName())},
 		new String[] {new String(annotationType.shortReadableName()), new String(containerAnnotationType.shortReadableName())},
 		markerNode.sourceStart,
@@ -14201,7 +14193,7 @@
 }
 public void disallowedTargetForContainerAnnotation(Annotation annotation, TypeBinding containerAnnotationType) {
 	this.handle(
-		IProblem.DisallowedTargetForContainerAnnotation,
+		IProblem.DisallowedTargetForContainerAnnotationType,
 		new String[] {new String(annotation.resolvedType.readableName()), new String(containerAnnotationType.readableName())},
 		new String[] {new String(annotation.resolvedType.shortReadableName()), new String(containerAnnotationType.shortReadableName())},
 		annotation.sourceStart,
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index fb4a81f..27438a0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -748,16 +748,15 @@
 896 = Static methods are allowed in interfaces only at source level 1.8 or above
 
 897 = Duplicate annotation of non-repeatable type @{0}. Only annotation types marked @Repeatable can be used multiple times at one target.
-898 = The repeatable annotation @{0} is disallowed for this location since its container annotation @{1} is disallowed at this location
-899 = The repeatable annotation @{0} may not be repeated where its container annotation @{1} is also used directly
-902 = The value method in the containing annotation @{0} must be of type {1}[] but is {2}
-903 = The containing annotation @{0} must declare a member value()
-904 = The containing annotation @{0} must declare a default value for the annotation attribute ''{1}''
-905 = Retention ''{1}'' of @{0} is longer than the retention of the containing annotation @{2}, which is ''{3}''
-906 = The repeatable annotation @{0} has a @Target annotation, @{1} does not
-907 = The containing annotation @{1} is allowed at targets where the repeatable annotation @{0} is not: {2}
-908 = The repeatable annotation @{0} is marked @Documented, but the containing annotation @{1} is not
-909 = The repeatable annotation @{0} is marked @Inherited, but the containing annotation @{1} is not
+898 = The annotation @{0} cannot be repeated at this location since its container annotation type @{1} is disallowed at this location
+899 = The repeatable annotation @{0} may not be repeated where its container annotation type @{1} is also used directly
+902 = The value method in the container annotation type @{0} must be of type {1}[] but is {2}
+903 = The container annotation type @{0} must declare a member value()
+904 = The container annotation type @{0} must declare a default value for the annotation attribute ''{1}''
+905 = Retention ''{1}'' of @{0} is longer than the retention of its container annotation type @{2}, which is ''{3}''
+906 = The container annotation type @{1} is allowed at targets where the repeatable annotation type @{0} is not: {2}
+907 = The repeatable annotation type @{0} is marked @Documented, but its container annotation type @{1} is not
+908 = The repeatable annotation type @{0} is marked @Inherited, but its container annotation type @{1} is not
 
 ### NULL ANNOTATIONS
 910 = Null type mismatch: required ''{0}'' but the provided value is null
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/WeakenedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/WeakenedTypeBinding.java
index 264c49c..be466ee 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/WeakenedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lookup/WeakenedTypeBinding.java
@@ -50,7 +50,6 @@
 		if (this.type instanceof WeakenedTypeBinding)
 			this.type = ((WeakenedTypeBinding)this.type).type;
 		initializeDependentType(declaredType._teamAnchor, declaredType._valueParamPosition);
-		this.id = weakenedType.id;
 	}
 
 	/** Factory method. */
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
index 7ed5c30..6230e41 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
@@ -1156,31 +1156,32 @@
 
 	/**
 	 * Creates and returns a new unparented array type node with the given
-	 * component type, which may be another array type for levels less than JLS8.
-	 * For JLS8 and above this type has to be an annotatable type.
+	 * element type, which cannot be an array type for API levels JLS8 and later.
+	 * <p>
+	 * For JLS4 and before, the given component type may be another array type.
 	 *
-	 * @param type the component type (possibly another array type) for level less than JLS8, 
-	 * a <code>AnnotatableType</code>  for JLS8 and above
+	 * @param elementType element type for API level JLS8 and later, or the
+	 * component type (possibly another array type) for levels less than JLS8
 	 * @return a new unparented array type node
 	 * @exception IllegalArgumentException if:
 	 * <ul>
 	 * <li>the node belongs to a different AST</li>
 	 * <li>the node already has a parent</li>
-	 * <li> level is greater than or equal to JLS8 and type not an array type</li>
+	 * <li>API level is JLS8 or later and type is an array type</li>
 	 * </ul>
 	 */
-	public ArrayType newArrayType(Type type) {
+	public ArrayType newArrayType(Type elementType) {
 		ArrayType result;
 		if (this.apiLevel < AST.JLS8) {
 			result = new ArrayType(this);
-			setArrayComponentType(result, type);
+			setArrayComponentType(result, elementType);
 			return result;
 		}
-		if (type.isArrayType()) {
+		if (elementType.isArrayType()) {
 			throw new IllegalArgumentException();
 		}
 		result = new ArrayType(this);
-		result.setElementType(type);
+		result.setElementType(elementType);
 		return result;
 	}
 
@@ -1188,11 +1189,11 @@
 	 * Creates and returns a new unparented array type node with the given
 	 * element type and number of (additional) dimensions.
 	 * <p>
-	 * Note that if the element type passed in is an array type, the
+	 * For JLS4 and before, the element type passed in can be an array type, but in that case, the
 	 * element type of the result will not be the same as what was passed in.
 	 * </p>
 	 *
-	 * @param elementType the element type (can be an array type for JLS8. For level JLS8 and above this should be an <code>AnnotatableType</code>)
+	 * @param elementType the element type (cannot be an array type for JLS8 and later)
 	 * @param dimensions the number of dimensions, a positive number
 	 * @return a new unparented array type node
 	 * @exception IllegalArgumentException if:
@@ -1202,7 +1203,7 @@
 	 * <li>the element type is null</li>
 	 * <li>the number of dimensions is lower than 1</li>
 	 * <li>the number of dimensions is greater than 1000</li>
-	 * <li>for levels from JLS8 and later, if the element type is not an array type </li>
+	 * <li>for levels from JLS8 and later, if the element type is an array type </li>
 	 * </ul>
 	 */
 	public ArrayType newArrayType(Type elementType, int dimensions) {
@@ -1230,7 +1231,7 @@
 		result.setElementType(elementType);
 		// index starting from 1 since there is a dimension already available by default.
 		for (int i = 1; i < dimensions; ++i) {
-			result.dimensions().add(new ExtraDimension(this));
+			result.dimensions().add(new Dimension(this));
 		}
 		return result;
 
@@ -1595,10 +1596,10 @@
 	}
 
 	/**
-	 * Creates and returns a new unparented annotatable extra dimension node
+	 * Creates and returns a new unparented annotatable dimension node
 	 * (Supported only in JLS8 level).
 	 *
-	 * @return a new unparented annotatable extra dimension node
+	 * @return a new unparented annotatable dimension node
 	 * @exception IllegalArgumentException if:
 	 * <ul>
 	 * <li>the node belongs to a different AST</li>
@@ -1608,8 +1609,8 @@
 	 *            in a JLS2, JLS3 or JLS4 AST
 	 * @since 3.9 BETA_JAVA8
 	 */
-	public ExtraDimension newExtraDimension() {
-		ExtraDimension result = new ExtraDimension(this);
+	public Dimension newDimension() {
+		Dimension result = new Dimension(this);
 		return result;
 	}
 
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
index 5cc6cdb..d649a41 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
@@ -1098,17 +1098,20 @@
 		 * See PR http://bugs.eclipse.org/bugs/show_bug.cgi?id=23284
 		 */
 		if (isVarArgs) {
+			Dimension lastDimension = null;
+			if (this.ast.apiLevel() >= AST.JLS8) {
+				if (type.isArrayType()) { // should always be true
+					List dimensions = ((ArrayType) type).dimensions();
+					if (!dimensions.isEmpty()) {
+						lastDimension = (Dimension) dimensions.get(dimensions.size() - 1);
+					}
+				}
+			}
 			setTypeForSingleVariableDeclaration(variableDecl, type, extraDimensions + 1);
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=391898
 			if (this.ast.apiLevel() >= AST.JLS8) {
-				List annotations  = null;
-				if (type.isAnnotatable()) {
-					annotations = ((AnnotatableType) type).annotations();
-				} else if (type.isArrayType()) {
-					ArrayType arrayType = (ArrayType) type;
-					annotations = arrayType.dimensions().isEmpty() ? null : ((arrayType.getDimensionAt(0)).annotations());
-				}
-				if (annotations != null) {
+				if (lastDimension != null) { // should always be true
+					List annotations = lastDimension.annotations();
 					Iterator iter = annotations.iterator();
 					while (iter.hasNext()) {
 						Annotation annotation = (Annotation) iter.next();
@@ -3632,9 +3635,9 @@
 		return variableDecl;
 	}
 
-	private ExtraDimension convertToExtraDimensions(int start, int end, org.eclipse.jdt.internal.compiler.ast.Annotation[] annotation) {
+	private Dimension convertToDimensions(int start, int end, org.eclipse.jdt.internal.compiler.ast.Annotation[] annotation) {
 		int length = annotation == null ? 0 : annotation.length;
-		ExtraDimension dimension = this.ast.newExtraDimension();
+		Dimension dimension = this.ast.newDimension();
 		for (int i = 0; i < length; i++) {
 			Annotation annot = convert(annotation[i]);
 			dimension.annotations().add(annot);
@@ -3737,14 +3740,14 @@
 			org.eclipse.jdt.internal.compiler.ast.Annotation[][] annotationsOnDims = type.getAnnotationsOnDimensions(true);
 			int length = (annotationsOnDims == null) ? 0 : annotationsOnDims.length;
 			for (int i = (length - extraDimension); i < length; i++) {
-				ExtraDimension dim = convertToExtraDimensions(start, end, (annotationsOnDims == null) ? null : annotationsOnDims[i]);
+				Dimension dim = convertToDimensions(start, end, (annotationsOnDims == null) ? null : annotationsOnDims[i]);
 				extraAnnotatedDimensions.add(dim);
 				start = dim.getStartPosition() + dim.getLength();
 			}
 		}
 	}
 
-	private void setTypeAnnotationsOnDimension(ExtraDimension currentDimension, org.eclipse.jdt.internal.compiler.ast.Annotation[][] annotationsOnDimensions, int dimension) {
+	private void setTypeAnnotationsOnDimension(Dimension currentDimension, org.eclipse.jdt.internal.compiler.ast.Annotation[][] annotationsOnDimensions, int dimension) {
 		if (annotationsOnDimensions == null) return;
 		org.eclipse.jdt.internal.compiler.ast.Annotation[] annotations = annotationsOnDimensions[dimension];
 		if (annotations != null) {
@@ -3766,7 +3769,7 @@
 		
 		start = endElement;
 		for (int i = 0; i < dimensions.size(); i++) {
-			ExtraDimension currentDimension = (ExtraDimension) dimensions.get(i);
+			Dimension currentDimension = (Dimension) dimensions.get(i);
 			setTypeAnnotationsOnDimension(currentDimension, annotationsOnDimensions, i);
 			retrieveDimensionAndSetPositions(start, end, currentDimension);
 			start = currentDimension.getStartPosition() + currentDimension.getLength();
@@ -5143,7 +5146,7 @@
 		return dimensions;
 	}
 
-	protected void retrieveDimensionAndSetPositions(int start, int end, ExtraDimension dim) {
+	protected void retrieveDimensionAndSetPositions(int start, int end, Dimension dim) {
 		this.scanner.resetTo(start, end);
 		int token;
 		int count = 0, lParenCount = 0;
@@ -6111,23 +6114,23 @@
 	/** extracts the subArrayType for a given declaration for AST levels less
 	 * @param arrayType parent type
 	 * @param remainingDimensions 
-	 * @param extraDimensions
+	 * @param dimensionsToRemove
 	 * @return an ArrayType
 	 */
-	private ArrayType extractSubArrayType(ArrayType arrayType, int remainingDimensions, int extraDimensions) {
+	private ArrayType extractSubArrayType(ArrayType arrayType, int remainingDimensions, int dimensionsToRemove) {
 		ArrayType subArrayType = arrayType;
 		int start = subArrayType.getStartPosition();
 		if (this.ast.apiLevel() < AST.JLS8) {
-			while (extraDimensions > 0 ) {
+			while (dimensionsToRemove > 0 ) {
 				subArrayType = (ArrayType) componentType(subArrayType);
-				extraDimensions--;
+				dimensionsToRemove--;
 			}
 			updateInnerPositions(subArrayType, remainingDimensions);
 		} else {
 			List dimensions = subArrayType.dimensions();
-			while (extraDimensions > 0 ) {
+			while (dimensionsToRemove > 0 ) {
 				dimensions.remove(dimensions.size() - 1);
-				extraDimensions--;
+				dimensionsToRemove--;
 			}
 		}
 		int end = retrieveProperRightBracketPosition(remainingDimensions, start);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
index 87246df..b8e1e9a 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
@@ -738,6 +738,29 @@
 	 * @return <code>true</code> if the subtree matches, or
 	 *   <code>false</code> if they do not match or the other object has a
 	 *   different node type or is <code>null</code>
+	 * @since 3.9 BETA_JAVA8
+	 */
+	public boolean match(Dimension node, Object other) {
+		if (!(other instanceof Dimension)) {
+			return false;
+		}
+		Dimension o = (Dimension) other;
+		return safeSubtreeListMatch(node.annotations(), o.annotations());
+	}
+
+	/**
+	 * Returns whether the given node and the other object match.
+	 * <p>
+	 * The default implementation provided by this class tests whether the
+	 * other object is a node of the same type with structurally isomorphic
+	 * child subtrees. Subclasses may override this method as needed.
+	 * </p>
+	 *
+	 * @param node the node
+	 * @param other the other object, or <code>null</code>
+	 * @return <code>true</code> if the subtree matches, or
+	 *   <code>false</code> if they do not match or the other object has a
+	 *   different node type or is <code>null</code>
 	 */
 	public boolean match(DoStatement node, Object other) {
 		if (!(other instanceof DoStatement)) {
@@ -918,29 +941,6 @@
 	 * @return <code>true</code> if the subtree matches, or
 	 *   <code>false</code> if they do not match or the other object has a
 	 *   different node type or is <code>null</code>
-	 * @since 3.9 BETA_JAVA8
-	 */
-	public boolean match(ExtraDimension node, Object other) {
-		if (!(other instanceof ExtraDimension)) {
-			return false;
-		}
-		ExtraDimension o = (ExtraDimension) other;
-		return safeSubtreeListMatch(node.annotations(), o.annotations());
-	}
-
-	/**
-	 * Returns whether the given node and the other object match.
-	 * <p>
-	 * The default implementation provided by this class tests whether the
-	 * other object is a node of the same type with structurally isomorphic
-	 * child subtrees. Subclasses may override this method as needed.
-	 * </p>
-	 *
-	 * @param node the node
-	 * @param other the other object, or <code>null</code>
-	 * @return <code>true</code> if the subtree matches, or
-	 *   <code>false</code> if they do not match or the other object has a
-	 *   different node type or is <code>null</code>
 	 */
 	public boolean match(FieldAccess node, Object other) {
 		if (!(other instanceof FieldAccess)) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java
index 8300e26..7a41baa 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java
@@ -837,12 +837,12 @@
 
 	/**
 	 * Node type constant indicating a node of type
-	 * <code>ExtraDimension</code>.
+	 * <code>Dimension</code>.
 	 *
-	 * @see ExtraDimension
+	 * @see Dimension
 	 * @since 3.9 BETA_JAVA8
 	 */
-	public static final int EXTRA_DIMENSION = 85;
+	public static final int DIMENSION = 85;
 
 	/**
 	 * Node type constant indicating a node of type
@@ -1053,8 +1053,8 @@
 				return ContinueStatement.class;
 			case CREATION_REFERENCE :
 				return CreationReference.class;
-			case UNION_TYPE :
-				return UnionType.class;
+			case DIMENSION:
+				return Dimension.class;
 			case DO_STATEMENT :
 				return DoStatement.class;
 			case EMPTY_STATEMENT :
@@ -1069,8 +1069,6 @@
 				return ExpressionMethodReference.class;
 			case EXPRESSION_STATEMENT :
 				return ExpressionStatement.class;
-			case EXTRA_DIMENSION:
-				return ExtraDimension.class;
 			case FIELD_ACCESS :
 				return FieldAccess.class;
 			case FIELD_DECLARATION :
@@ -1183,6 +1181,8 @@
 				return TypeLiteral.class;
 			case TYPE_PARAMETER :
 				return TypeParameter.class;
+			case UNION_TYPE :
+				return UnionType.class;
 			case VARIABLE_DECLARATION_EXPRESSION :
 				return VariableDeclarationExpression.class;
 			case VARIABLE_DECLARATION_FRAGMENT :
@@ -1361,11 +1361,15 @@
 	private StructuralPropertyDescriptor location = null;
 
 	/** Internal convenience constant indicating that there is definite risk of cycles.
+	 * @see ChildPropertyDescriptor#cycleRisk()
+	 * @see ChildListPropertyDescriptor#cycleRisk()
 	 * @since 3.0
 	 */
 	static final boolean CYCLE_RISK = true;
 
 	/** Internal convenience constant indicating that there is no risk of cycles.
+	 * @see ChildPropertyDescriptor#cycleRisk()
+	 * @see ChildListPropertyDescriptor#cycleRisk()
 	 * @since 3.0
 	 */
 	static final boolean NO_CYCLE_RISK = false;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java
index 7481d0b..53c34f7 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java
@@ -561,6 +561,23 @@
 	 * @return <code>true</code> if the children of this node should be
 	 * visited, and <code>false</code> if the children of this node should
 	 * be skipped
+	 * @since 3.9 BETA_JAVA8
+	 */
+	public boolean visit(Dimension node) {
+		return true;
+	}
+
+	/**
+	 * Visits the given type-specific AST node.
+	 * <p>
+	 * The default implementation does nothing and return true.
+	 * Subclasses may reimplement.
+	 * </p>
+	 *
+	 * @param node the node to visit
+	 * @return <code>true</code> if the children of this node should be
+	 * visited, and <code>false</code> if the children of this node should
+	 * be skipped
 	 */
 	public boolean visit(DoStatement node) {
 		return true;
@@ -677,23 +694,6 @@
 	 * @return <code>true</code> if the children of this node should be
 	 * visited, and <code>false</code> if the children of this node should
 	 * be skipped
-	 * @since 3.9 BETA_JAVA8
-	 */
-	public boolean visit(ExtraDimension node) {
-		return true;
-	}
-
-	/**
-	 * Visits the given type-specific AST node.
-	 * <p>
-	 * The default implementation does nothing and return true.
-	 * Subclasses may reimplement.
-	 * </p>
-	 *
-	 * @param node the node to visit
-	 * @return <code>true</code> if the children of this node should be
-	 * visited, and <code>false</code> if the children of this node should
-	 * be skipped
 	 */
 	public boolean visit(FieldAccess node) {
 		return true;
@@ -2354,7 +2354,7 @@
 	 * @param node the node to visit
 	 * @since 3.9 BETA_JAVA8
 	 */
-	public void endVisit(ExtraDimension node) {
+	public void endVisit(Dimension node) {
 		// do nothing by default
 	}
 
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java
index c3e3f75..a99b8b4 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java
@@ -21,15 +21,27 @@
 /**
  * Type node for an array type.
  * <p>
- * Array types are expressed in a recursive manner, one dimension at a time. From JLS8 onwards,
- * instead of this recursive manner, arrays are represented by a base element type (which cannot
- * be an Array type) and a list of dimensions each of which may have a list of annotations.
+ * In JLS8 and later, array types are represented by a base element type (which cannot
+ * be an array type) and a list of dimensions, each of which may have a list of annotations.
  * </p>
  * <pre>
  * ArrayType: 
- *    Type ExtraDimension { ExtraDimension }
+ *    Type Dimension <b>{</b> Dimension <b>}</b>
  * </pre>
+ * 
+ * In JLS4 and before, array types were expressed in a recursive manner, one dimension at a time:
+ * <pre>
+ * ArrayType:
+ *    Type <b>[</b> <b>]</b></pre>
  *
+ * This structure became untenable with the advent of type-use annotations, because
+ * array dimensions bind from left to right, whereas a recursive structure binds from right to left.
+ * <p>
+ * Example:<br>
+ * <code>int @A[] @B[] @C[]</code><br>
+ * is an <code>@A</code>-array of <code>int @B[] @C[]</code>,
+ * but such a component type is not representable by nested <code>ArrayType</code>s with contiguous source ranges.
+ * 
  * @since 2.0
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
@@ -37,7 +49,7 @@
 
 	/**
 	 * The "componentType" structural property of this node type (child type: {@link Type}).
-	 * Not supported from JLS8 onwards.
+	 * @deprecated In the JLS8 API, this property is replaced by {@link #ELEMENT_TYPE_PROPERTY} and {@link #DIMENSIONS_PROPERTY}.
 	 * @since 3.0
 	 */
 	public static final ChildPropertyDescriptor COMPONENT_TYPE_PROPERTY =
@@ -45,17 +57,18 @@
 
 	/**
 	 * The "elementType" structural property of this node type (child type: {@link Type}) (added in JLS8 API).
+	 * Cannot be an array type.
 	 * @since 3.9 BETA_JAVA8
 	 */
 	public static final ChildPropertyDescriptor ELEMENT_TYPE_PROPERTY =
 			new ChildPropertyDescriptor(ArrayType.class, "elementType", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$	
 	
 	/**
-	 * The "dimensions" structural property of this node type (element type: {@link ExtraDimension}) (added in JLS8 API).
+	 * The "dimensions" structural property of this node type (element type: {@link Dimension}) (added in JLS8 API).
 	 * @since 3.9 BETA_JAVA8
 	 */
 	public static final ChildListPropertyDescriptor DIMENSIONS_PROPERTY =
-			new ChildListPropertyDescriptor(ArrayType.class, "dimensions", ExtraDimension.class, CYCLE_RISK); //$NON-NLS-1$	
+			new ChildListPropertyDescriptor(ArrayType.class, "dimensions", Dimension.class, CYCLE_RISK); //$NON-NLS-1$	
 	/**
 	 * A list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor}),
@@ -106,14 +119,14 @@
 	}
 
 	/**
-	 * The component type; lazily initialized; defaults to a simple type with
-	 * an unspecified, but legal, name. reused for element type from JLS8 onwards.
+	 * The element type (before JLS8: component type); lazily initialized; defaults to a simple type with
+	 * an unspecified, but legal, name.
 	 */
-	private Type componentType = null;
+	private Type type = null;
 
 	/**
-	 * List of extra dimensions this node has with optional annotations
-	 * (element type: {@link ExtraDimension}).
+	 * List of dimensions this node has with optional annotations
+	 * (element type: {@link Dimension}).
 	 * Null before JLS8. Added in JLS8; defaults to a list with one element
 	 * (see constructor).
 	 * 
@@ -135,7 +148,7 @@
 		if (ast.apiLevel >= AST.JLS8) {
 			this.dimensions = new ASTNode.NodeList(DIMENSIONS_PROPERTY);
 			// single dimension array is the default
-			this.dimensions().add(this.ast.newExtraDimension());
+			this.dimensions().add(this.ast.newDimension());
 		}
 	}
 
@@ -155,7 +168,7 @@
 		unsupportedIn2_3_4();
 		this.dimensions = new ASTNode.NodeList(DIMENSIONS_PROPERTY);
 		for (int i = 0; i < dimensions; ++i) {
-			this.dimensions().add(this.ast.newExtraDimension());
+			this.dimensions().add(this.ast.newDimension());
 		}
 	}
 
@@ -255,25 +268,27 @@
 	 * may be another array type.
 	 *
 	 * @return the component type node
-	 * @deprecated from JLS8 and later, the recursive structure is not valid
+	 * @exception UnsupportedOperationException if this operation is used in
+	 * an AST later than JLS4
+	 * @deprecated In the JLS8 API, the recursive structure is not valid.
 	 */
 	public Type getComponentType() {
 		supportedOnlyIn2_3_4();
-		return internalGetComponentType(COMPONENT_TYPE_PROPERTY);
+		return internalGetType(COMPONENT_TYPE_PROPERTY);
 	}
 
-	private Type internalGetComponentType(ChildPropertyDescriptor property) {
-		if (this.componentType == null) {
+	private Type internalGetType(ChildPropertyDescriptor property) {
+		if (this.type == null) {
 			// lazy init must be thread-safe for readers
 			synchronized (this) {
-				if (this.componentType == null) {
+				if (this.type == null) {
 					preLazyInit();
-					this.componentType = new SimpleType(this.ast);
-					postLazyInit(this.componentType, property);
+					this.type = new SimpleType(this.ast);
+					postLazyInit(this.type, property);
 				}
 			}
 		}
-		return this.componentType;
+		return this.type;
 	}
 
 	/**
@@ -287,30 +302,31 @@
 	 * <li>the node already has a parent</li>
 	 * <li>a cycle in would be created</li>
 	 * </ul>
-	 * @deprecated from JLS8 and later, the recursive structure is not valid
+	 * @exception UnsupportedOperationException if this operation is used in
+	 * an AST later than JLS4
+	 * @deprecated In the JLS8 API, the recursive structure is not valid.
 	 */
 	public void setComponentType(Type componentType) {
 		supportedOnlyIn2_3_4();
 		if (componentType == null) {
 			throw new IllegalArgumentException();
 		}
-		internalSetComponentType(componentType, COMPONENT_TYPE_PROPERTY);
+		internalSetType(componentType, COMPONENT_TYPE_PROPERTY);
 	}
 
-	private void internalSetComponentType(Type type, ChildPropertyDescriptor property) {
-		ASTNode oldChild = this.componentType;
-		preReplaceChild(oldChild, type, property);
-		this.componentType = type;
-		postReplaceChild(oldChild, type, property);
+	private void internalSetType(Type componentType, ChildPropertyDescriptor property) {
+		ASTNode oldChild = this.type;
+		preReplaceChild(oldChild, componentType, property);
+		this.type = componentType;
+		postReplaceChild(oldChild, componentType, property);
 	}
 
 	/**
 	 * Returns the element type of this array type. The element type is
 	 * never an array type.
 	 * <p>
-	 * This is a convenience method that descends a chain of nested array types
-	 * until it reaches a non-array type until JLS4. From JLS8 and later, this returns the
-	 * element type directly.
+	 * In JLS4 and earlier, this is a convenience method that descends a chain of nested array types
+	 * until it reaches a non-array type.
 	 * </p>
 	 *
 	 * @return the element type node
@@ -323,7 +339,7 @@
 			}
 			return t;
 		}
-		return internalGetComponentType(ELEMENT_TYPE_PROPERTY);
+		return internalGetType(ELEMENT_TYPE_PROPERTY);
 	}
 
 	/**
@@ -336,21 +352,22 @@
 	 * <li>the node already has a parent</li>
 	 * <li>the node is an array type</li>
 	 * </ul>
+	 * @exception UnsupportedOperationException if this operation is used below JLS8
 	 * @since 3.9 BETA_JAVA8
 	 */
 	public void setElementType(Type type) {
+		unsupportedIn2_3_4();
 		if (type == null || type instanceof ArrayType) {
 			throw new IllegalArgumentException();
 		}
-		internalSetComponentType(type, ELEMENT_TYPE_PROPERTY);
+		internalSetType(type, ELEMENT_TYPE_PROPERTY);
 	}
 
 	/**
 	 * Returns the number of dimensions in this array type.
 	 * <p>
-	 * This is a convenience method that descends a chain of nested array types
-	 * until it reaches a non-array type (until JLS4). From JLS8 onwards, 
-	 * this returns the size of the dimensions list.
+	 * In JLS4 and earlier, this is a convenience method that descends a chain of nested array types
+	 * until it reaches a non-array type.
 	 * </p>
 	 *
 	 * @return the number of dimensions (always positive)
@@ -369,29 +386,9 @@
 	}
 
 	/**
-	 * Returns the dimension d in this array type.
-	 * <p>
-	 * This is a convenience method that returns the dimension at the given number d.
-	 * </p>
-	 * @param d dimension no
-	 * @return Dimension at number d, null if d out of range
-	 * 
-	 * @since 3.9 BETA_JAVA8
-	 */
-	public ExtraDimension getDimensionAt(int d) {
-		unsupportedIn2_3_4();
-		ExtraDimension extraDimension = null;
-		int n = getDimensions() - 1;
-		if (d >= 0 && d <= n) {
-			extraDimension = (ExtraDimension) dimensions().get(n - d);
-		}
-		return extraDimension;
-	}
-
-	/**
 	 * Returns the live ordered list of dimensions with optional annotations (added in JLS8 API).
 	 * 
-	 * @return the live list of dimensions with optional annotations (element type: {@link ExtraDimension})
+	 * @return the live list of dimensions with optional annotations (element type: {@link Dimension})
 	 * @exception UnsupportedOperationException if this operation is used below JLS8
 	 * @since 3.9 BETA_JAVA8
 	 */
@@ -416,7 +413,7 @@
 	int treeSize() {
 		return
 			memSize()
-			+ (this.componentType == null ? 0 : (this.ast.apiLevel() < AST.JLS8 ? getComponentType().treeSize() : getElementType().treeSize())
+			+ (this.type == null ? 0 : (this.ast.apiLevel() < AST.JLS8 ? getComponentType().treeSize() : getElementType().treeSize())
 			+ (this.dimensions == null ? 0 : this.dimensions.listSize()));
 	}
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java
index c8bffe5..1594d42 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java
@@ -95,6 +95,10 @@
 	public void endVisit(CreationReference node) {
 		endVisitNode(node);
 	}
+	public void endVisit(Dimension node) {
+		endVisitNode(node);
+	}
+
 	public void endVisit(DoStatement node) {
 		endVisitNode(node);
 	}
@@ -116,9 +120,6 @@
 	public void endVisit(ExpressionStatement node) {
 		endVisitNode(node);
 	}
-	public void endVisit(ExtraDimension node) {
-		endVisitNode(node);
-	}
 	public void endVisit(FieldAccess node) {
 		endVisitNode(node);
 	}
@@ -377,6 +378,10 @@
 	public boolean visit(CreationReference node) {
 		return visitNode(node);
 	}
+	public boolean visit(Dimension node) {
+		return visitNode(node);
+	}
+
 	public boolean visit(DoStatement node) {
 		return visitNode(node);
 	}
@@ -398,9 +403,6 @@
 	public boolean visit(ExpressionStatement node) {
 		return visitNode(node);
 	}
-	public boolean visit(ExtraDimension node) {
-		return visitNode(node);
-	}
 	public boolean visit(FieldAccess node) {
 		return visitNode(node);
 	}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExtraDimension.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Dimension.java
similarity index 83%
rename from org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExtraDimension.java
rename to org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Dimension.java
index 306abe9..eb91189 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExtraDimension.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Dimension.java
@@ -18,29 +18,31 @@
 import java.util.List;
 
 /**
- * The extra dimension node. An extra dimension, represented as <b>[]</b>, can have
- * type annotations. This node type is supported only in JLS8 or later.
+ * AST node for an array dimension (added in JLS8 API).
  * <p>
- * The extra dimension node is used to represent an extra dimension in the following node types:
- * {@link SingleVariableDeclaration}, {@link VariableDeclarationFragment}, {@link MethodDeclaration}.
- * It is not used for annotations on an {@link ArrayType}, since that type extends {@link AnnotatableType} now.
+ * A dimension, represented as <b>[]</b>, can have type annotations. The dimension node is used for:
  * </p>
+ * <ul>
+ * <li>the dimensions of an {@link ArrayType}</li>
+ * <li>extra dimension in the following node types:
+ * {@link SingleVariableDeclaration}, {@link VariableDeclarationFragment}, {@link MethodDeclaration}</li>
+ * </ul>
  * 
  * <pre>
- * ExtraDimension:
+ * Dimension:
  * 	{ Annotation } <b>[]</b>
  * </pre>
  *
  * @since 3.9 BETA_JAVA8
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
-public class ExtraDimension extends ASTNode {
+public class Dimension extends ASTNode {
 
 	/**
 	 * The "annotations" structural property of this node type (element type: {@link Annotation}).
 	 */
 	public static final ChildListPropertyDescriptor ANNOTATIONS_PROPERTY =
-		new ChildListPropertyDescriptor(ExtraDimension.class, "annotations", Annotation.class, NO_CYCLE_RISK); //$NON-NLS-1$
+		new ChildListPropertyDescriptor(Dimension.class, "annotations", Annotation.class, NO_CYCLE_RISK); //$NON-NLS-1$
 
 	/**
 	 * A list of property descriptors (element type:
@@ -51,7 +53,7 @@
 
 	static {
 		List propertyList = new ArrayList(2);
-		createPropertyList(ExtraDimension.class, propertyList);
+		createPropertyList(Dimension.class, propertyList);
 		addProperty(ANNOTATIONS_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS_8_0 = reapPropertyList(propertyList);
 	}
@@ -76,8 +78,7 @@
 	private ASTNode.NodeList annotations = new ASTNode.NodeList(ANNOTATIONS_PROPERTY);
 
 	/**
-	 * Creates a new extra dimension node (Supported only in level
-	 * JLS8 or above).
+	 * Creates a new dimension node (supported only in level JLS8 or above).
 	 * <p>
 	 * N.B. This constructor is package-private.
 	 * </p>
@@ -86,7 +87,7 @@
 	 * @exception UnsupportedOperationException if this operation is used
 	 *            in a JLS2, JLS3 or JLS4 AST
 	 */
-	ExtraDimension(AST ast) {
+	Dimension(AST ast) {
 		super(ast);
 		unsupportedIn2_3_4();
 	}
@@ -113,14 +114,14 @@
 	 * Method declared on ASTNode.
 	 */
 	final int getNodeType0() {
-		return EXTRA_DIMENSION;
+		return DIMENSION;
 	}
 
 	/* (omit javadoc for this method)
 	 * Method declared on ASTNode.
 	 */
 	ASTNode clone0(AST target) {
-		ExtraDimension result = new ExtraDimension(target);
+		Dimension result = new Dimension(target);
 		result.annotations().addAll(
 				ASTNode.copySubtrees(target, annotations()));
 		return result;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java
index aa45e2f..bd837c7 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java
@@ -28,14 +28,14 @@
  *    [ Javadoc ] { ExtendedModifier } [ <b>&lt;</b> TypeParameter { <b>,</b> TypeParameter } <b>&gt;</b> ] ( Type | <b>void</b> )
  *        Identifier <b>(</b>
  *            [ ReceiverParameter <b>,</b> ] [ FormalParameter { <b>,</b> FormalParameter } ]
- *        <b>)</b> { ExtraDimension }
+ *        <b>)</b> { Dimension }
  *        [ <b>throws</b> Type { <b>,</b> Type } ]
  *        ( Block | <b>;</b> )
  * ConstructorDeclaration:
  *    [ Javadoc ] { ExtendedModifier } [ <b>&lt;</b> TypeParameter { <b>,</b> TypeParameter } <b>&gt;</b> ]
  *        Identifier <b>(</b>
  *            [ ReceiverParameter <b>,</b> ] [ FormalParameter { <b>,</b> FormalParameter } ]
- *        <b>)</b> { ExtraDimension }
+ *        <b>)</b> { Dimension }
  *        [ <b>throws</b> Type { <b>,</b> Type } ]
  *        ( Block | <b>;</b> )
  * </pre>
@@ -125,11 +125,11 @@
 		new SimplePropertyDescriptor(MethodDeclaration.class, "extraDimensions", int.class, MANDATORY); //$NON-NLS-1$
 	
 	/**
-	 * The "extraDimensions2" structural property of this node type (element type: {@link ExtraDimension}) (added in JLS8 API).
+	 * The "extraDimensions2" structural property of this node type (element type: {@link Dimension}) (added in JLS8 API).
 	 * @since 3.9 BETA_JAVA8
 	 */
 	public static final ChildListPropertyDescriptor EXTRA_DIMENSIONS2_PROPERTY =
-			new ChildListPropertyDescriptor(MethodDeclaration.class, "extraDimensions2", ExtraDimension.class, NO_CYCLE_RISK); //$NON-NLS-1$
+			new ChildListPropertyDescriptor(MethodDeclaration.class, "extraDimensions2", Dimension.class, NO_CYCLE_RISK); //$NON-NLS-1$
 
 	/**
 	 * The "typeParameters" structural property of this node type (element type: {@link TypeParameter}) (added in JLS3 API).
@@ -354,7 +354,7 @@
 
 	/**
 	 * List of extra dimensions this node has with optional annotations
-	 * (element type: {@link ExtraDimension}).
+	 * (element type: {@link Dimension}).
 	 * Null before JLS8. Added in JLS8; defaults to an empty list
 	 * (see constructor).
 	 * 
@@ -1107,7 +1107,7 @@
 	 * a JLS8 or later AST 
 	 * @since 2.1
 	 * @deprecated In the JLS8 API, this method is replaced by
-	 * {@link #extraDimensions()} which contains a list of {@link ExtraDimension} nodes.
+	 * {@link #extraDimensions()} which contains a list of {@link Dimension} nodes.
 	 */
 	public void setExtraDimensions(int dimensions) {
 		// more efficient than just calling supportedOnlyIn2_3_4() to check
@@ -1125,7 +1125,7 @@
 	/**
 	 * Returns the live ordered list of extra dimensions with optional annotations (added in JLS8 API).
 	 * 
-	 * @return the live list of extra dimensions with optional annotations (element type: {@link ExtraDimension})
+	 * @return the live list of extra dimensions with optional annotations (element type: {@link Dimension})
 	 * @exception UnsupportedOperationException if this operation is used below JLS8
 	 * @since 3.9 BETA_JAVA8
 	 */
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java
index d5b0439..c06a680 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java
@@ -26,7 +26,7 @@
  * and regular variable declaration statements.
  * <pre>
  * SingleVariableDeclaration:
- *    { ExtendedModifier } Type {Annotation} [ <b>...</b> ] Identifier { ExtraDimension } [ <b>=</b> Expression ]
+ *    { ExtendedModifier } Type {Annotation} [ <b>...</b> ] Identifier { Dimension } [ <b>=</b> Expression ]
  * </pre>
  * <p>
  * Note: There's currently no construct in the Java language that allows an initializer on a SingleVariableDeclaration.
@@ -92,7 +92,7 @@
 			internalExtraDimensionsPropertyFactory(SingleVariableDeclaration.class);
 
 	/**
-	 * The "extraDimensions2" structural property of this node type (element type: {@link ExtraDimension}) (added in JLS8 API).
+	 * The "extraDimensions2" structural property of this node type (element type: {@link Dimension}) (added in JLS8 API).
 	 * @since 3.9 BETA_JAVA8
 	 */
 	public static final ChildListPropertyDescriptor EXTRA_DIMENSIONS2_PROPERTY =
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java
index 336deda..50854d2 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java
@@ -30,11 +30,11 @@
  * Type:
  *    AnnotatableType:
  *       PrimitiveType
- *       ArrayType
  *       SimpleType
  *       QualifiedType
  *       PackageQualifiedType
  *       WildcardType
+ *    ArrayType
  *    ParameterizedType
  *    UnionType
  *    IntersectionType
@@ -50,7 +50,7 @@
  *    { Annotation } <b>boolean</b>
  *    { Annotation } <b>void</b>
  * {@link ArrayType}:
- *    Type { Annotation } <b>'['</b> <b>']'</b>
+ *    Type Dimension <b>{</b> Dimension <b>}</b>
  * {@link SimpleType}:
  *    { Annotation } TypeName
  * {@link QualifiedType}:
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java
index c13bd9b..e06343f 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java
@@ -47,7 +47,7 @@
 
 	/**
 	 * List of extra dimensions this node has with optional annotations
-	 * (element type: {@link ExtraDimension}).
+	 * (element type: {@link Dimension}).
 	 * Null before JLS8. Added in JLS8; defaults to an empty list
 	 * (see constructor).
 	 * 
@@ -84,12 +84,12 @@
 	
 	/**
 	 * Creates and returns a structural property descriptor for the
-	 * "extraDimensions2" property declared on the given concrete node type (element type: {@link ExtraDimension}).
+	 * "extraDimensions2" property declared on the given concrete node type (element type: {@link Dimension}).
 	 *
 	 * @return the property descriptor
 	 */
 	static final ChildListPropertyDescriptor internalExtraDimensions2PropertyFactory(Class nodeClass) {
-		return 	new ChildListPropertyDescriptor(nodeClass, "extraDimensions2", ExtraDimension.class, CYCLE_RISK); //$NON-NLS-1$
+		return 	new ChildListPropertyDescriptor(nodeClass, "extraDimensions2", Dimension.class, CYCLE_RISK); //$NON-NLS-1$
 	}
 	
 	/**
@@ -147,7 +147,7 @@
 
 	/**
 	 * Returns the structural property descriptor for the "extraDimensions" property
-	 * of this node (element type: {@link ExtraDimension}) (added in JLS8 API).
+	 * of this node (element type: {@link Dimension}) (added in JLS8 API).
 	 *
 	 * @return the property descriptor
 	 * @since 3.9 BETA_JAVA8
@@ -156,7 +156,7 @@
 	
 	/**
 	 * Returns the structural property descriptor for the "extraDimensions" property
-	 * of this node (element type: {@link ExtraDimension}) (added in JLS8 API).
+	 * of this node (element type: {@link Dimension}) (added in JLS8 API).
 	 *
 	 * @return the property descriptor
 	 * @since 3.9 BETA_JAVA8
@@ -288,7 +288,7 @@
 	 * @exception UnsupportedOperationException if this operation is used in
 	 * a JLS8 or later AST 
 	 * @deprecated In the JLS8 API, this method is replaced by
-	 * {@link #extraDimensions()} which contains a list of {@link ExtraDimension} nodes.
+	 * {@link #extraDimensions()} which contains a list of {@link Dimension} nodes.
 	 * @since 2.1
 	 */
 	public void setExtraDimensions(int dimensions) {
@@ -317,7 +317,7 @@
 	/**
 	 * Returns the live ordered list of extra dimensions with optional annotations (added in JLS8 API).
 	 *
-	 * @return the live list of extra dimensions with optional annotations (element type: {@link ExtraDimension})
+	 * @return the live list of extra dimensions with optional annotations (element type: {@link Dimension})
 	 * @exception UnsupportedOperationException if this operation is used below JLS8
 	 * @since 3.9 BETA_JAVA8
 	 */
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java
index 7d990e9..4929579 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java
@@ -23,7 +23,7 @@
  *
  * <pre>
  * VariableDeclarationFragment:
- *    Identifier { ExtraDimension } [ <b>=</b> Expression ]
+ *    Identifier { Dimension } [ <b>=</b> Expression ]
  * </pre>
  * @since 2.0
  * @noinstantiate This class is not intended to be instantiated by clients.
@@ -47,7 +47,7 @@
 			internalExtraDimensionsPropertyFactory(VariableDeclarationFragment.class);
 
 	/**
-	 * The "extraDimensions2" structural property of this node type (element type: {@link ExtraDimension}) (added in JLS8 API).
+	 * The "extraDimensions2" structural property of this node type (element type: {@link Dimension}) (added in JLS8 API).
 	 * @since 3.9 BETA_JAVA8
 	 */
 	public static final ChildListPropertyDescriptor EXTRA_DIMENSIONS2_PROPERTY =
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
index 58eb318..0d21b3f 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
@@ -379,7 +379,7 @@
 			node.getElementType().accept(this);
 			List dimensions = node.dimensions();
 			for (int i = 0; i < dimensions.size() ; i++) {
-				ExtraDimension aDimension = (ExtraDimension) dimensions.get(i);
+				Dimension aDimension = (Dimension) dimensions.get(i);
 				aDimension.accept(this);
 			}
 		}
@@ -620,6 +620,13 @@
 		return false;
 	}
 
+	public boolean visit(Dimension node) {
+		this.buffer.append(" ");//$NON-NLS-1$
+		visitAnnotationsList(node.annotations());
+		this.buffer.append("[]"); //$NON-NLS-1$
+		return false;
+	}
+
 	/*
 	 * @see ASTVisitor#visit(DoStatement)
 	 */
@@ -753,13 +760,6 @@
 		return false;
 	}
 
-	public boolean visit(ExtraDimension node) {
-		this.buffer.append(" ");//$NON-NLS-1$
-		visitAnnotationsList(node.annotations());
-		this.buffer.append("[]"); //$NON-NLS-1$
-		return false;
-	}
-
 	/*
 	 * @see ASTVisitor#visit(FieldAccess)
 	 */
@@ -1085,7 +1085,7 @@
 		if (node.getAST().apiLevel() >= AST.JLS8) {
 			List dimensions = node.extraDimensions();
 			for (int i = 0; i < size; i++) {
-				visit((ExtraDimension) dimensions.get(i));
+				visit((Dimension) dimensions.get(i));
 			}
 		} else {
 			for (int i = 0; i < size; i++) {
@@ -1441,7 +1441,7 @@
 		if (node.getAST().apiLevel() >= AST.JLS8) {
 			List dimensions = node.extraDimensions();
 			for (int i = 0; i < size; i++) {
-				visit((ExtraDimension) dimensions.get(i));
+				visit((Dimension) dimensions.get(i));
 			}
 		} else {
 			for (int i = 0; i < size; i++) {
@@ -1902,7 +1902,7 @@
 		if (node.getAST().apiLevel() >= AST.JLS8) {
 			List dimensions = node.extraDimensions();
 			for (int i = 0; i < size; i++) {
-				visit((ExtraDimension) dimensions.get(i));
+				visit((Dimension) dimensions.get(i));
 			}
 		} else {
 			for (int i = 0; i < size; i++) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
index 5ac1b06..288ca99 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
@@ -68,6 +68,9 @@
 public final class ASTRewriteAnalyzer extends ASTVisitor {
 
 	/** @deprecated using deprecated code */
+	private static final ChildPropertyDescriptor INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY = ArrayType.COMPONENT_TYPE_PROPERTY;
+
+	/** @deprecated using deprecated code */
 	private static final SimplePropertyDescriptor INTERNAL_FIELD_MODIFIERS_PROPERTY = FieldDeclaration.MODIFIERS_PROPERTY;
 
 	/** @deprecated using deprecated code */
@@ -1938,11 +1941,11 @@
 		return offset;
 	}
 
-	public boolean visit(ExtraDimension node) {
+	public boolean visit(Dimension node) {
 		if (!hasChildrenChanges(node)) {
 			return doVisitUnchangedChildren(node);
 		}
-		rewriteNodeList(node, ExtraDimension.ANNOTATIONS_PROPERTY, node.getStartPosition(), Util.EMPTY_STRING, " "); //$NON-NLS-1$
+		rewriteNodeList(node, Dimension.ANNOTATIONS_PROPERTY, node.getStartPosition(), Util.EMPTY_STRING, " "); //$NON-NLS-1$
 		return false;
 	}
 
@@ -2113,7 +2116,7 @@
 			int offset= elementType.getStartPosition() + elementType.getLength();
 			while(currentLevel != null || astLevelGTE8) {
 				if (i < dimSize) {
-					if (astLevelGTE8) internalExtraDimensionRewrite(replacingType, i, offset);
+					if (astLevelGTE8) internalDimensionRewrite(replacingType, i, offset);
 					 offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLBRACKET, offset);
 					if (hasDimensionChanges) {
 						RewriteEvent event= events[i];
@@ -2148,10 +2151,10 @@
 						offset= retrieveRightBracketEndPosition(offset, 1, true);
 					}
 				} else if (i < nOldBrackets) {
-					if (astLevelGTE8) internalExtraDimensionRewrite(replacingType, i, offset);
+					if (astLevelGTE8) internalDimensionRewrite(replacingType, i, offset);
 					offset= retrieveRightBracketEndPosition(offset, 1, false);
 				} else {
-					internalExtraDimensionAddition(replacingType, i, offset, editGroup, astLevelGTE8);
+					internalDimensionAddition(replacingType, i, offset, editGroup, astLevelGTE8);
 					doTextInsert(offset, "[]", editGroup); //$NON-NLS-1$
 				}
 				i++;
@@ -2180,10 +2183,10 @@
 		return false;
 	}
 
-	private void internalExtraDimensionAddition(ArrayType replacingType, int index, int pos, TextEditGroup editGroup,
+	private void internalDimensionAddition(ArrayType replacingType, int index, int pos, TextEditGroup editGroup,
 			boolean astLevelGTE8) {
 		if (astLevelGTE8) {
-			ExtraDimension dim = (ExtraDimension) replacingType.dimensions().get(index);
+			Dimension dim = (Dimension) replacingType.dimensions().get(index);
 			List annotations = dim.annotations();
 			if (annotations != null) {
 				for (int j = 0; j < annotations.size(); j++) {
@@ -2195,9 +2198,9 @@
 		}
 	}
 
-	private void internalExtraDimensionRewrite(ArrayType replacingType, int index, int pos) {
-		ExtraDimension dim = (ExtraDimension) replacingType.dimensions().get(index);
-		rewriteTypeAnnotations(dim, ExtraDimension.ANNOTATIONS_PROPERTY, pos);
+	private void internalDimensionRewrite(ArrayType replacingType, int index, int pos) {
+		Dimension dim = (Dimension) replacingType.dimensions().get(index);
+		rewriteTypeAnnotations(dim, Dimension.ANNOTATIONS_PROPERTY, pos);
 	}
 
 	/**
@@ -2232,9 +2235,9 @@
 		if (parent.getAST().apiLevel() >= AST.JLS8) {
 			return (Type) getOriginalValue(parent, ArrayType.ELEMENT_TYPE_PROPERTY);
 		}
-		Type t = (Type) getOriginalValue(parent, ArrayType.COMPONENT_TYPE_PROPERTY);
+		Type t = (Type) getOriginalValue(parent, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY);
 		while (t.isArrayType()) {
-			t = (Type) getOriginalValue(t, ArrayType.COMPONENT_TYPE_PROPERTY);
+			t = (Type) getOriginalValue(t, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY);
 		}
 		return t;
 	}
@@ -2243,11 +2246,11 @@
 		if (parent.getAST().apiLevel() >= AST.JLS8) {
 			return ((List) getOriginalValue(parent, ArrayType.DIMENSIONS_PROPERTY)).size();
 		}
-		Type t = (Type) getOriginalValue(parent, ArrayType.COMPONENT_TYPE_PROPERTY);
+		Type t = (Type) getOriginalValue(parent, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY);
 		int dimensions = 1; // always include this array type
 		while (t.isArrayType()) {
 			dimensions++;
-			t = (Type) getOriginalValue(t, ArrayType.COMPONENT_TYPE_PROPERTY);
+			t = (Type) getOriginalValue(t, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY);
 		}
 		return dimensions;
 	}
@@ -2275,7 +2278,7 @@
 			return doVisitUnchangedChildren(node);
 		}
 		if (node.getAST().apiLevel() < AST.JLS8) {
-			rewriteRequiredNode(node, ArrayType.COMPONENT_TYPE_PROPERTY);
+			rewriteRequiredNode(node, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY);
 		} else {
 			int pos = rewriteRequiredNode(node, ArrayType.ELEMENT_TYPE_PROPERTY);
 			rewriteNodeList(node, ArrayType.DIMENSIONS_PROPERTY, pos, Util.EMPTY_STRING, " "); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
index b556362..74abda9 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
@@ -24,6 +24,9 @@
 public class ASTRewriteFlattener extends ASTVisitor {
 
 	/** @deprecated using deprecated code */
+	private static final ChildPropertyDescriptor INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY = ArrayType.COMPONENT_TYPE_PROPERTY;
+
+	/** @deprecated using deprecated code */
 	private static final SimplePropertyDescriptor INTERNAL_FIELD_MODIFIERS_PROPERTY = FieldDeclaration.MODIFIERS_PROPERTY;
 
 	/** @deprecated using deprecated code */
@@ -272,16 +275,16 @@
 		// get the element type and count dimensions
 		Type elementType;
 		int dimensions;
-		boolean astLevelGTE8 = node.getAST().apiLevel() >= AST.JLS8 ? true : false;
+		boolean astLevelGTE8 = node.getAST().apiLevel() >= AST.JLS8;
 		if (astLevelGTE8) {
 			elementType = (Type) getChildNode(arrayType, ArrayType.ELEMENT_TYPE_PROPERTY);
 			dimensions = getChildList(arrayType, ArrayType.DIMENSIONS_PROPERTY).size();
 		} else {
-			elementType = (Type) getChildNode(arrayType, ArrayType.COMPONENT_TYPE_PROPERTY);
+			elementType = (Type) getChildNode(arrayType, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY);
 			dimensions = 1; // always include this array type
 			while (elementType.isArrayType()) {
 				dimensions++;
-				elementType = (Type) getChildNode(elementType, ArrayType.COMPONENT_TYPE_PROPERTY);
+				elementType = (Type) getChildNode(elementType, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY);
 			}
 		}
 
@@ -290,7 +293,7 @@
 		// add "<annotations> [ <dimension> ]" for each dimension expression
 		List list= getChildList(node, ArrayCreation.DIMENSIONS_PROPERTY);
 		for (int i= 0; i < list.size(); i++) {
-			internalVisitExtraDimensionAnnotations(arrayType, i, astLevelGTE8);
+			internalVisitDimensionAnnotations(arrayType, i, astLevelGTE8);
 			this.result.append('[');
 			((ASTNode) list.get(i)).accept(this);
 			this.result.append(']');
@@ -298,7 +301,7 @@
 
 		// add "<annotations> []" for each extra array dimension
 		for (int i= list.size(); i < dimensions; i++) {
-			internalVisitExtraDimensionAnnotations(arrayType, i, astLevelGTE8);
+			internalVisitDimensionAnnotations(arrayType, i, astLevelGTE8);
 			this.result.append("[]"); //$NON-NLS-1$
 		}
 
@@ -309,10 +312,10 @@
 		return false;
 	}
 
-	private void internalVisitExtraDimensionAnnotations(ArrayType arrayType, int index, boolean astLevelGTE8) {
+	private void internalVisitDimensionAnnotations(ArrayType arrayType, int index, boolean astLevelGTE8) {
 		if (astLevelGTE8) {
-			ExtraDimension extraDimension = (ExtraDimension) arrayType.dimensions().get(index);
-			visitList(extraDimension, ExtraDimension.ANNOTATIONS_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' '));
+			Dimension dimension = (Dimension) arrayType.dimensions().get(index);
+			visitList(dimension, Dimension.ANNOTATIONS_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' '));
 		}
 	}
 
@@ -331,7 +334,7 @@
 	 */
 	public boolean visit(ArrayType node) {
 		if (node.getAST().apiLevel() < AST.JLS8) {
-			getChildNode(node, ArrayType.COMPONENT_TYPE_PROPERTY).accept(this);
+			getChildNode(node, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY).accept(this);
 			this.result.append("[]"); //$NON-NLS-1$
 		} else {
 			getChildNode(node, ArrayType.ELEMENT_TYPE_PROPERTY).accept(this);
@@ -524,6 +527,12 @@
 		return false;
 	}
 
+	public boolean visit(Dimension node) {
+		visitList(node, Dimension.ANNOTATIONS_PROPERTY, String.valueOf(' '), String.valueOf(' '), String.valueOf(' '));
+		this.result.append("[]"); //$NON-NLS-1$
+		return false;
+	}
+
 	/*
 	 * @see ASTVisitor#visit(DoStatement)
 	 */
@@ -553,12 +562,6 @@
 		return false;
 	}
 
-	public boolean visit(ExtraDimension node) {
-		visitList(node, ExtraDimension.ANNOTATIONS_PROPERTY, String.valueOf(' '), String.valueOf(' '), String.valueOf(' '));
-		this.result.append("[]"); //$NON-NLS-1$
-		return false;
-	}
-
 	/*
 	 * @see ASTVisitor#visit(FieldAccess)
 	 */
diff --git a/releng/build-scripts/build/test.properties.in b/releng/build-scripts/build/test.properties.in
index 6c3b301..6961d93 100644
--- a/releng/build-scripts/build/test.properties.in
+++ b/releng/build-scripts/build/test.properties.in
@@ -9,8 +9,8 @@
 # ----
 
 # tests referenced without version qualifier:
-org.eclipse.jdt.core.tests.compiler=org.eclipse.jdt.core.tests.compiler_3.9.2

-org.eclipse.jdt.core.tests.model=org.eclipse.jdt.core.tests.model_3.9.2

+org.eclipse.jdt.core.tests.compiler=org.eclipse.jdt.core.tests.compiler_3.9.0

+org.eclipse.jdt.core.tests.model=org.eclipse.jdt.core.tests.model_3.9.0

 
 org.eclipse.objectteams.otdt.tests=org.eclipse.objectteams.otdt.tests_2.0.0
 org.eclipse.objectteams.otdt.ui.tests=org.eclipse.objectteams.otdt.ui.tests_2.0.0