@@ -119,7 +119,10 @@ let lifetimeDependenceScopeFixupPass = FunctionPass(
119119 // Recursively sink enclosing end_access, end_borrow, end_apply, and destroy_value. If the scope can be extended
120120 // into the caller, return the function arguments that are the dependency sources.
121121 var scopeExtension = ScopeExtension ( localReachabilityCache, context)
122- let args = scopeExtension. extendScopes ( dependence: newLifetimeDep)
122+ guard scopeExtension. extendScopes ( dependence: newLifetimeDep) else {
123+ continue
124+ }
125+ let args = scopeExtension. findArgumentDependencies ( )
123126
124127 // Redirect the dependence base to the function arguments. This may create additional mark_dependence instructions.
125128 markDep. redirectFunctionReturn ( to: args, context)
@@ -246,28 +249,25 @@ private struct ScopeExtension {
246249// `mark_dependence` to the outer access `%0`. This ensures that exclusivity diagnostics correctly reports the
247250// violation, and that subsequent optimizations do not shrink the inner access `%a1`.
248251extension ScopeExtension {
249- mutating func extendScopes( dependence: LifetimeDependence ) -> SingleInlineArray < FunctionArgument > {
252+ mutating func extendScopes( dependence: LifetimeDependence ) -> Bool {
250253 log ( " Scope fixup for lifetime dependent instructions: \( dependence) " )
251254
252255 gatherExtensions ( dependence: dependence)
253256
254- let noCallerScope = SingleInlineArray < FunctionArgument > ( )
255-
256257 // computeDependentUseRange initializes scopeExtension.dependsOnCaller.
257258 guard var useRange = computeDependentUseRange ( of: dependence) else {
258- return noCallerScope
259+ return false
259260 }
260261 // tryExtendScopes deinitializes 'useRange'
261262 var scopesToExtend = SingleInlineArray < ExtendableScope > ( )
262263 guard canExtendScopes ( over: & useRange, scopesToExtend: & scopesToExtend) else {
263264 useRange. deinitialize ( )
264- return noCallerScope
265+ return false
265266 }
266267 // extend(over:) must receive the original unmodified `useRange`, without intermediate scope ending instructions.
267268 // This deinitializes `useRange` before erasing instructions.
268269 extend ( scopesToExtend: scopesToExtend, over: & useRange, context)
269-
270- return dependsOnArgs
270+ return true
271271 }
272272}
273273
@@ -448,10 +448,15 @@ extension ScopeExtension {
448448}
449449
450450extension ScopeExtension {
451- /// Return all scope owners as long as they are all function arguments and all nested accesses are compatible with
452- /// their argument convention. Then, if all nested accesses were extended to the return statement, it is valid to
453- /// logically combine them into a single access for the purpose of diagnostic lifetime dependence.
454- var dependsOnArgs : SingleInlineArray < FunctionArgument > {
451+ /// Check if the dependent value depends only on function arguments and can therefore be returned to caller. If so,
452+ /// return the list of arguments that it depends on. If this returns an empty list, then the dependent value cannot be
453+ /// returned.
454+ ///
455+ /// The conditions for returning a dependent value are:
456+ /// - The dependent value is returned from this function.
457+ /// - All nested scopes are access scopes that are redundant with the caller's exclusive access scope.
458+ /// - All scope owners are function arguments.
459+ func findArgumentDependencies( ) -> SingleInlineArray < FunctionArgument > {
455460 let noCallerScope = SingleInlineArray < FunctionArgument > ( )
456461 // Check that the dependent value is returned by this function.
457462 if !dependsOnCaller! {
0 commit comments