@@ -213,7 +213,11 @@ public void getAllAnnotationContexts(int targetType, int parameterIndex, List<An
213213 public boolean isReceiver () {
214214 return false ;
215215 }
216- public TypeBinding patchType (TypeBinding newType ) {
216+ public TypeBinding patchType (BlockScope scope , TypeBinding newType ) {
217+ if (TypeBinding .equalsEquals (TypeBinding .NULL , newType ))
218+ scope .problemReporter ().varLocalInitializedToNull (this );
219+ else if (TypeBinding .equalsEquals (TypeBinding .VOID , newType ))
220+ scope .problemReporter ().varLocalInitializedToVoid (this );
217221 // Perform upwards projection on type wrt mentioned type variables
218222 TypeBinding [] mentionedTypeVariables = newType != null ? newType .syntheticTypeVariablesMentioned () : null ;
219223 if (mentionedTypeVariables != null && mentionedTypeVariables .length > 0 ) {
@@ -222,63 +226,31 @@ public TypeBinding patchType(TypeBinding newType) {
222226 this .type .resolvedType = newType ;
223227 if (this .binding != null ) {
224228 this .binding .type = newType ;
225- this .binding .markInitialized ();
226229 }
227230 return this .type .resolvedType ;
228231 }
229232
230- private static Expression findPolyExpression (Expression e ) {
231- // This is simpler than using an ASTVisitor, since we only care about a very few select cases.
232- if (e instanceof FunctionalExpression ) {
233- return e ;
234- }
235- if (e instanceof ConditionalExpression ) {
236- ConditionalExpression ce = (ConditionalExpression )e ;
237- Expression candidate = findPolyExpression (ce .valueIfTrue );
238- if (candidate == null ) {
239- candidate = findPolyExpression (ce .valueIfFalse );
240- }
241- if (candidate != null ) return candidate ;
242- }
243- if (e instanceof SwitchExpression se ) {
244- for (Expression re : se .resultExpressions ()) {
245- Expression candidate = findPolyExpression (re );
246- if (candidate != null ) return candidate ;
247- }
248- }
249- return null ;
250- }
251-
252233 @ Override
253234 public void resolve (BlockScope scope ) {
254- resolve (scope , false );
255- }
256- public void resolve (BlockScope scope , boolean isPatternVariable ) { // prescan NNBD
257- handleNonNullByDefault (scope , this .annotations , this );
258235
259- if (!isPatternVariable && (this .bits & ASTNode .IsForeachElementVariable ) == 0 && this .initialization == null && this .isUnnamed (scope )) {
260- scope .problemReporter ().unnamedVariableMustHaveInitializer (this );
261- }
236+ handleNonNullByDefault (scope , this .annotations , this ); // prescan NNBD
237+
238+ final boolean isPatternVariable = (this .bits & ASTNode .IsPatternVariable ) != 0 ;
239+ final boolean isForeachElementVariable = (this .bits & ASTNode .IsForeachElementVariable ) != 0 ;
240+ final boolean varTypedLocal = isTypeNameVar (scope );
241+ final boolean unnamedLocal = isUnnamed (scope );
262242
263243 TypeBinding variableType = null ;
264- boolean variableTypeInferenceError = false ;
265- boolean isTypeNameVar = isTypeNameVar (scope );
266- if (isTypeNameVar && !isPatternVariable ) {
267- if (this .type .isParameterizedTypeReference ()) {
244+
245+ if (varTypedLocal ) {
246+ if (this .type .isParameterizedTypeReference ())
268247 scope .problemReporter ().varCannotBeUsedWithTypeArguments (this .type );
269- }
270- if ((this .bits & ASTNode .IsForeachElementVariable ) == 0 ) {
271- // infer a type from the initializer
272- if (this .initialization != null ) {
273- variableType = checkInferredLocalVariableInitializer (scope );
274- variableTypeInferenceError = variableType != null ;
275- } else {
276- // That's always an error
277- scope .problemReporter ().varLocalWithoutInitizalier (this );
278- variableType = scope .getJavaLangObject ();
279- variableTypeInferenceError = true ;
280- }
281- }
248+ if (this .type .dimensions () > 0 || this .type .extraDimensions () > 0 )
249+ scope .problemReporter ().varLocalCannotBeArray (this );
250+ if ((this .bits & ASTNode .IsAdditionalDeclarator ) != 0 )
251+ scope .problemReporter ().varLocalMultipleDeclarators (this );
252+ if (isPatternVariable )
253+ variableType = this .type .resolvedType ; // set already if this is a component pattern or is problem binding as it should be.
282254 } else {
283255 variableType = this .type == null ? null : this .type .resolveType (scope , true /* check bounds*/ );
284256 }
@@ -297,14 +269,14 @@ public void resolve(BlockScope scope, boolean isPatternVariable) { // prescan N
297269 }
298270 }
299271
300- Binding existingVariable = scope .getBinding (this .name , Binding .VARIABLE , this , false /*do not resolve hidden field*/ );
301- if (existingVariable != null && existingVariable .isValidBinding () && !this . isUnnamed ( scope ) ) {
272+ Binding existingVariable = scope .getBinding (this .name , Binding .VARIABLE , this , false /*do not resolve hidden field*/ );
273+ if (existingVariable != null && existingVariable .isValidBinding () && !unnamedLocal ) {
302274 boolean localExists = existingVariable instanceof LocalVariableBinding ;
303- if (localExists && (this .bits & ASTNode .ShadowsOuterLocal ) != 0 && scope .isLambdaSubscope () && this .hiddenVariableDepth == 0 ) {
275+ if (localExists && (this .bits & ASTNode .ShadowsOuterLocal ) != 0 && scope .isLambdaSubscope () && this .hiddenVariableDepth == 0 ) {
304276 scope .problemReporter ().lambdaRedeclaresLocal (this );
305277 } else if (localExists && this .hiddenVariableDepth == 0 ) {
306278 if (existingVariable .isPatternVariable ()) {
307- scope .problemReporter ().illegalRedeclarationOfPatternVar ((LocalVariableBinding ) existingVariable , this );
279+ scope .problemReporter ().illegalRedeclarationOfPatternVar ((LocalVariableBinding ) existingVariable , this );
308280 } else {
309281 scope .problemReporter ().redefineLocal (this );
310282 }
@@ -313,66 +285,22 @@ public void resolve(BlockScope scope, boolean isPatternVariable) { // prescan N
313285 }
314286 }
315287 }
316- if ((this .modifiers & ClassFileConstants .AccFinal )!= 0 && this .initialization == null ) {
288+ if ((this .modifiers & ClassFileConstants .AccFinal ) != 0 && this .initialization == null ) {
317289 this .modifiers |= ExtraCompilerModifiers .AccBlankFinal ;
318290 }
319- if (isTypeNameVar ) {
320- // Create binding for the initializer's type
321- // In order to resolve self-referential initializers, we must declare the variable with a placeholder type (j.l.Object), and then patch it later
322- this .binding = new LocalVariableBinding (this , variableType != null ? variableType : scope .getJavaLangObject (), this .modifiers , false ) {
323- private boolean isInitialized = false ;
324-
325- @ Override
326- public void markReferenced () {
327- if (! this .isInitialized ) {
328- scope .problemReporter ().varLocalReferencesItself (LocalDeclaration .this );
329- this .type = null ;
330- this .isInitialized = true ; // Quell additional type errors
331- }
332- }
333- @ Override
334- public void markInitialized () {
335- this .isInitialized = true ;
336- }
337- };
338- } else {
339- // create a binding from the specified type
340- this .binding = new LocalVariableBinding (this , variableType , this .modifiers , false /*isArgument*/ );
341- }
291+ // Create a binding from the specified type; In order to diagnose self-referential initializers,
292+ // we must create the binding with jlO as a placeholder type and patch it later
293+ this .binding = new LocalVariableBinding (this , varTypedLocal && variableType == null ? scope .getJavaLangObject () : variableType , this .modifiers , false /*isArgument*/ );
342294 if (isPatternVariable )
343295 this .binding .tagBits |= TagBits .IsPatternBinding ;
344296 scope .addLocalVariable (this .binding );
345297 this .binding .setConstant (Constant .NotAConstant );
346- // allow to recursivelly target the binding....
298+ // allow to recursively target the binding....
347299 // the correct constant is harmed if correctly computed at the end of this method
348300
349- if (variableType == null ) {
350- if (this .initialization != null ) {
351- if (this .initialization instanceof CastExpression ) {
352- ((CastExpression )this .initialization ).setVarTypeDeclaration (true );
353- }
354- this .initialization .resolveType (scope ); // want to report all possible errors
355- if (isTypeNameVar && this .initialization .resolvedType != null ) {
356- if (TypeBinding .equalsEquals (TypeBinding .NULL , this .initialization .resolvedType )) {
357- scope .problemReporter ().varLocalInitializedToNull (this );
358- variableTypeInferenceError = true ;
359- } else if (TypeBinding .equalsEquals (TypeBinding .VOID , this .initialization .resolvedType )) {
360- scope .problemReporter ().varLocalInitializedToVoid (this );
361- variableTypeInferenceError = true ;
362- }
363- variableType = patchType (this .initialization .resolvedType );
364- } else {
365- variableTypeInferenceError = true ;
366- }
367- }
368- }
369- this .binding .markInitialized ();
370- if (variableTypeInferenceError ) {
371- return ;
372- }
373301 boolean resolveAnnotationsEarly = false ;
374302 if (scope .environment ().usesNullTypeAnnotations ()
375- && !isTypeNameVar // 'var' does not provide a target type
303+ && !varTypedLocal // 'var' does not provide a target type
376304 && variableType != null && variableType .isValidBinding ()) {
377305 resolveAnnotationsEarly = this .initialization instanceof Invocation
378306 || this .initialization instanceof ConditionalExpression
@@ -387,16 +315,35 @@ public void markInitialized() {
387315 }
388316 if (this .initialization != null ) {
389317 if (this .initialization instanceof ArrayInitializer ) {
318+ if (varTypedLocal ) {
319+ scope .problemReporter ().varLocalCannotBeArrayInitalizers (this );
320+ variableType = scope .createArrayType (scope .getJavaLangObject (), 1 ); // Treat as array of anything
321+ }
390322 TypeBinding initializationType = this .initialization .resolveTypeExpecting (scope , variableType );
391323 if (initializationType != null ) {
392324 ((ArrayInitializer ) this .initialization ).binding = (ArrayBinding ) initializationType ;
393325 this .initialization .computeConversion (scope , variableType , initializationType );
394326 }
395327 } else {
396- this .initialization .setExpressionContext (isTypeNameVar ? VANILLA_CONTEXT : ASSIGNMENT_CONTEXT );
328+ if (varTypedLocal ) {
329+ this .binding .useFlag = LocalVariableBinding .ILLEGAL_SELF_REFERENCE_IF_USED ; // hijack analysis phase flag
330+ if (this .initialization instanceof CastExpression castExpression )
331+ castExpression .setVarTypeDeclaration (true );
332+ }
333+ this .initialization .setExpressionContext (varTypedLocal ? VANILLA_CONTEXT : ASSIGNMENT_CONTEXT );
397334 this .initialization .setExpectedType (variableType );
398- TypeBinding initializationType = this .initialization .resolvedType != null ? this .initialization .resolvedType : this .initialization .resolveType (scope );
335+ TypeBinding initializationType = this .initialization .resolveType (scope );
336+ if (varTypedLocal )
337+ this .binding .useFlag = LocalVariableBinding .UNUSED ; // hand-over hijacked flag; let flow analysis do what it does with it.
338+
339+ if ((variableType == null && !varTypedLocal ) || // having waited until any additional errors in initializer are surfaced, bail out
340+ (initializationType == null && varTypedLocal )) // fubar, bail out.
341+ return ;
342+
399343 if (initializationType != null ) {
344+ if (varTypedLocal ) {
345+ variableType = patchType (scope , this .initialization .resolvedType );
346+ }
400347 if (TypeBinding .notEquals (variableType , initializationType )) // must call before computeConversion() and typeMismatchError()
401348 scope .compilationUnitScope ().recordTypeConversion (variableType , initializationType );
402349 if (this .initialization .isConstantValueOfTypeAssignableToType (initializationType , variableType )
@@ -434,6 +381,11 @@ public void markInitialized() {
434381 this .binding .isFinal ()
435382 ? this .initialization .constant .castTo ((variableType .id << 4 ) + this .initialization .constant .typeID ())
436383 : Constant .NotAConstant );
384+ } else if (!isPatternVariable && !isForeachElementVariable ) {
385+ if (varTypedLocal )
386+ scope .problemReporter ().varLocalWithoutInitizalier (this );
387+ if (unnamedLocal )
388+ scope .problemReporter ().unnamedVariableMustHaveInitializer (this );
437389 }
438390 // if init could be a constant only resolve annotation at the end, for constant to be positioned before (96991)
439391 if (!resolveAnnotationsEarly )
@@ -447,37 +399,6 @@ void validateNullAnnotations(BlockScope scope) {
447399 this .binding .tagBits &= ~TagBits .AnnotationNullMASK ;
448400 }
449401
450- /*
451- * Checks the initializer for simple errors, and reports an error as needed. If error is found,
452- * returns a reasonable match for further type checking.
453- */
454- private TypeBinding checkInferredLocalVariableInitializer (BlockScope scope ) {
455- TypeBinding errorType = null ;
456- if (this .initialization instanceof ArrayInitializer ) {
457- scope .problemReporter ().varLocalCannotBeArrayInitalizers (this );
458- errorType = scope .createArrayType (scope .getJavaLangObject (), 1 ); // Treat as array of anything
459- } else {
460- // Catch-22: isPolyExpression() is not reliable BEFORE resolveType, so we need to peek to suppress the errors
461- Expression polyExpression = findPolyExpression (this .initialization );
462- if (polyExpression instanceof ReferenceExpression ) {
463- scope .problemReporter ().varLocalCannotBeMethodReference (this );
464- errorType = TypeBinding .NULL ;
465- } else if (polyExpression != null ) { // Should be instanceof LambdaExpression, but this is safer
466- scope .problemReporter ().varLocalCannotBeLambda (this );
467- errorType = TypeBinding .NULL ;
468- }
469- }
470- if (this .type .dimensions () > 0 || this .type .extraDimensions () > 0 ) {
471- scope .problemReporter ().varLocalCannotBeArray (this );
472- errorType = scope .createArrayType (scope .getJavaLangObject (), 1 ); // This is just to quell some warnings
473- }
474- if ((this .bits & ASTNode .IsAdditionalDeclarator ) != 0 ) {
475- scope .problemReporter ().varLocalMultipleDeclarators (this );
476- errorType = this .initialization .resolveType (scope );
477- }
478- return errorType ;
479- }
480-
481402 @ Override
482403 public void traverse (ASTVisitor visitor , BlockScope scope ) {
483404
0 commit comments