Bug 437767 - [java8][null] semantically integrate null type annotations
with anchored role types
- improve parsing of mixed type annotation / type anchor patterns
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
index 177da4b..1e7b2af 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
@@ -7602,6 +7602,12 @@
 	// PushZeroTypeAnnotations ::= $empty
 	// Name ::= SimpleName
 	// TypeAnnotationsopt ::= $empty
+	int sentinelPos = -1;
+	if (this.typeAnnotationLengthPtr != -1) {
+		sentinelPos = this.typeAnnotationPtr - this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr];
+		if (sentinelPos > -1 && this.typeAnnotationStack[sentinelPos] == annotationSentinel)
+			return; // convertTypeAnchor already allocated a sentinel-delimited annotation list, don't add another one
+	}
 	pushOnTypeAnnotationLengthStack(0); // signal absence of @308 annotations.
 }
 // This method is part of an automatic generation : do NOT edit-modify
@@ -9398,6 +9404,10 @@
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
  
+    case 763 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument1 ::= AnyTypeAnchor..."); }  //$NON-NLS-1$
+		    confirmTypeAnchor();  
+			break;
+ 
     case 764 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument1 ::=..."); }  //$NON-NLS-1$
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
@@ -9406,6 +9416,10 @@
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
  
+    case 766 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument2 ::= AnyTypeAnchor..."); }  //$NON-NLS-1$
+		    confirmTypeAnchor();  
+			break;
+ 
     case 767 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument2 ::=..."); }  //$NON-NLS-1$
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
@@ -9414,6 +9428,10 @@
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
  
+    case 769 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument3 ::= AnyTypeAnchor..."); }  //$NON-NLS-1$
+		    confirmTypeAnchor();  
+			break;
+ 
     case 770 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument3 ::=..."); }  //$NON-NLS-1$
 		    consumeAnnotationsOnTypeArgumentFromAnchor();  
 			break;
@@ -11420,6 +11438,11 @@
 	// anchor has no type annotations, yet it will be consumed in a context where type annotations are possible
 	pushOnTypeAnnotationLengthStack(0);
 }
+protected void confirmTypeAnchor() {
+	// tentative type anchor is indeed a type anchor (not converted to type annotation).
+	// need to remove the empty type annotation list now (see consumeTypeAnchor()).
+	this.typeAnnotationLengthPtr--;
+}
 // this sentinel annotation is pushed below a type annotation that was converted from a type anchor.
 // it signals to a subsequent type annotation that it shall be merged into the existing list
 static final Annotation annotationSentinel = new MarkerAnnotation(new SingleTypeReference("annotationSentinel".toCharArray(), 0), 0); //$NON-NLS-1$
@@ -11518,35 +11541,13 @@
 	// TypeAnchorOrAnnotatedTypeArgument2 -> TentativeTypeAnchor NotAnAnchor ReferenceType2
 	// TypeAnchorOrAnnotatedTypeArgument2 -> TentativeTypeAnchor NotAnAnchor Wildcard2
 
