1919//w(11)->{r(17), r(19)} & w(19)->{r(17), r(19)} & w(22)
2020class VarStates {
2121 final ImmutableMap <LocalVarDef , VState > states ;
22+ final ImmutableSet <NameDef > destroyedParameters ;
2223 final boolean thisDestroyed ;
2324
2425 public VarStates (ImmutableMap <LocalVarDef , VState > states , boolean thisDestroyed ) {
26+ this (states , ImmutableSet .of (), thisDestroyed );
27+ }
28+
29+ public VarStates (ImmutableMap <LocalVarDef , VState > states , ImmutableSet <NameDef > destroyedParameters , boolean thisDestroyed ) {
2530 this .states = states ;
31+ this .destroyedParameters = destroyedParameters ;
2632 this .thisDestroyed = thisDestroyed ;
2733 }
2834
2935 VarStates merge (VarStates other ) {
3036 ImmutableMap <LocalVarDef , VState > merged = Utils .mergeMaps (states , other .states , VState ::merge );
31- return new VarStates (merged , thisDestroyed || other .thisDestroyed );
37+ return new VarStates (merged , ImmutableSet .< NameDef > builder (). addAll ( destroyedParameters ). addAll ( other . destroyedParameters ). build (), thisDestroyed || other .thisDestroyed );
3238 }
3339
3440 @ Override
@@ -37,12 +43,13 @@ public boolean equals(Object o) {
3743 if (o == null || getClass () != o .getClass ()) return false ;
3844 VarStates varStates = (VarStates ) o ;
3945 return thisDestroyed == varStates .thisDestroyed &&
40- Objects .equals (states , varStates .states );
46+ Objects .equals (states , varStates .states ) &&
47+ Objects .equals (destroyedParameters , varStates .destroyedParameters );
4148 }
4249
4350 @ Override
4451 public int hashCode () {
45- return Objects .hash (states , thisDestroyed );
52+ return Objects .hash (states , destroyedParameters , thisDestroyed );
4653 }
4754
4855 public static VarStates initial (Set <LocalVarDef > r ) {
@@ -55,7 +62,7 @@ public static VarStates initial(Set<LocalVarDef> r) {
5562
5663 public boolean destroyed (NameDef v ) {
5764 VState s = states .get (v );
58- return s != null && s .mightBeDestroyed ;
65+ return ( s != null && s .mightBeDestroyed ) || destroyedParameters . contains ( v ) ;
5966 }
6067
6168 public boolean uninitialized (NameDef v ) {
@@ -78,7 +85,7 @@ public VarStates addRead(LocalVarDef v, Element r) {
7885 ImmutableMap <LocalVarDef , VState > rs = builder
7986 .put (v , s )
8087 .build ();
81- return new VarStates (rs , thisDestroyed );
88+ return new VarStates (rs , destroyedParameters , thisDestroyed );
8289 }
8390
8491 public ImmutableSet <WStatement > getUnreadWrites (NameDef var ) {
@@ -107,7 +114,7 @@ public VarStates addWrite(LocalVarDef var, WStatement s) {
107114 }
108115 vState = vState .addWrite (s );
109116 res .put (var , vState );
110- return new VarStates (res .build (), thisDestroyed );
117+ return new VarStates (res .build (), destroyedParameters , thisDestroyed );
111118 }
112119
113120 public VarStates addDestroy (LocalVarDef var ) {
@@ -118,7 +125,26 @@ public VarStates addDestroy(LocalVarDef var) {
118125 }
119126 }
120127 res .put (var , VState .destroyed );
121- return new VarStates (res .build (), thisDestroyed );
128+ return new VarStates (res .build (), destroyedParameters , thisDestroyed );
129+ }
130+
131+ public VarStates addDestroyParameter (NameDef var ) {
132+ ImmutableSet .Builder <NameDef > destroyed = ImmutableSet .builder ();
133+ destroyed .addAll (destroyedParameters ).add (var );
134+ return new VarStates (states , destroyed .build (), thisDestroyed );
135+ }
136+
137+ public VarStates clearDestroyParameter (NameDef var ) {
138+ if (!destroyedParameters .contains (var )) {
139+ return this ;
140+ }
141+ ImmutableSet .Builder <NameDef > remaining = ImmutableSet .builder ();
142+ for (NameDef destroyed : destroyedParameters ) {
143+ if (destroyed != var ) {
144+ remaining .add (destroyed );
145+ }
146+ }
147+ return new VarStates (states , remaining .build (), thisDestroyed );
122148 }
123149
124150
@@ -144,7 +170,7 @@ public boolean isThisDestroyed() {
144170 }
145171
146172 public VarStates withThisDestroyed (boolean thisDestroyed ) {
147- return new VarStates (states , thisDestroyed );
173+ return new VarStates (states , destroyedParameters , thisDestroyed );
148174 }
149175
150176
@@ -300,6 +326,9 @@ VarStates calculate(WStatement s, VarStates incoming) {
300326 if (isLocalVarDef (destroyedVar )) {
301327 return incoming .addDestroy ((LocalVarDef ) destroyedVar );
302328 }
329+ if (destroyedVar instanceof WParameter || destroyedVar instanceof WShortParameter ) {
330+ return incoming .addDestroyParameter (destroyedVar );
331+ }
303332 } else if (destr .getDestroyedObj () instanceof ExprThis ) {
304333 return incoming .withThisDestroyed (true );
305334 }
@@ -318,6 +347,9 @@ VarStates calculate(WStatement s, VarStates incoming) {
318347 LocalVarDef lv = (LocalVarDef ) n ;
319348 return incoming .addWrite (lv , s );
320349 }
350+ if (n instanceof WParameter || n instanceof WShortParameter ) {
351+ return incoming .clearDestroyParameter (n );
352+ }
321353 }
322354 return incoming ;
323355 }
@@ -509,7 +541,9 @@ void checkFinal(VarStates fin) {
509541 @ Nullable ExprClosure exprClosure = errorPos .attrNearestExprClosure ();
510542 @ Nullable ExprClosure exprClosure1 = var .attrNearestExprClosure ();
511543 if (exprClosure != null && exprClosure != exprClosure1 ) {
512- errorPos .addWarning ("This assignment to the closure-captured variable " + Utils .printElement (var ) + " has no effect outside the closure." );
544+ errorPos .addWarning ("This assignment to the closure-captured variable " + Utils .printElement (var )
545+ + " does not propagate outside the closure because closures capture locals by value. "
546+ + "If you want to update the outer value, use reference(" + var .getName () + ") deliberately." );
513547 } else {
514548 errorPos .addWarning ("The assignment to " + Utils .printElement (var ) + " is never read." );
515549 }
0 commit comments