Bug 437767 - [java8][null] semantically integrate null type annotations
with anchored role types
- parser cleanup
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 78fc78f..b62c2d4 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
@@ -3123,9 +3123,13 @@
 	optimizedConcatNodeLists();
 }
 protected void consumeCatchFormalParameter() {
+//{ObjectTeams: support LiftingTypeReference:
+// orig:
+// CatchFormalParameter ::= Modifiersopt CatchType VariableDeclaratorId
+// :giro
 	// CatchFormalParameter ::= Modifiersopt CatchType CatchLiftingTypeopt VariableDeclaratorId
 	// CatchLiftingType ::= 'as' Type
-
+// SH}
 	this.identifierLengthPtr--;
 	char[] identifierName = this.identifierStack[this.identifierPtr];
 	long namePositions = this.identifierPositionStack[this.identifierPtr--];
@@ -6671,20 +6675,6 @@
 }
 protected void consumeOneMoreTypeAnnotation() {
 	// TypeAnnotations ::= TypeAnnotations TypeAnnotation
-//{ObjectTeams: inside a sentinel-delimited list?
-	if (this.typeAnnotationLengthPtr > 1) {
-		int l = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr-2];
-		if (this.typeAnnotationPtr - l - 1 > -1) {
-			if (this.typeAnnotationStack[this.typeAnnotationPtr - l - 1] == annotationSentinel) {
-				// so we have a sentinal delimited list of annotations at lenghts[-2]
-				// merge into that list rather than in into the list at [-1]
-				this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr-2]++;
-				this.typeAnnotationLengthStack[--this.typeAnnotationLengthPtr] = 0;
-				return;
-			}
-		}
-	}
-// SH}
 	this.typeAnnotationLengthStack[--this.typeAnnotationLengthPtr]++;
 }
 protected void consumeNameArrayType() {
@@ -7602,20 +7592,11 @@
 	// PushZeroTypeAnnotations ::= $empty
 	// Name ::= SimpleName
 	// TypeAnnotationsopt ::= $empty
-	int sentinelPos = -1;
-	if (this.typeAnnotationLengthPtr != -1) {
-		int len = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr];
-		sentinelPos = this.typeAnnotationPtr - len;
-		if (sentinelPos > -1 && this.typeAnnotationStack[sentinelPos] == annotationSentinel) {
-			// new ZeroTypeAnnotations in a sentinal situation means: the sentinel has served its purpose, we move on.
-			// Ergo:
-			// - remove the sentinel, transforming the special list into a regular one (lenght is already correct).
-			// - this leaves the rest of the sentinel list as the pending type annotations (instead of zero)
-			System.arraycopy(this.typeAnnotationStack, sentinelPos+1, this.typeAnnotationStack, sentinelPos, len);
-			this.typeAnnotationPtr--;
-			return;
-		}
+//{ObjectTeams: check presence of annotation sentinel (no longer needed, ambiguous tokens will be interpreted as type annotation):
+	if (confirmTypeAnnotation()) {
+		return;
 	}
+// SH}
 	pushOnTypeAnnotationLengthStack(0); // signal absence of @308 annotations.
 }
 // This method is part of an automatic generation : do NOT edit-modify
@@ -7702,7 +7683,7 @@
 			break;
  
     case 85 : if (DEBUG) { System.out.println("TypeAnnotationsopt -> TypeAnnotations"); }  //$NON-NLS-1$
-		    consumeTypeAnnotationSeen();  
+		    confirmTypeAnnotation();  
 			break;
  
      case 88 : if (DEBUG) { System.out.println("TypeAnnotations0 ::= TypeAnnotations0 TypeAnnotation"); }  //$NON-NLS-1$
@@ -9408,6 +9389,10 @@
 		    consumeTypeArgument();  
 			break;
  
+    case 760 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument -> AnyTypeAnchor"); }  //$NON-NLS-1$
+		    confirmTypeAnchor();  
+			break;
+ 
     case 761 : if (DEBUG) { System.out.println("TypeAnchorOrAnnotatedTypeArgument ::=..."); }  //$NON-NLS-1$
 		    consumeTypeArgumentFromAnchor();  
 			break;
