@@ -240,9 +240,9 @@ public struct EscapeEffects : CustomStringConvertible, NoReflectionChildren {
240
240
/// [%0: escape s1 => %r] // field 2 of argument 0 exclusively escapes via return.
241
241
/// [%0: escape s1 -> %r] // field 2 of argument 0 - and other values - escape via return
242
242
///
243
- /// The "exclusive" flag (= second payload) is true if only the argument escapes,
244
- /// but nothing else escapes to the return value.
245
- /// For example, "exclusive" is true for the following function:
243
+ /// The `isExclusive` flag is true if only the argument escapes, but nothing else escapes to
244
+ /// the return value.
245
+ /// For example, `isExclusive` is true for the following function:
246
246
///
247
247
/// @_effect(escaping c => return)
248
248
/// func exclusiveEscape(_ c: Class) -> Class { return c }
@@ -254,17 +254,38 @@ public struct EscapeEffects : CustomStringConvertible, NoReflectionChildren {
254
254
/// @_effect(escaping c -> return)
255
255
/// func notExclusiveEscape(_ c: Class) -> Class { return cond ? c : global }
256
256
///
257
- case escapingToReturn( SmallProjectionPath , Bool ) // toPath, exclusive
257
+ /// Also, if `isExclusive` is true, there must not be a store in the chain from the argument to
258
+ /// the return, e.g.
259
+ ///
260
+ /// @_effect(escaping x -> return)
261
+ /// func notExclusiveEscape(_ s: String) -> Class {
262
+ /// c = new Class()
263
+ /// c.s = s // Store, which prevents the effect to be `isExclusive`
264
+ /// return s
265
+ /// }
266
+ case escapingToReturn( toPath: SmallProjectionPath , isExclusive: Bool )
258
267
259
268
/// Like `escapingToReturn`, but the argument escapes to another argument.
260
269
///
261
270
/// Example: The argument effects of
271
+ ///
262
272
/// func argToArgEscape(_ r: inout Class, _ c: Class) { r = c }
263
273
///
264
274
/// would be
265
275
/// [%1: escape => %0] // Argument 1 escapes to argument 0
266
276
///
267
- case escapingToArgument( Int , SmallProjectionPath , Bool ) // toArgumentIndex, toPath, exclusive
277
+ /// It's not allowed that the argument (or a derived value) is _stored_ to an object which is loaded from somewhere.
278
+ /// In the following example `c` is loaded from the indirect inout argument and `s` is stored to a field of `c`:
279
+ ///
280
+ /// func noEscapeEffect(_ c: inout Class, s: String) {
281
+ /// c.s = s
282
+ /// }
283
+ ///
284
+ /// In this case there is no escaping effect from `s` to `c`.
285
+ /// Note that theoretically this rule also applies to the `escapingToReturn` effect, but it's impossible
286
+ /// to construct such a situation for an argument which is only escaping to the function return.
287
+ ///
288
+ case escapingToArgument( toArgumentIndex: Int , toPath: SmallProjectionPath , isExclusive: Bool )
268
289
}
269
290
270
291
/// To which argument does this effect apply to?
@@ -309,19 +330,19 @@ public struct EscapeEffects : CustomStringConvertible, NoReflectionChildren {
309
330
if resultArgDelta != 1 {
310
331
return nil
311
332
}
312
- self . kind = . escapingToArgument( 0 , toPath, exclusive)
333
+ self . kind = . escapingToArgument( toArgumentIndex : 0 , toPath: toPath , isExclusive : exclusive)
313
334
} else {
314
- self . kind = . escapingToReturn( toPath, exclusive)
335
+ self . kind = . escapingToReturn( toPath: toPath , isExclusive : exclusive)
315
336
}
316
337
case . escapingToArgument( let toArgIdx, let toPath, let exclusive) :
317
338
let resultingToArgIdx = toArgIdx + resultArgDelta
318
339
if resultingToArgIdx < 0 {
319
340
if resultingToArgIdx != - 1 {
320
341
return nil
321
342
}
322
- self . kind = . escapingToReturn( toPath, exclusive)
343
+ self . kind = . escapingToReturn( toPath: toPath , isExclusive : exclusive)
323
344
} else {
324
- self . kind = . escapingToArgument( resultingToArgIdx, toPath, exclusive)
345
+ self . kind = . escapingToArgument( toArgumentIndex : resultingToArgIdx, toPath: toPath , isExclusive : exclusive)
325
346
}
326
347
}
327
348
}
@@ -642,16 +663,16 @@ extension StringParser {
642
663
try throwError ( " multi-value returns not supported yet " )
643
664
}
644
665
let toPath = try parsePathPatternFromSource ( for: function, type: function. argumentTypes [ 0 ] )
645
- return EscapeEffects . ArgumentEffect ( . escapingToArgument( 0 , toPath, exclusive) ,
666
+ return EscapeEffects . ArgumentEffect ( . escapingToArgument( toArgumentIndex : 0 , toPath: toPath , isExclusive : exclusive) ,
646
667
argumentIndex: fromArgIdx, pathPattern: fromPath, isDerived: false )
647
668
}
648
669
let toPath = try parsePathPatternFromSource ( for: function, type: function. resultType)
649
- return EscapeEffects . ArgumentEffect ( . escapingToReturn( toPath, exclusive) ,
670
+ return EscapeEffects . ArgumentEffect ( . escapingToReturn( toPath: toPath , isExclusive : exclusive) ,
650
671
argumentIndex: fromArgIdx, pathPattern: fromPath, isDerived: false )
651
672
}
652
673
let toArgIdx = try parseArgumentIndexFromSource ( for: function, params: params)
653
674
let toPath = try parsePathPatternFromSource ( for: function, type: function. argumentTypes [ toArgIdx] )
654
- return EscapeEffects . ArgumentEffect ( . escapingToArgument( toArgIdx, toPath, exclusive) ,
675
+ return EscapeEffects . ArgumentEffect ( . escapingToArgument( toArgumentIndex : toArgIdx, toPath: toPath , isExclusive : exclusive) ,
655
676
argumentIndex: fromArgIdx, pathPattern: fromPath, isDerived: false )
656
677
}
657
678
try throwError ( " unknown effect " )
@@ -715,12 +736,12 @@ extension StringParser {
715
736
let effect : EscapeEffects . ArgumentEffect
716
737
if consume ( " %r " ) {
717
738
let toPath = consume ( " . " ) ? try parseProjectionPathFromSIL ( ) : SmallProjectionPath ( )
718
- effect = EscapeEffects . ArgumentEffect ( . escapingToReturn( toPath, exclusive) ,
739
+ effect = EscapeEffects . ArgumentEffect ( . escapingToReturn( toPath: toPath , isExclusive : exclusive) ,
719
740
argumentIndex: argumentIndex, pathPattern: fromPath, isDerived: isDerived)
720
741
} else {
721
742
let toArgIdx = try parseArgumentIndexFromSIL ( )
722
743
let toPath = consume ( " . " ) ? try parseProjectionPathFromSIL ( ) : SmallProjectionPath ( )
723
- effect = EscapeEffects . ArgumentEffect ( . escapingToArgument( toArgIdx, toPath, exclusive) ,
744
+ effect = EscapeEffects . ArgumentEffect ( . escapingToArgument( toArgumentIndex : toArgIdx, toPath: toPath , isExclusive : exclusive) ,
724
745
argumentIndex: argumentIndex, pathPattern: fromPath, isDerived: isDerived)
725
746
}
726
747
effects. escapeEffects. arguments. append ( effect)
0 commit comments