Skip to content

Commit 2812196

Browse files
committed
[lifetimes] add same-type default lifetime inference
Infer @Lifetime(result: copy arg) for every (result: R, arg: A) pair such that R == A and 'arg' is not 'inout'.
1 parent 885d14e commit 2812196

File tree

5 files changed

+313
-29
lines changed

5 files changed

+313
-29
lines changed

lib/AST/LifetimeDependence.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,8 @@ class LifetimeDependenceChecker {
10841084

10851085
// Infer non-Escapable results.
10861086
if (isDiagnosedNonEscapable(getResultOrYield())) {
1087+
inferNonEscapableResultOnSameTypeParam();
1088+
10871089
if (isInit() && isImplicitOrSIL()) {
10881090
inferImplicitInit();
10891091
} else if (hasImplicitSelfParam()) {
@@ -1105,6 +1107,45 @@ class LifetimeDependenceChecker {
11051107
inferInoutParams();
11061108
}
11071109

1110+
// Infer a dependency to the ~Escapable result from all parameters of the same
1111+
// type.
1112+
void inferNonEscapableResultOnSameTypeParam() {
1113+
// The function declaration's substituted result type.
1114+
CanType resultTy = getResultOrYield()->getCanonicalType();
1115+
1116+
TargetDeps *targetDeps = depBuilder.getInferredTargetDeps(resultIndex);
1117+
if (!targetDeps)
1118+
return;
1119+
1120+
// Ignore mutating self. An 'inout' modifier effectively makes the parameter
1121+
// a different type for lifetime inference.
1122+
if (hasImplicitSelfParam() && !afd->getImplicitSelfDecl()->isInOut()) {
1123+
Type selfTy = afd->mapTypeIntoEnvironment(dc->getSelfInterfaceType());
1124+
if (selfTy->getCanonicalType() == resultTy) {
1125+
targetDeps->inheritIndices.set(selfIndex);
1126+
}
1127+
}
1128+
1129+
unsigned paramIndex = 0;
1130+
for (auto *param : *afd->getParameters()) {
1131+
SWIFT_DEFER { paramIndex++; };
1132+
1133+
// Ignore 'inout' parameters. An 'inout' modifier effectively makes the
1134+
// parameter a different type for lifetime inference. An 'inout' parameter
1135+
// defaults to being the source and target of a self-dependency, as
1136+
// covered by the 'inout' rule.
1137+
if (param->isInOut())
1138+
continue;
1139+
1140+
CanType paramTy = afd->mapTypeIntoEnvironment(
1141+
param->getInterfaceType())->getCanonicalType();
1142+
if (paramTy != resultTy)
1143+
continue;
1144+
1145+
targetDeps->inheritIndices.set(paramIndex);
1146+
}
1147+
}
1148+
11081149
// Infer dependence for an accessor whose non-escapable result depends on
11091150
// self. This includes _read and _modify.
11101151
//

test/Parse/lifetime_attr.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ func derive(_ ne1: NE, _ ne2: NE) -> NE {
2020
}
2121

2222
@_lifetime // expected-error{{expected '(' after lifetime dependence specifier}}
23-
func testMissingLParenError(_ ne: NE) -> NE { // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
23+
func testMissingLParenError(_ ne: NE) -> NE {
2424
ne
2525
}
2626

2727
@_lifetime() // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier, index or 'self' in lifetime dependence specifier}}
28-
func testMissingDependence(_ ne: NE) -> NE { // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
28+
func testMissingDependence(_ ne: NE) -> NE {
2929
ne
3030
}
3131

test/Sema/lifetime_depend_infer.swift

Lines changed: 136 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// RUN: %target-typecheck-verify-swift \
2-
// RUN: -enable-experimental-feature Lifetimes
2+
// RUN: -enable-experimental-feature Lifetimes \
3+
// RUN: -enable-experimental-feature SuppressedAssociatedTypes
34

45
// REQUIRES: swift_feature_Lifetimes
6+
// REQUIRES: swift_feature_SuppressedAssociatedTypes
57

68
// Coverage testing for LifetimeDependence inferrence logic. The tests are sorted and grouped according to
79
// docs/ReferenceGuides/LifetimeAnnotation.md. To find the cases that cover the default lifetime
@@ -21,6 +23,117 @@ struct NEImmortal: ~Escapable {
2123

2224
struct MutNE: ~Copyable & ~Escapable {}
2325

26+
// =============================================================================
27+
// Same-type default rule
28+
// =============================================================================
29+
30+
func sameTypeParam(ne: NE) -> NE { ne }
31+
32+
func sameTypeConsumingParam(ne: consuming NE) -> NE { ne }
33+
34+
func sameTypeBorrowingParam(ne: borrowing NE) -> NE { ne }
35+
36+
func sameTypeInoutParam(ne: inout NE) -> NE { ne } // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
37+
38+
func sameTypeParam_sameTypeParam(ne1: NE, ne2: NE) -> NE { ne1 }
39+
40+
func sameTypeParam_otherTypeParam(ne: NE, c: C) -> NE { ne }
41+
42+
func sameTypeParam_sameTypeInoutParam(ne: NE, mutNE: inout NE) -> NE { ne }
43+
44+
struct NonEscapable<T>: ~Escapable {
45+
@_lifetime(immortal)
46+
init() {}
47+
48+
init(ne: Self) {}
49+
50+
init(c: C) {} // expected-error{{cannot borrow the lifetime of 'c', which has consuming ownership on an initializer}}
51+
52+
init(ne: Self, c: C) {}
53+
54+
init<U>(ne: Self, u: U) {}
55+
56+
init<U>(neNominal: NonEscapable<T>, u: U) {}
57+
58+
init<U>(other: NonEscapable<U>) {} // expected-error{{cannot infer the lifetime dependence scope on an initializer with a ~Escapable parameter, specify '@_lifetime(borrow other)' or '@_lifetime(copy other)'}}
59+
60+
func sameTypeSelf_noParam() -> Self { self }
61+
62+
consuming func sameTypeConsumingSelf_noParam() -> Self { self }
63+
64+
borrowing func sameTypeBorrowingSelf_noParam() -> Self { self }
65+
66+
mutating func sameTypeMutatingSelf() -> Self { self } // expected-error{{a mutating method with a ~Escapable result requires '@_lifetime(...)'}}
67+
68+
func sameTypeSelf_sameTypeParam(ne: Self) -> Self { self }
69+
70+
func sameTypeSelf_otherTypeParam(c: C) -> Self { self }
71+
72+
func sameTypeSelf_sameTypeInoutParam(mutNE: inout Self) -> Self { self }
73+
74+
func sameArchetypeSelf<U>(u: U) -> Self { self }
75+
76+
func sameNominalTypeSelf_genericParam<U>(u: U) -> NonEscapable<T> { self }
77+
78+
func otherNominalTypeSelf_genericParam<U>(u: U) -> NonEscapable<U> { NonEscapable<U>() } // expected-error{{a method with a ~Escapable result requires '@_lifetime(...)'}}
79+
}
80+
81+
protocol NonEscapableProtocol: ~Escapable {
82+
@_lifetime(immortal)
83+
static func create() -> Self
84+
85+
init(ne: Self)
86+
87+
init<U>(ne: Self, u: U)
88+
89+
init(ne: some NonEscapableProtocol, c: C) // expected-error{{an initializer with a ~Escapable result requires '@_lifetime(...)'}}
90+
91+
init(neProtocol: any NonEscapableProtocol, c: C) // expected-error{{an initializer with a ~Escapable result requires '@_lifetime(...)'}}
92+
93+
func sameArchetypeSelf() -> Self
94+
95+
mutating func sameArchetypeMutatingSelf() -> Self // expected-error{{a mutating method with a ~Escapable result requires '@_lifetime(...)'}}
96+
}
97+
98+
extension NonEscapableProtocol where Self: ~Escapable {
99+
func sameArchetypeSelf() -> Self {
100+
Self.create()
101+
}
102+
}
103+
104+
func sameGenericTypeParam<T: ~Escapable>(ne: T) -> T {
105+
ne
106+
}
107+
108+
func otherGenericTypeParam<T: ~Escapable,
109+
U: NonEscapableProtocol & ~Escapable>(
110+
ne: T, utype: U.Type) -> U { // expected-error{{a function with a ~Escapable result requires '@_lifetime(...)'}}
111+
U.create()
112+
}
113+
114+
protocol P_NE {
115+
associatedtype T: ~Escapable
116+
}
117+
118+
protocol Q_NE {
119+
associatedtype U: NonEscapableProtocol & ~Escapable
120+
}
121+
122+
struct AssociatedNE<P: P_NE, Q: Q_NE> {
123+
func otherAssociatedTypeParam(a: P.T, b: P.T) -> Q.U { // expected-error{{a method with a ~Escapable result requires '@_lifetime(...)'}}
124+
Q.U.create()
125+
}
126+
}
127+
128+
extension AssociatedNE where P.T == Q.U {
129+
/* OK: @_lifetime(copy a) is valid and default */
130+
func sameAssociatedTypeParam(a: P.T) -> Q.U {
131+
// Note: the same-type rule is satisfied in this context, but the declaration of 'otherAssociatedTypeParam'
132+
// is itself invalid.
133+
otherAssociatedTypeParam(a: a, b: a)
134+
}
135+
}
136+
24137
// =============================================================================
25138
// Single parameter default rule for functions
26139
// =============================================================================
@@ -71,22 +184,22 @@ func twoParamsBorrow_NEResult(c: borrowing C, _: Int) -> NEImmortal { NEImmortal
71184

72185
func twoParamsInout_NEResult(c: inout C, _: Int) -> NEImmortal { NEImmortal() } // expected-error{{a function with a ~Escapable result requires '@_lifetime(...)'}}
73186

74-
func neParam_NEResult(ne: NE) -> NE { ne } // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
187+
func neParam_NEResult(ne: NE) -> NE { ne }
75188

76189
@_lifetime(ne) // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
77190
func neParamLifetime_NEResult(ne: NE) -> NE { ne }
78191

79-
func neParamBorrow_NEResult(ne: borrowing NE) -> NE { ne } // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
192+
func neParamBorrow_NEResult(ne: borrowing NE) -> NE { ne }
80193

81194
@_lifetime(ne) // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
82195
func neParamBorrowLifetime_NEResult(ne: borrowing NE) -> NE { ne }
83196

84-
func neParamConsume_NEResult(ne: consuming NE) -> NE { ne } // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
197+
func neParamConsume_NEResult(ne: consuming NE) -> NE { ne }
85198

86199
@_lifetime(ne) // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
87200
func neParamConsumeLifetime_NEResult(ne: consuming NE) -> NE { ne }
88201

89-
func neParam_IntParam_NEResult(ne: NE, _:Int) -> NE { ne } // expected-error{{a function with a ~Escapable result requires '@_lifetime(...)'}}
202+
func neParam_IntParam_NEResult(ne: NE, _:Int) -> NE { ne }
90203

91204
func inoutParam_inoutParam_NEResult(a: inout C, b: inout C) -> NEImmortal { NEImmortal() }
92205
// expected-error@-1{{a function with a ~Escapable result requires '@_lifetime(...)'}}
@@ -201,50 +314,50 @@ struct EscapableTrivialSelf {
201314
mutating func mutating_oneParamBorrow_NEResult(_: Int) -> NEImmortal { NEImmortal() }
202315
}
203316

204-
struct NonEscapableSelf: ~Escapable {
205-
func noParam_NEResult() -> NonEscapableSelf { self } // expected-error{{cannot infer the lifetime dependence scope on a method with a ~Escapable parameter, specify '@_lifetime(borrow self)' or '@_lifetime(copy self)'}}
317+
extension NonEscapable /* where Self: ~Escapable */ {
318+
func noParam_NEResult() -> NonEscapable { self }
206319

207320
@_lifetime(self) // expected-error{{cannot infer the lifetime dependence scope on a method with a ~Escapable parameter, specify '@_lifetime(borrow self)' or '@_lifetime(copy self)'}}
208-
func noParamLifetime_NEResult() -> NonEscapableSelf { self }
321+
func noParamLifetime_NEResult() -> NonEscapable { self }
209322

210323
@_lifetime(copy self) // OK
211-
func noParamCopy_NEResult_NEResult() -> NonEscapableSelf { self }
324+
func noParamCopy_NEResult_NEResult() -> NonEscapable { self }
212325

213326
@_lifetime(borrow self) // OK
214-
func noParamBorrow_NEResult() -> NonEscapableSelf { self }
327+
func noParamBorrow_NEResult() -> NonEscapable { self }
215328

216-
mutating func mutating_noParam_NEResult() -> NonEscapableSelf { self } // expected-error{{a mutating method with a ~Escapable result requires '@_lifetime(...)'}}
329+
mutating func mutating_noParam_NEResult() -> NonEscapable { self } // expected-error{{a mutating method with a ~Escapable result requires '@_lifetime(...)'}}
217330

218331
@_lifetime(self) // expected-error{{cannot infer the lifetime dependence scope on a mutating method with a ~Escapable parameter, specify '@_lifetime(borrow self)' or '@_lifetime(copy self)'}}
219-
mutating func mutating_noParamLifetime_NEResult() -> NonEscapableSelf { self }
332+
mutating func mutating_noParamLifetime_NEResult() -> NonEscapable { self }
220333

221334
@_lifetime(copy self) // OK
222-
mutating func mutating_noParamCopy_NEResult() -> NonEscapableSelf { self }
335+
mutating func mutating_noParamCopy_NEResult() -> NonEscapable { self }
223336

224337
@_lifetime(&self) // OK
225-
mutating func mutating_noParamBorrow_NEResult() -> NonEscapableSelf { self }
338+
mutating func mutating_noParamBorrow_NEResult() -> NonEscapable { self }
226339

227-
func oneParam_NEResult(_: Int) -> NonEscapableSelf { self } // expected-error{{a method with a ~Escapable result requires '@_lifetime(...)'}}
340+
func oneParam_NEResult(_: Int) -> NonEscapable { self }
228341

229342
@_lifetime(self) // expected-error{{cannot infer the lifetime dependence scope on a method with a ~Escapable parameter, specify '@_lifetime(borrow self)' or '@_lifetime(copy self)'}}
230-
func oneParamLifetime_NEResult(_: Int) -> NonEscapableSelf { self }
343+
func oneParamLifetime_NEResult(_: Int) -> NonEscapable { self }
231344

232345
@_lifetime(copy self) // OK
233-
func oneParamCopy_NEResult(_: Int) -> NonEscapableSelf { self }
346+
func oneParamCopy_NEResult(_: Int) -> NonEscapable { self }
234347

235348
@_lifetime(borrow self) // OK
236-
func oneParamBorrow_NEResult(_: Int) -> NonEscapableSelf { self }
349+
func oneParamBorrow_NEResult(_: Int) -> NonEscapable { self }
237350

238-
mutating func mutating_oneParam_NEResult(_: Int) -> NonEscapableSelf { self } // expected-error{{a mutating method with a ~Escapable result requires '@_lifetime(...)'}}
351+
mutating func mutating_oneParam_NEResult(_: Int) -> NonEscapable { self } // expected-error{{a mutating method with a ~Escapable result requires '@_lifetime(...)'}}
239352

240353
@_lifetime(self) // expected-error{{cannot infer the lifetime dependence scope on a mutating method with a ~Escapable parameter, specify '@_lifetime(borrow self)' or '@_lifetime(copy self)'}}
241-
mutating func mutating_oneParamLifetime_NEResult(_: Int) -> NonEscapableSelf { self }
354+
mutating func mutating_oneParamLifetime_NEResult(_: Int) -> NonEscapable { self }
242355

243356
@_lifetime(copy self) // OK
244-
mutating func mutating_oneParamCopy_NEResult(_: Int) -> NonEscapableSelf { self }
357+
mutating func mutating_oneParamCopy_NEResult(_: Int) -> NonEscapable { self }
245358

246359
@_lifetime(&self) // OK
247-
mutating func mutating_oneParamBorrow_NEResult(_: Int) -> NonEscapableSelf { self }
360+
mutating func mutating_oneParamBorrow_NEResult(_: Int) -> NonEscapable { self }
248361

249362
mutating func mutating_inoutParam_NEResult(a: inout NE) -> NEImmortal { NEImmortal() } // expected-error{{a mutating method with a ~Escapable result requires '@_lifetime(...)'}}
250363
}
@@ -263,6 +376,7 @@ func inoutNEParam_NEParam_void(_: inout NE, _: NE) {} // OK
263376
/* DEFAULT: @_lifetime(1: copy 1) */
264377
func inoutParam_inoutNEParam_void(_: inout NE, _: inout NE) {} // OK
265378

379+
266380
func inoutNEParam_NEResult(ne: inout NE) -> NE { ne } // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
267381

268382
/* DEFAULT: @_lifetime(ne: copy ne) */

0 commit comments

Comments
 (0)