@@ -1760,7 +1760,7 @@ private void checkUninitializedVars(FunctionLike f) {
17601760 * cheap, local check: it does not attempt interprocedural or path-sensitive reasoning.
17611761 */
17621762 private void checkPotentiallyUninitializedClassFields (FunctionLike function ) {
1763- ClassDef owner = function .attrNearestClassDef ();
1763+ ClassOrModule owner = function .attrNearestClassOrModule ();
17641764 if (owner == null || function instanceof OnDestroyDef ) {
17651765 return ;
17661766 }
@@ -1926,12 +1926,12 @@ private boolean hasGuaranteedConstructorAssignment(GlobalVarDef field) {
19261926 if (cached != null ) {
19271927 return cached ;
19281928 }
1929- ClassDef declaringClass = field . attrNearestClassDef ( );
1930- if (declaringClass == null || declaringClass . getConstructors () .isEmpty ()) {
1929+ List < ConstructorDef > constructors = constructorsFor ( field );
1930+ if (constructors .isEmpty ()) {
19311931 guaranteedClassFieldInitCache .put (field , false );
19321932 return false ;
19331933 }
1934- for (ConstructorDef constructor : declaringClass . getConstructors () ) {
1934+ for (ConstructorDef constructor : constructors ) {
19351935 if (!constructorAssignsField (constructor , field , Collections .newSetFromMap (new IdentityHashMap <>()))) {
19361936 guaranteedClassFieldInitCache .put (field , false );
19371937 return false ;
@@ -1965,14 +1965,38 @@ private boolean constructorAssignsField(ConstructorDef constructor, GlobalVarDef
19651965 if (thisCall == null ) {
19661966 return false ;
19671967 }
1968- ClassOrModule owner = constructor .attrNearestClassOrModule ();
1969- if (owner == null ) {
1970- return false ;
1971- }
1972- ConstructorDef target = OverloadingResolver .resolveThisCall (owner .getConstructors (), thisCall );
1968+ ConstructorDef target = OverloadingResolver .resolveThisCall (constructorsFor (constructor ), thisCall );
19731969 return target != null && target != constructor && constructorAssignsField (target , field , visiting );
19741970 }
19751971
1972+ private List <ConstructorDef > constructorsFor (GlobalVarDef field ) {
1973+ Element current = field ;
1974+ while (current != null ) {
1975+ if (current instanceof ModuleInstanciation module ) {
1976+ return module .getConstructors ();
1977+ }
1978+ if (current instanceof ClassOrModule owner ) {
1979+ return owner .getConstructors ();
1980+ }
1981+ current = current .getParent ();
1982+ }
1983+ return Collections .emptyList ();
1984+ }
1985+
1986+ private List <ConstructorDef > constructorsFor (ConstructorDef constructor ) {
1987+ Element current = constructor ;
1988+ while (current != null ) {
1989+ if (current instanceof ModuleInstanciation module ) {
1990+ return module .getConstructors ();
1991+ }
1992+ if (current instanceof ClassOrModule owner ) {
1993+ return owner .getConstructors ();
1994+ }
1995+ current = current .getParent ();
1996+ }
1997+ return Collections .emptyList ();
1998+ }
1999+
19762000 private void checkClassFieldInitializerReads (GlobalVarDef field ) {
19772001 if (!field .attrIsDynamicClassMember () || !(field .getInitialExpr () instanceof Expr initializer )) {
19782002 return ;
@@ -1993,6 +2017,11 @@ private void checkField(NameRef access) {
19932017 + " Initialize it explicitly before using it." );
19942018 }
19952019
2020+ @ Override
2021+ public void visit (ExprClosure closure ) {
2022+ // A closure runs later (and may never run), so its body is not field initialization.
2023+ }
2024+
19962025 @ Override
19972026 public void visit (ExprVarAccess access ) {
19982027 super .visit (access );
0 commit comments