@@ -11436,6 +11421,9 @@
 }
 // SH}
 //{ObjectTeams: new syntax for dependent types.
+
+//==== handle situations of TentativeTypeAnchor: could be either a TypeAnchor or a TypeAnnotation ====
+
 protected void consumeTypeAnchor(boolean haveBase) {
 	// TentativeTypeAnchor ::= '@OT' UnannotatableName
 	// TypeAnchor ::= '@OT' 'base'
@@ -11443,6 +11431,8 @@
 
 	// see also skipThisAnchor() and consumeQualifiedBaseTypeAnchor() for related productions
 	
+	// could be either TypeAnchor or TypeAnnotation
+	// create TypeAnchor for now, two avoid awaiting the decision between Annotation w or w/o member values
 	NameReference anchor = haveBase ?
 		  newBaseReference()
 		: getUnspecifiedReference(false);
@@ -11450,14 +11440,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$
+
 protected void convertTypeAnchor(int annotationKind) {
 	// rule number corresponds to argument annotationKind:
 	// (0) NotAnAnchor ::= $empty
@@ -11517,6 +11504,7 @@
 	}
 	// and push it back
 	this.typeAnnotationLengthPtr--; // drop the empty list pushed in consumeTypeAnchor()
+	// mark that the following annotation may have to be integrated into a subsequent type annotation list:
 	pushOnTypeAnnotationStack(annotationSentinel);
 	pushOnTypeAnnotationStack(annotation);
 	// still need to check if the type annotation is legal:
@@ -11526,10 +11514,48 @@
 		problemReporter().invalidUsageOfTypeAnnotations(annotation);
 	}
 }
-protected void consumeTypeArgumentFromAnchor() {
-	// TypeAnchorOrAnnotatedTypeArgument -> TentativeTypeAnchor NotAnAnchor ReferenceType
 
-	// collect everything into a regular type argument:
+// --- The following two methods terminate a sentinal situation, by confirming either a type anchor or a type annotation list: ---
+protected void confirmTypeAnchor() {
+	// TypeAnchorOrAnnotatedTypeArgument -> AnyTypeAnchor
+	// TypeAnchorOrAnnotatedTypeArgument1 -> AnyTypeAnchor '>'
+	// TypeAnchorOrAnnotatedTypeArgument2 -> AnyTypeAnchor '>>'
+	// TypeAnchorOrAnnotatedTypeArgument3 -> AnyTypeAnchor '>>>'
+	
+	// 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--;
+}
+protected boolean confirmTypeAnnotation() {
+	// TypeAnnotationsopt ::= $empty
+	// /.$putCase consumeZeroTypeAnnotations(); $break ./
+	//   - internally calls confirmTypeAnnotation()
+	// TypeAnnotationsopt -> TypeAnnotations
+	
+	int sentinelPos = -1;
+	if (this.typeAnnotationLengthPtr != -1) {
+		int len = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr];
+		sentinelPos = this.typeAnnotationPtr - len;
+		if (sentinelPos > -1 && this.typeAnnotationStack[sentinelPos] == annotationSentinel) {
+			// new (possibly zero) Type Annotation in a sentinal situation means: the sentinel has served its purpose, we move on.
+			// Ergo:
+			// - remove the sentinel, transforming the special list into a regular one (lenght is already correct).
+			// - this leaves the rest of the sentinel list as the pending type annotations (instead of zero)
+			System.arraycopy(this.typeAnnotationStack, sentinelPos+1, this.typeAnnotationStack, sentinelPos, len);
+			this.typeAnnotationPtr--;
+			return true; // yes, we were in a sentinel situation
+		}
+	}
+	return false; // no, nothing ambiuous to confirm
+}
+//--- finally collect the pieces involving the TentativeTypeAnchor that was not an anchor:
+protected void consumeTypeArgumentFromAnchor() {
+	// TypeAnchorOrAnnotatedTypeArgument ::= TentativeTypeAnchor NotAnAnchor ReferenceType
+
+	// original rule:
+	// TypeArgument ::= ReferenceType
+	// /.$putCase consumeTypeArgument(); $break ./
+
 	consumeTypeArgument();
 	if (this.typeAnnotationPtr > -1 && this.typeAnnotationStack[this.typeAnnotationPtr] == annotationSentinel)
 		this.typeAnnotationPtr--; // drop the annotationSentinel if still present
@@ -11551,24 +11577,9 @@
 	if (this.typeAnnotationPtr > -1 && this.typeAnnotationStack[this.typeAnnotationPtr] == annotationSentinel)
 		this.typeAnnotationPtr--; // drop the annotationSentinel if still present
 }