-	// in all these cases a type reference (with dims) already exists
-	// and only type annotations need to be added/merged (if any)
-	
-	TypeReference ref = (TypeReference) this.genericsStack[this.genericsPtr];
-	// insert or merge converted annotation at first level into ref's annotations:
-	int length = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr--];
-	if (length != 0) {
-		if (ref.annotations == null)
-			ref.annotations = new Annotation[ref.getAnnotatableLevels()][];
-		Annotation[] annotations = ref.annotations[0];
-		int oldLen = 0;
-		if (annotations != null) {
-			oldLen = annotations.length;
-			System.arraycopy(annotations, 0, annotations = new Annotation[oldLen+length], length, oldLen);
-		} else {
-			annotations = new Annotation[length];				
-		}
-		System.arraycopy(
-				this.typeAnnotationStack,
-				(this.typeAnnotationPtr -= length) + 1,
-				annotations,
-				0,
-				length);
-		ref.annotations[0] = annotations;
-		ref.sourceStart = annotations[0].sourceStart;
-		ref.bits |= ASTNode.HasTypeAnnotations;
+	// in all these cases a type reference (with dims) already exists on the genericsStack
+	//    (will be collected by consumeTypeArgumentList1())
+	// type annotations should have been attached via the tail of the production (e.g., consumeReferenceType1())
+	// now just clean-up the remaining annotation sentinel
+	if (this.typeAnnotationStack[this.typeAnnotationPtr] == annotationSentinel) {
+		this.typeAnnotationPtr--; // drop the annotationSentinel
 	}
-	// type references are already on genericsStack, will be collected by consumeTypeArgumentList1()
-	this.typeAnnotationPtr--; // drop the annotationSentinel
 }
 protected NameReference newBaseReference() {
 	return new SingleNameReference(IOTConstants._OT_BASE, (((long)this.intStack[this.intPtr--])<<32)+this.intStack[this.intPtr--]);
@@ -11558,6 +11559,8 @@
 	// Cannot use ThisReference as type anchor.
 	// Since R<@this> is redundant, simply drop the argument (see also concatGenericsList()).
 	this.intPtr-=2;
+	// anchor has not type annotations, yet it will be consumed in a context where type annotations are possible
+	pushOnTypeAnnotationLengthStack(0);
 }
 protected void consumeQualifiedBaseTypeAnchor() {
 	// TypeAnchor ::= '@OT' UnannotatableName '.' 'base'
@@ -11566,7 +11569,8 @@
 	// handle type arguments (see consumePrimaryNoNewArrayNameThis):
 	pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
 	pushOnGenericsLengthStack(0); // handle type arguments
-	TypeReference prefix = getTypeReference(0);
+	pushOnTypeAnnotationLengthStack(0); // unannotated by construction, but haven't yet pushed zero type annotatations
+	TypeReference prefix = getTypeReference(0); // consumes the above zero type annotations
 	
 	Reference anchor = new QualifiedBaseReference(prefix, this.intStack[this.intPtr--], this.intStack[this.intPtr--]);
 	pushOnGenericsStack(new TypeAnchorReference(anchor, this.intStack[this.intPtr--]));
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc
index c8f6027..57d2985 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props
index b198740..fd6a148 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props
@@ -370,9 +370,9 @@
 TryStatementWithResources=TryStatementWithResources
 Type=Type
 TypeAnchor=typeAnchor
-TypeAnchorOrAnnotatedTypeArgument1=TypeArgument
-TypeAnchorOrAnnotatedTypeArgument2=TypeArgument
-TypeAnchorOrAnnotatedTypeArgument3=TypeArgument
+TypeAnchorOrAnnotatedTypeArgument1=TypeAnchor
+TypeAnchorOrAnnotatedTypeArgument2=TypeAnchor
+TypeAnchorOrAnnotatedTypeArgument3=TypeAnchor
 TypeAnchorOrAnnotatedTypeArgument=TypeArgument
 TypeAnnotation=TypeAnnotation
 TypeAnnotationName=AnnotationName
diff --git a/org.eclipse.jdt.core/grammar/java.g b/org.eclipse.jdt.core/grammar/java.g
index 6eacdc8..923faa4 100644
--- a/org.eclipse.jdt.core/grammar/java.g
+++ b/org.eclipse.jdt.core/grammar/java.g
@@ -2601,12 +2601,12 @@
 -- ==== No Nested Generics ====
 -- case 1: it was indeed a type anchor:
 TypeAnchorOrAnnotatedTypeArgument -> AnyTypeAnchor
--- case 2a: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+-- case 2a: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument -> TentativeTypeAnchor NotAnAnchor ReferenceType
 /.$putCase consumeTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
--- case 2b: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+-- case 2b: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument -> TentativeTypeAnchor NotAnAnchor Wildcard
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
@@ -2615,12 +2615,15 @@
 -- ==== One Level Nested Generics ====
 -- case 1: it was indeed a type anchor:
 TypeAnchorOrAnnotatedTypeArgument1 -> AnyTypeAnchor '>'
--- case 2a: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+/.$putCase confirmTypeAnchor(); $break ./
+/:$readableName TypeAnchor:/
+/:$compliance 1.5:/
+-- case 2a: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument1 -> TentativeTypeAnchor NotAnAnchor ReferenceType1
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
--- case 2b: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+-- case 2b: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument1 -> TentativeTypeAnchor NotAnAnchor Wildcard1
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
@@ -2629,12 +2632,15 @@
 -- ==== Two Levels Nested Generics ====
 -- case 1: it was indeed a type anchor:
 TypeAnchorOrAnnotatedTypeArgument2 -> AnyTypeAnchor '>>'
--- case 2a: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+/.$putCase confirmTypeAnchor(); $break ./
+/:$readableName TypeAnchor:/
+/:$compliance 1.5:/
+-- case 2a: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument2 -> TentativeTypeAnchor NotAnAnchor ReferenceType2
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
--- case 2b: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+-- case 2b: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument2 -> TentativeTypeAnchor NotAnAnchor Wildcard2
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
@@ -2643,19 +2649,22 @@
 -- ==== Three Levels Nested Generics ====
 -- case 1: it was indeed a type anchor:
 TypeAnchorOrAnnotatedTypeArgument3 -> AnyTypeAnchor '>>>'
--- case 2a: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+/.$putCase confirmTypeAnchor(); $break ./
+/:$readableName TypeAnchor:/
+/:$compliance 1.5:/
+-- case 2a: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument3 -> TentativeTypeAnchor NotAnAnchor ReferenceType3
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
--- case 2b: we were wrong in assuming a type anchor, now is the time to convert it into a marker type annotation:
+-- case 2b: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
 TypeAnchorOrAnnotatedTypeArgument3 -> TentativeTypeAnchor NotAnAnchor Wildcard3
 /.$putCase consumeAnnotationsOnTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/
 -- =====================================
 
--- trigger converting a mistaken type anchor into a type argument
+-- trigger converting a mistaken type anchor into a type annotation on a type argument
 NotAnAnchor ::= $empty
 /.$putCase convertTypeAnchor(0); $break ./
 /:$readableName annotatedTypeArgument:/