@@ -66,6 +66,8 @@ private func log(prefix: Bool = true, _ message: @autoclosure () -> String) {
6666/// Walk up the value dependence chain to find the best-effort
6767/// variable declaration. Typically called while diagnosing an error.
6868///
69+ /// Returns an array with at least one introducer value.
70+ ///
6971/// The walk stops at:
7072/// - an address
7173/// - a variable declaration (begin_borrow [var_decl], move_value [var_decl])
@@ -85,6 +87,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context)
8587 }
8688 defer { useDefVisitor. deinitialize ( ) }
8789 _ = useDefVisitor. walkUp ( valueOrAddress: value)
90+ assert ( !introducers. isEmpty, " missing variable introducer " )
8891 return introducers
8992}
9093
@@ -104,7 +107,6 @@ func gatherVariableIntroducers(for value: Value, _ context: Context)
104107/// A lifetime dependence identifies its parent value, the kind of
105108/// scope that the parent value represents, and a dependent value.
106109struct LifetimeDependence : CustomStringConvertible {
107- // TODO: handle trivial values based on variable binding
108110 enum Scope : CustomStringConvertible {
109111 /// A guaranteed or inout argument whose scope is provided by the caller
110112 /// and covers the entire function and any dependent results or yields.
@@ -113,9 +115,10 @@ struct LifetimeDependence : CustomStringConvertible {
113115 case access( BeginAccessInst )
114116 /// A coroutine.
115117 case yield( Value )
116- /// An owned value whose OSSA lifetime encloses nonescapable values
118+ /// An owned value whose OSSA lifetime encloses nonescapable values, or a trivial variable introduced by move_value.
117119 case owned( Value )
118- /// An borrowed value whose OSSA lifetime encloses nonescapable values
120+ /// An borrowed value whose OSSA lifetime encloses nonescapable values, or a trivial variable introduced by
121+ /// begin_borrow.
119122 case borrowed( BeginBorrowValue )
120123 /// Singly-initialized addressable storage (likely for an
121124 /// immutable address-only value). The lifetime extends until the
@@ -128,8 +131,7 @@ struct LifetimeDependence : CustomStringConvertible {
128131 /// If `initializingStore` is nil, then the `initialAddress` is
129132 /// initialized on function entry.
130133 case initialized( initialAddress: Value , initializingStore: Instruction ? )
131- // TODO: Add SIL verification that no mark_depedence [unresolved] has an unknown LifetimeDependence.
132- // This currently requires stack allocations to be singly initialized.
134+ // Unknown includes: escapable values with local var_decl, stack allocations that are not singly initialized.
133135 case unknown( Value )
134136
135137 var parentValue : Value {
@@ -202,7 +204,7 @@ extension LifetimeDependence {
202204 if arg. isIndirectResult {
203205 return nil
204206 }
205- self . scope = Scope ( base: arg, context) !
207+ self . scope = Scope ( base: arg, context)
206208 self . dependentValue = arg
207209 }
208210
@@ -219,7 +221,7 @@ extension LifetimeDependence {
219221 return nil
220222 }
221223 assert ( value. ownership == . owned, " unsafe apply result must be owned " )
222- self . scope = Scope ( base: value, context) !
224+ self . scope = Scope ( base: value, context)
223225 self . dependentValue = value
224226 }
225227
@@ -238,14 +240,11 @@ extension LifetimeDependence {
238240 /// For any LifetimeDependence constructed from a mark_dependence, its `dependentValue` will be the result of the
239241 /// mark_dependence.
240242 ///
241- /// Returns 'nil' for dependence on a trivial value .
243+ /// Returns 'nil' for unknown dependence .
242244 init ? ( _ markDep: MarkDependenceInst , _ context: some Context ) {
243245 switch markDep. dependenceKind {
244246 case . Unresolved, . NonEscaping:
245- guard let scope = Scope ( base: markDep. base, context) else {
246- return nil
247- }
248- self . scope = scope
247+ self . scope = Scope ( base: markDep. base, context)
249248 self . dependentValue = markDep
250249 case . Escaping:
251250 return nil
@@ -294,65 +293,45 @@ extension LifetimeDependence.Scope {
294293 /// directly defines the parent lifetime. If `base` is guaranteed, then it must have a single borrow introducer, which
295294 /// defines the parent lifetime. `base` must not be derived from a guaranteed phi or forwarded (via struct/tuple) from
296295 /// multiple guaranteed values.
297- ///
298- /// Returns 'nil' for dependence on a trivial value.
299- init ? ( base: Value , _ context: some Context ) {
296+ init ( base: Value , _ context: some Context ) {
300297 if base. type. isAddress {
301- guard let scope = Self ( address: base, context) else {
302- return nil
303- }
304- self = scope
298+ self = Self ( address: base, context)
305299 return
306300 }
307301 switch base. ownership {
308302 case . owned:
309303 self = . owned( base)
310304 return
311305 case . guaranteed:
312- guard let scope = Self ( guaranteed: base, context) else {
313- return nil
314- }
315- self = scope
306+ self = Self ( guaranteed: base, context)
316307 case . none:
317- // lifetime dependence requires a nontrivial value
318- return nil
308+ self = Self ( variable: base, context)
319309 case . unowned:
320310 self = . unknown( base)
321311 }
322312 }
323313
324- /// Returns 'nil' for dependence on a trivial value.
325- private init ? ( address: Value , _ context: some Context ) {
314+ private init ( address: Value , _ context: some Context ) {
326315 switch address. enclosingAccessScope {
327316 case let . scope( access) :
328317 self = . access( access)
329318 case let . base( accessBase) :
330- guard let scope = Self ( accessBase: accessBase, address: address, context) else {
331- return nil
332- }
333- self = scope
319+ self = Self ( accessBase: accessBase, address: address, context)
334320 }
335321 }
336322
337- /// Returns 'nil' for dependence on a trivial value.
338- init ? ( accessBase: AccessBase , address: Value , _ context: some Context ) {
323+ init ( accessBase: AccessBase , address: Value , _ context: some Context ) {
339324 switch accessBase {
340325 case let . box( projectBox) :
341326 // Note: the box may be in a borrow scope.
342- guard let scope = Self ( base: projectBox. operand. value, context) else {
343- return nil
344- }
345- self = scope
327+ self = Self ( base: projectBox. operand. value, context)
346328 case let . stack( allocStack) :
347329 self = Self ( allocation: allocStack, context)
348330 case . global:
349331 self = . unknown( address)
350332 case . class, . tail:
351333 let refElt = address as! UnaryInstruction
352- guard let scope = Self ( guaranteed: refElt. operand. value, context) else {
353- return nil
354- }
355- self = scope
334+ self = Self ( guaranteed: refElt. operand. value, context)
356335 case let . argument( arg) :
357336 if arg. convention. isIndirectIn {
358337 self = . initialized( initialAddress: arg, initializingStore: nil )
@@ -368,24 +347,23 @@ extension LifetimeDependence.Scope {
368347 case let . yield( result) :
369348 self = Self ( yield: result)
370349 case . storeBorrow( let sb) :
371- guard let scope = Self ( base: sb. source, context) else {
372- return nil
373- }
374- self = scope
350+ self = Self ( base: sb. source, context)
375351 case . pointer, . index, . unidentified:
376352 self = . unknown( address)
377353 }
378354 }
379355
380- /// Returns 'nil' for dependence on a trivial value.
381- private init ? ( guaranteed base: Value , _ context: some Context ) {
382- // If introducers is empty, then the dependence is on a trivial value, so
383- // there is no dependence scope.
384- //
356+ private init ( guaranteed base: Value , _ context: some Context ) {
385357 // TODO: Add a SIL verifier check that a mark_dependence [nonescaping]
386358 // base is never a guaranteed phi.
387359 var iter = base. getBorrowIntroducers ( context) . makeIterator ( )
388- guard let beginBorrow = iter. next ( ) else { return nil }
360+ // If no borrow introducer was found, then this is a borrow of a trivial value. Since we can assume a single
361+ // introducer here, then this is the only condition under which we have a trivial introducer.
362+ guard let beginBorrow = iter. next ( ) else {
363+ self = Self ( variable: base, context)
364+ return
365+ }
366+ // TODO: will we need to handle tuple/struct with multiple scopes?
389367 assert ( iter. next ( ) == nil ,
390368 " guaranteed phis not allowed when diagnosing lifetime dependence " )
391369 switch beginBorrow {
@@ -400,6 +378,24 @@ extension LifetimeDependence.Scope {
400378 }
401379 }
402380
381+ private init ( variable base: Value , _ context: some Context ) {
382+ guard let introducer = gatherVariableIntroducers ( for: base, context) . singleElement else {
383+ // TODO: do we need to handle multiple introducers in case of a tuple/struct?
384+ self = . unknown( base)
385+ return
386+ }
387+ switch introducer {
388+ case let arg as FunctionArgument :
389+ self = . caller( arg)
390+ case let bbi as BeginBorrowInst :
391+ self = . borrowed( BeginBorrowValue ( bbi) !)
392+ case is MoveValueInst :
393+ self = . owned( introducer)
394+ default :
395+ self = . unknown( introducer)
396+ }
397+ }
398+
403399 private init ( yield result: MultipleValueInstructionResult ) {
404400 // Consider an @in yield an .initialized scope. We must find the destroys.
405401 let apply = result. parentInstruction as! FullApplySite
@@ -431,7 +427,7 @@ extension LifetimeDependence.Scope {
431427 if bb. isFromVarDecl {
432428 return self
433429 }
434- return LifetimeDependence . Scope ( base: bb. borrowedValue, context) ? . ignoreBorrowScope ( context)
430+ return LifetimeDependence . Scope ( base: bb. borrowedValue, context) . ignoreBorrowScope ( context)
435431 case let . loadBorrow( lb) :
436432 return LifetimeDependence . Scope ( base: lb. address, context)
437433 default :
@@ -443,7 +439,7 @@ extension LifetimeDependence.Scope {
443439extension LifetimeDependence . Scope {
444440 /// Compute the range of the dependence scope.
445441 ///
446- /// Returns nil if the dependence scope covers the entire function.
442+ /// Returns nil if the dependence scope covers the entire function. Returns an empty range for an unknown scope.
447443 ///
448444 /// Note: The caller must deinitialize the returned range.
449445 func computeRange( _ context: Context ) -> InstructionRange ? {
@@ -480,11 +476,12 @@ extension LifetimeDependence.Scope {
480476 return InstructionRange ( for: value, context)
481477 }
482478 }
483-
484- private static func computeInitializedRange ( initialAddress : Value ,
485- initializingStore: Instruction ? ,
479+
480+ // !!! - handle allocations of trivial values: no destroy. Use the dealloc in that case?
481+ private static func computeInitializedRange ( initialAddress : Value , initializingStore: Instruction ? ,
486482 _ context: Context )
487483 -> InstructionRange {
484+
488485 assert ( initialAddress. type. isAddress)
489486
490487 var range : InstructionRange
@@ -619,7 +616,12 @@ struct VariableIntroducerUseDefWalker : LifetimeDependenceUseDefWalker {
619616
620617 mutating func walkUp( value: Value , _ owner: Value ? ) -> WalkResult {
621618 if let inst = value. definingInstruction, VariableScopeInstruction ( inst) != nil {
622- return introducer ( value, owner)
619+ return visitorClosure ( value)
620+ }
621+ // Finding a variable introducer requires following the mark_dependence forwarded value, not the base value like the
622+ // default LifetimeDependenceUseDefWalker.
623+ if value is MarkDependenceInst {
624+ return walkUpDefault ( forwarded: value, owner)
623625 }
624626 return walkUpDefault ( dependent: value, owner: owner)
625627 }
@@ -685,6 +687,9 @@ struct VariableIntroducerUseDefWalker : LifetimeDependenceUseDefWalker {
685687protocol LifetimeDependenceUseDefWalker : ForwardingUseDefWalker where PathContext == Value ? {
686688 var context : Context { get }
687689
690+ /// 'owner' is the most recently visited suitable base. Generally, this is the most recent owned value. When a
691+ /// mark_dependence value operand is forwarded from its base operand, however, the owner is not updated because that
692+ /// would could lead to introducing an illegal mark_dependence with the same value for both operands.
688693 mutating func introducer( _ value: Value , _ owner: Value ? ) -> WalkResult
689694
690695 // Minimally, check a ValueSet. This walker may traverse chains of
@@ -1239,7 +1244,7 @@ let lifetimeDependenceScopeTest = FunctionTest("lifetime_dependence_scope") {
12391244 function, arguments, context in
12401245 let markDep = arguments. takeValue ( ) as! MarkDependenceInst
12411246 guard let dependence = LifetimeDependence ( markDep, context) else {
1242- print ( " Trivial Dependence" )
1247+ print ( " Invalid Dependence" )
12431248 return
12441249 }
12451250 print ( dependence)
0 commit comments