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:/