@@ -52,6 +52,7 @@ public class WildcardBinding extends ReferenceBinding implements HotSwappable{
5252 ReferenceBinding [] superInterfaces ;
5353 TypeVariableBinding typeVariable ; // corresponding variable
5454 LookupEnvironment environment ;
55+ long nullTagBitsFromErasedObjectBound = 0 ; // stores null info from '? extends @NonNull Object'
5556
5657 /**
5758 * When unbound, the bound denotes the corresponding type variable (so as to retrieve its bound lazily)
@@ -161,46 +162,46 @@ public long determineNullBitsFromDeclaration(Scope scope, Wildcard wildcard) {
161162 }
162163 }
163164 }
164- if ( this .bound != null && this .bound .isValidBinding ()) {
165- long boundNullTagBits = this .bound .tagBits & TagBits .AnnotationNullMASK ;
166- if ( boundNullTagBits != 0L ) {
167- if (this . boundKind == Wildcard . SUPER ) {
168- if (( boundNullTagBits & TagBits . AnnotationNullable ) != 0 ) {
169- if (nullTagBits == 0L ) {
170- nullTagBits = TagBits . AnnotationNullable ;
171- } else if ( wildcard != null && ( nullTagBits & TagBits .AnnotationNonNull ) != 0 ) {
172- Annotation annotation = wildcard . bound . findAnnotation ( boundNullTagBits );
173- if ( annotation == null ) { // false alarm, implicit annotation is no conflict, but should be removed:
174- // may not be reachable, how could we have an implicit @Nullable (not via @NonNullByDefault)?
175- TypeBinding newBound = this . bound . withoutToplevelNullAnnotation ();
176- this . bound = newBound ;
177- wildcard .bound . resolvedType = newBound ;
178- } else {
179- scope . problemReporter (). contradictoryNullAnnotationsOnBounds ( annotation , nullTagBits );
180- }
165+ long boundNullTagBits = this .bound != null && this .bound .isValidBinding ()
166+ ? this .bound .tagBits & TagBits .AnnotationNullMASK
167+ : this . nullTagBitsFromErasedObjectBound ;
168+ if (boundNullTagBits != 0L ) {
169+ if (this . boundKind == Wildcard . SUPER ) {
170+ if (( boundNullTagBits & TagBits . AnnotationNullable ) != 0 ) {
171+ if ( nullTagBits == 0L ) {
172+ nullTagBits = TagBits .AnnotationNullable ;
173+ } else if ( wildcard != null && ( nullTagBits & TagBits . AnnotationNonNull ) != 0 ) {
174+ Annotation annotation = wildcard . bound . findAnnotation ( boundNullTagBits );
175+ if ( annotation == null ) { // false alarm, implicit annotation is no conflict, but should be removed:
176+ // may not be reachable, how could we have an implicit @Nullable (not via @NonNullByDefault)?
177+ TypeBinding newBound = this . bound . withoutToplevelNullAnnotation () ;
178+ this .bound = newBound ;
179+ wildcard . bound . resolvedType = newBound ;
180+ } else {
181+ scope . problemReporter (). contradictoryNullAnnotationsOnBounds ( annotation , nullTagBits );
181182 }
182183 }
183- } else {
184- if (( boundNullTagBits & TagBits . AnnotationNonNull ) != 0 ) {
185- if (nullTagBits == 0L ) {
186- nullTagBits = TagBits . AnnotationNonNull ;
187- } else if ( wildcard != null && ( nullTagBits & TagBits .AnnotationNullable ) != 0 ) {
188- Annotation annotation = wildcard . bound . findAnnotation ( boundNullTagBits );
189- if ( annotation == null ) { // false alarm, implicit annotation is no conflict, but should be removed:
190- TypeBinding newBound = this . bound . withoutToplevelNullAnnotation ();
191- this . bound = newBound ;
192- wildcard .bound . resolvedType = newBound ;
193- } else {
194- scope . problemReporter (). contradictoryNullAnnotationsOnBounds ( annotation , nullTagBits );
195- }
184+ }
185+ } else {
186+ if (( boundNullTagBits & TagBits . AnnotationNonNull ) != 0 ) {
187+ if ( nullTagBits == 0L ) {
188+ nullTagBits = TagBits .AnnotationNonNull ;
189+ } else if ( wildcard != null && ( nullTagBits & TagBits . AnnotationNullable ) != 0 ) {
190+ Annotation annotation = wildcard . bound . findAnnotation ( boundNullTagBits );
191+ if ( annotation == null ) { // false alarm, implicit annotation is no conflict, but should be removed:
192+ TypeBinding newBound = this . bound . withoutToplevelNullAnnotation () ;
193+ this .bound = newBound ;
194+ wildcard . bound . resolvedType = newBound ;
195+ } else {
196+ scope . problemReporter (). contradictoryNullAnnotationsOnBounds ( annotation , nullTagBits );
196197 }
197198 }
198- if ( nullTagBits == 0L && this . otherBounds != null ) {
199- for ( TypeBinding otherBound : this .otherBounds ) {
200- if (( otherBound . tagBits & TagBits . AnnotationNonNull ) != 0 ) { // can this happen?
201- nullTagBits = TagBits .AnnotationNonNull ;
202- break ;
203- }
199+ }
200+ if ( nullTagBits == 0L && this .otherBounds != null ) {
201+ for ( TypeBinding otherBound : this . otherBounds ) {
202+ if (( otherBound . tagBits & TagBits .AnnotationNonNull ) != 0 ) { // can this happen?
203+ nullTagBits = TagBits . AnnotationNonNull ;
204+ break ;
204205 }
205206 }
206207 }
@@ -300,7 +301,9 @@ public char[] constantPoolName() {
300301
301302 @ Override
302303 public TypeBinding clone (TypeBinding immaterial ) {
303- return new WildcardBinding (this .genericType , this .rank , this .bound , this .otherBounds , this .boundKind , this .environment );
304+ WildcardBinding clone = new WildcardBinding (this .genericType , this .rank , this .bound , this .otherBounds , this .boundKind , this .environment );
305+ clone .nullTagBitsFromErasedObjectBound = this .nullTagBitsFromErasedObjectBound ;
306+ return clone ;
304307 }
305308
306309 @ Override
@@ -881,4 +884,10 @@ TypeBinding propagateNonConflictingNullAnnotations(TypeBinding type) {
881884 return type ;
882885 return this .environment .createAnnotatedType (type , annots );
883886 }
887+
888+ public boolean hasNullTagBits (long nullTagBits ) {
889+ if (nullTagBits == this .nullTagBitsFromErasedObjectBound )
890+ return true ;
891+ return (this .tagBits & TagBits .AnnotationNullMASK ) == nullTagBits ;
892+ }
884893}
0 commit comments