2222 *******************************************************************************/
2323package org .eclipse .jdt .internal .compiler .lookup ;
2424
25+ import java .util .Arrays ;
2526import org .eclipse .jdt .core .compiler .CharOperation ;
2627import org .eclipse .jdt .internal .compiler .ast .ASTNode ;
2728import org .eclipse .jdt .internal .compiler .ast .Wildcard ;
@@ -203,6 +204,12 @@ public void initializeBounds(Scope scope, ParameterizedTypeBinding capturedParam
203204 }
204205 return ;
205206 }
207+ // JLS 5.1.10
208+ // Let G name a generic type declaration (§8.1.2, §9.1.2) with n type parameters A1,...,An with corresponding bounds U1,...,Un.
209+ // our equivalents:
210+ // G = capturedParameterizedType.type
211+ // Ai = wildcardVariable
212+ // Ui = wildcardVariable.superclass & wildcardVariable.superInterfaces()
206213 ReferenceBinding originalVariableSuperclass = wildcardVariable .superclass ;
207214 ReferenceBinding substitutedVariableSuperclass = (ReferenceBinding ) Scope .substitute (capturedParameterizedType , originalVariableSuperclass );
208215 // prevent cyclic capture: given X<T>, capture(X<? extends T> could yield a circular type
@@ -217,40 +224,62 @@ public void initializeBounds(Scope scope, ParameterizedTypeBinding capturedParam
217224 }
218225 }
219226 // no substitution for wildcard bound (only formal bounds from type variables are to be substituted: 104082)
220- TypeBinding originalWildcardBound = this .wildcard .bound ;
227+ TypeBinding wildcardBound = this .wildcard .bound ;
221228
222229 switch (this .wildcard .boundKind ) {
223230 case Wildcard .EXTENDS :
224- // still need to capture bound supertype as well so as not to expose wildcards to the outside (111208)
225- TypeBinding capturedWildcardBound = originalWildcardBound ; // as spec'd
226- if (originalWildcardBound .isInterface ()) {
227- this .setSuperClass (substitutedVariableSuperclass );
228- // merge wildcard bound into variable superinterfaces using glb
229- if (substitutedVariableInterfaces == Binding .NO_SUPERINTERFACES ) {
230- this .setSuperInterfaces (new ReferenceBinding [] { (ReferenceBinding ) capturedWildcardBound });
231- } else {
232- int length = substitutedVariableInterfaces .length ;
233- System .arraycopy (substitutedVariableInterfaces , 0 , substitutedVariableInterfaces = new ReferenceBinding [length +1 ], 1 , length );
234- substitutedVariableInterfaces [0 ] = (ReferenceBinding ) capturedWildcardBound ;
235- this .setSuperInterfaces (Scope .greaterLowerBound (substitutedVariableInterfaces ));
236- }
237- } else {
238- // the wildcard bound should be a subtype of variable superclass
239- // it may occur that the bound is less specific, then consider glb (202404)
240- if (capturedWildcardBound .isArrayType () || TypeBinding .equalsEquals (capturedWildcardBound , this )) {
241- this .setSuperClass (substitutedVariableSuperclass );
242- } else {
243- this .setSuperClass ((ReferenceBinding ) capturedWildcardBound );
244- if (this .superclass .isSuperclassOf (substitutedVariableSuperclass )) {
245- this .setSuperClass (substitutedVariableSuperclass );
231+ // JLS:
232+ // If Ti is a wildcard type argument of the form ? extends Bi, then
233+ // Si is a fresh type variable
234+ // - whose upper bound is glb(Bi, Ui[A1:=S1,...,An:=Sn])
235+ // - and whose lower bound is the null type.
236+ // our equivalents:
237+ // Ti = this.wildcard
238+ // Si = this
239+ // Bi = wildcardBound
240+ // substitution [A1:=S1,...,An:=Sn] = substitute(capturedParameterizedType, X)
241+ // upper bound = Bi & subst(wildcardVariable.superclass) & subst(wildcardVariable.superInterfaces)
242+ // = wildcardBound & substitutedVariableSuperclass & substitutedVariableInteraces
243+ // minimize this intersection using glb and distribute it into this.superclass & this.superInterfaces:
244+ TypeBinding [] allBounds ;
245+ int ifcLen = substitutedVariableInterfaces .length ;
246+ if (wildcardBound instanceof ReferenceBinding ) {
247+ allBounds = Arrays .copyOf (substitutedVariableInterfaces , ifcLen + 2 );
248+ allBounds [ifcLen +1 ] = wildcardBound ;
249+ } else { // ignoring non-ReferenceBinding wildcardBound (ArrayBinding?), will be set as firstBound only
250+ allBounds = Arrays .copyOf (substitutedVariableInterfaces , ifcLen + 1 );
251+ }
252+ allBounds [ifcLen ] = substitutedVariableSuperclass ;
253+ TypeBinding [] fullGlb = Scope .greaterLowerBound (allBounds , scope , scope .environment ());
254+ if (fullGlb != null ) {
255+ // optimistically split the fullGlb into one superClass plus n interfaces
256+ ReferenceBinding superClass = scope .getJavaLangObject ();
257+ ReferenceBinding [] interfaces = new ReferenceBinding [fullGlb .length ];
258+ int j =0 ;
259+ for (int i =0 ; i < fullGlb .length ; i ++) {
260+ if (fullGlb [i ] instanceof ReferenceBinding ref ) {
261+ if (ref .isInterface ())
262+ interfaces [j ++] = ref ;
263+ else
264+ superClass = ref ;
246265 }
247- // TODO: there are cases were we need to compute glb(capturedWildcardBound, substitutedVariableSuperclass)
248- // but then when glb (perhaps triggered inside setFirstBound()) fails, how to report the error??
249266 }
250- this .setSuperInterfaces (substitutedVariableInterfaces );
267+ setSuperClass (superClass );
268+ if (j != fullGlb .length )
269+ interfaces = Arrays .copyOf (interfaces , j );
270+ setSuperInterfaces (interfaces );
271+ } else {
272+ // if glb is null, this capture type is uninhabitable.
273+ // opportunistically use weaker check to determine the stronger bound,
274+ // just so we give more interesting follow-up errors, if any.
275+ if (wildcardBound .original ().isCompatibleWith (substitutedVariableSuperclass .original ()))
276+ setSuperClass ((ReferenceBinding ) wildcardBound );
277+ else
278+ setSuperClass (substitutedVariableSuperclass );
279+ setSuperInterfaces (substitutedVariableInterfaces );
251280 }
252- this .setFirstBound (capturedWildcardBound );
253- if ((capturedWildcardBound .tagBits & TagBits .HasTypeVariable ) == 0 )
281+ this .setFirstBound (wildcardBound );
282+ if ((wildcardBound .tagBits & TagBits .HasTypeVariable ) == 0 )
254283 this .tagBits &= ~TagBits .HasTypeVariable ;
255284 break ;
256285 case Wildcard .UNBOUND :
@@ -266,19 +295,20 @@ public void initializeBounds(Scope scope, ParameterizedTypeBinding capturedParam
266295 break ;
267296 case Wildcard .SUPER :
268297 this .setSuperClass (substitutedVariableSuperclass );
269- if (TypeBinding .equalsEquals (wildcardVariable .firstBound , substitutedVariableSuperclass ) || TypeBinding .equalsEquals (originalWildcardBound , substitutedVariableSuperclass )) {
298+ if (TypeBinding .equalsEquals (wildcardVariable .firstBound , substitutedVariableSuperclass ) || TypeBinding .equalsEquals (wildcardBound , substitutedVariableSuperclass )) {
270299 this .setFirstBound (substitutedVariableSuperclass );
271300 }
272301 this .setSuperInterfaces (substitutedVariableInterfaces );
273- this .lowerBound = originalWildcardBound ;
274- if ((originalWildcardBound .tagBits & TagBits .HasTypeVariable ) == 0 )
302+ this .lowerBound = wildcardBound ;
303+ if ((wildcardBound .tagBits & TagBits .HasTypeVariable ) == 0 )
275304 this .tagBits &= ~TagBits .HasTypeVariable ;
276305 break ;
277306 }
278307 if (scope .environment ().usesNullTypeAnnotations ()) {
279308 evaluateNullAnnotations (scope , null );
280309 }
281310 }
311+
282312 @ Override
283313 public TypeBinding upwardsProjection (Scope scope , TypeBinding [] mentionedTypeVariables ) {
284314 if (enterRecursiveProjectionFunction ()) {
0 commit comments