-protected void consumeTypeAnnotationSeen() {
-	int sentinelPos = -1;
-	if (this.typeAnnotationLengthPtr != -1) {
-		int len = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr];
-		sentinelPos = this.typeAnnotationPtr - len;
-		if (sentinelPos > -1 && this.typeAnnotationStack[sentinelPos] == annotationSentinel) {
-			// new ZeroTypeAnnotations in a sentinal situation means: the sentinel has served its purpose, we move on.
-			// Ergo:
-			// - remove the sentinel, transforming the special list into a regular one (lenght is already correct).
-			// - this leaves the rest of the sentinel list as the pending type annotations (instead of zero)
-			System.arraycopy(this.typeAnnotationStack, sentinelPos+1, this.typeAnnotationStack, sentinelPos, len);
-			this.typeAnnotationPtr--;
-		}
-	}
-}
-protected NameReference newBaseReference() {
-	return new SingleNameReference(IOTConstants._OT_BASE, (((long)this.intStack[this.intPtr--])<<32)+this.intStack[this.intPtr--]);
-}
+
+// ==============================================
+
 protected void skipThisAnchor() {
 	// TypeAnchor ::= '@OT' 'this'
 	//   where '@OT' is the synthetic token returned by the parser when a '@' is in a position suitable for a type anchor
@@ -11626,6 +11637,10 @@
 	TypeParameter parameter = (TypeParameter) this.genericsStack[this.genericsPtr];
 	parameter.bounds = new TypeReference[] { bound };
 }
+// ----
+protected NameReference newBaseReference() {
+	return new SingleNameReference(IOTConstants._OT_BASE, (((long)this.intStack[this.intPtr--])<<32)+this.intStack[this.intPtr--]);
+}
 // SH}
 protected void consumeTypeArgument() {
 	pushOnGenericsStack(getTypeReference(this.intStack[this.intPtr--]));
diff --git a/org.eclipse.jdt.core/grammar/java.g b/org.eclipse.jdt.core/grammar/java.g
index 7e60746..8be7063 100644
--- a/org.eclipse.jdt.core/grammar/java.g
+++ b/org.eclipse.jdt.core/grammar/java.g
@@ -404,8 +404,8 @@
 TypeAnnotationsopt ::= $empty
 /.$putCase consumeZeroTypeAnnotations(); $break ./
 TypeAnnotationsopt -> TypeAnnotations
---{ObjectTeams: give a chance to eliminate sentinel
-/.$putCase consumeTypeAnnotationSeen(); $break ./
+--{ObjectTeams: after TentativeTypeAnchor confirm that it was a *type annotation*:
+/.$putCase confirmTypeAnnotation(); $break ./
 -- SH}
 /:$compliance 1.8:/
 /:$readableName TypeAnnotationsopt:/
@@ -2604,8 +2604,9 @@
 -- ==== No Nested Generics ====
 -- case 1: it was indeed a type anchor:
 TypeAnchorOrAnnotatedTypeArgument -> AnyTypeAnchor
+/.$putCase confirmTypeAnchor(); $break ./
 -- case 2a: we were wrong in assuming a type anchor, converted marker type annotation exists, time to clean up
-TypeAnchorOrAnnotatedTypeArgument -> TentativeTypeAnchor NotAnAnchor ReferenceType
+TypeAnchorOrAnnotatedTypeArgument ::= TentativeTypeAnchor NotAnAnchor ReferenceType
 /.$putCase consumeTypeArgumentFromAnchor(); $break ./
 /:$readableName TypeArgument:/
 /:$compliance 1.5:/