Skip to content

Commit 54cf136

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 fdad8c5 commit 54cf136

File tree

5 files changed

+155
-13
lines changed

5 files changed

+155
-13
lines changed

lib/AST/LifetimeDependence.cpp

Lines changed: 38 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,42 @@ 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+
CanType resultTy = getResultOrYield()->getCanonicalType();
1114+
1115+
TargetDeps *targetDeps = depBuilder.getInferredTargetDeps(resultIndex);
1116+
if (!targetDeps)
1117+
return;
1118+
1119+
if (hasImplicitSelfParam() && !afd->getImplicitSelfDecl()->isInOut()) {
1120+
CanType selfTy = dc->getSelfTypeInContext()->getCanonicalType();
1121+
if (selfTy == resultTy) {
1122+
targetDeps->inheritIndices.set(selfIndex);
1123+
}
1124+
}
1125+
1126+
unsigned paramIndex = 0;
1127+
for (auto *param : *afd->getParameters()) {
1128+
SWIFT_DEFER { paramIndex++; };
1129+
1130+
// Ignore inout parameters--they are effectively considered to be a
1131+
// different type when applying the same-type rule. An inout parameter is
1132+
// only a default dependency source or target for the dependency on
1133+
// itself, which is covered by the 'inout' rule.
1134+
if (param->isInOut())
1135+
continue;
1136+
1137+
CanType paramTy = afd->mapTypeIntoEnvironment(
1138+
param->getInterfaceType())->getCanonicalType();
1139+
if (paramTy != resultTy)
1140+
continue;
1141+
1142+
targetDeps->inheritIndices.set(paramIndex);
1143+
}
1144+
}
1145+
11081146
// Infer dependence for an accessor whose non-escapable result depends on
11091147
// self. This includes _read and _modify.
11101148
//

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: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,46 @@ struct NEImmortal: ~Escapable {
2121

2222
struct MutNE: ~Copyable & ~Escapable {}
2323

24+
// =============================================================================
25+
// Same-type default rule
26+
// =============================================================================
27+
28+
func sameTypeParam(ne: NE) -> NE { ne }
29+
30+
func sameTypeConsumingParam(ne: consuming NE) -> NE { ne }
31+
32+
func sameTypeBorrowingParam(ne: borrowing NE) -> NE { ne }
33+
34+
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)'}}
35+
36+
func sameTypeParam_sameTypeParam(ne1: NE, ne2: NE) -> NE { ne1 }
37+
38+
func sameTypeParam_otherTypeParam(ne: NE, c: C) -> NE { ne }
39+
40+
func sameTypeParam_sameTypeInoutParam(ne: NE, mutNE: inout NE) -> NE { ne }
41+
42+
struct NonEscapableSelf: ~Escapable {
43+
init(ne: NonEscapableSelf) {}
44+
45+
init(c: C) {} // expected-error{{cannot borrow the lifetime of 'c', which has consuming ownership on an initializer}}
46+
47+
init(ne: NonEscapableSelf, c: C) {}
48+
49+
func sameTypeSelf_noParam() -> Self { self }
50+
51+
consuming func sameTypeConsumingSelf_noParam() -> Self { self }
52+
53+
borrowing func sameTypeBorrowingSelf_noParam() -> Self { self }
54+
55+
func sameTypeSelf_InoutParam(ne: inout NE) -> NE { ne } // expected-error{{a method with a ~Escapable result requires '@_lifetime(...)'}}
56+
57+
func sameTypeSelf_sameTypeParam(ne: NonEscapableSelf) -> Self { self }
58+
59+
func sameTypeSelf_otherTypeParam(c: C) -> Self { self }
60+
61+
func sameTypeSelf_sameTypeInoutParam(mutNE: inout NonEscapableSelf) -> Self { self }
62+
}
63+
2464
// =============================================================================
2565
// Single parameter default rule for functions
2666
// =============================================================================
@@ -71,22 +111,22 @@ func twoParamsBorrow_NEResult(c: borrowing C, _: Int) -> NEImmortal { NEImmortal
71111

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

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)'}}
114+
func neParam_NEResult(ne: NE) -> NE { ne }
75115

76116
@_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)'}}
77117
func neParamLifetime_NEResult(ne: NE) -> NE { ne }
78118

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)'}}
119+
func neParamBorrow_NEResult(ne: borrowing NE) -> NE { ne }
80120

81121
@_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)'}}
82122
func neParamBorrowLifetime_NEResult(ne: borrowing NE) -> NE { ne }
83123

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)'}}
124+
func neParamConsume_NEResult(ne: consuming NE) -> NE { ne }
85125

86126
@_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)'}}
87127
func neParamConsumeLifetime_NEResult(ne: consuming NE) -> NE { ne }
88128

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

91131
func inoutParam_inoutParam_NEResult(a: inout C, b: inout C) -> NEImmortal { NEImmortal() }
92132
// expected-error@-1{{a function with a ~Escapable result requires '@_lifetime(...)'}}
@@ -201,8 +241,8 @@ struct EscapableTrivialSelf {
201241
mutating func mutating_oneParamBorrow_NEResult(_: Int) -> NEImmortal { NEImmortal() }
202242
}
203243

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)'}}
244+
extension NonEscapableSelf /* where Self: ~Escapable */ {
245+
func noParam_NEResult() -> NonEscapableSelf { self }
206246

207247
@_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)'}}
208248
func noParamLifetime_NEResult() -> NonEscapableSelf { self }
@@ -224,7 +264,7 @@ struct NonEscapableSelf: ~Escapable {
224264
@_lifetime(&self) // OK
225265
mutating func mutating_noParamBorrow_NEResult() -> NonEscapableSelf { self }
226266

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

229269
@_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)'}}
230270
func oneParamLifetime_NEResult(_: Int) -> NonEscapableSelf { self }
@@ -263,6 +303,7 @@ func inoutNEParam_NEParam_void(_: inout NE, _: NE) {} // OK
263303
/* DEFAULT: @_lifetime(1: copy 1) */
264304
func inoutParam_inoutNEParam_void(_: inout NE, _: inout NE) {} // OK
265305

306+
266307
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)'}}
267308

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

test/Sema/lifetime_depend_infer_defaults.swift

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,68 @@ struct NEImmortal: ~Escapable {
1818

1919
struct MutNE: ~Copyable & ~Escapable {}
2020

21+
// =============================================================================
22+
// Same-type default rule
23+
// =============================================================================
24+
25+
/* DEFAULT: @_lifetime(copy ne) */
26+
// CHECK: @$s30lifetime_depend_infer_defaults13sameTypeParam2neAA2NEVAE_tF : $@convention(thin) (@guaranteed NE) -> @lifetime(copy 0) @owned NE
27+
func sameTypeParam(ne: NE) -> NE { ne }
28+
29+
/* DEFAULT: @_lifetime(copy ne) */
30+
// CHECK: @$s30lifetime_depend_infer_defaults22sameTypeConsumingParam2neAA2NEVAEn_tF : $@convention(thin) (@owned NE) -> @lifetime(copy 0) @owned NE
31+
func sameTypeConsumingParam(ne: consuming NE) -> NE { ne }
32+
33+
/* DEFAULT: @_lifetime(copy ne) */
34+
// CHECK: @$s30lifetime_depend_infer_defaults22sameTypeBorrowingParam2neAA2NEVAE_tF : $@convention(thin) (@guaranteed NE) -> @lifetime(copy 0) @owned NE
35+
func sameTypeBorrowingParam(ne: borrowing NE) -> NE { ne }
36+
37+
/* DEFAULT: @_lifetime(copy ne, copy ne2) */
38+
// CHECK: @$s30lifetime_depend_infer_defaults014sameTypeParam_efG03ne13ne2AA2NEVAF_AFtF : $@convention(thin) (@guaranteed NE, @guaranteed NE) -> @lifetime(copy 0, copy 1) @owned NE
39+
func sameTypeParam_sameTypeParam(ne1: NE, ne2: NE) -> NE { ne1 }
40+
41+
/* DEFAULT: @_lifetime(copy ne) */
42+
// CHECK: @$s30lifetime_depend_infer_defaults019sameTypeParam_otherfG02ne1cAA2NEVAF_AA1CCtF : $@convention(thin) (@guaranteed NE, @guaranteed C) -> @lifetime(copy 0) @owned NE
43+
func sameTypeParam_otherTypeParam(ne: NE, c: C) -> NE { ne }
44+
45+
/* DEFAULT: @_lifetime(copy ne) */
46+
// CHECK: @$s30lifetime_depend_infer_defaults014sameTypeParam_ef5InoutG02ne5mutNEAA0K0VAF_AFztF : $@convention(thin) (@guaranteed NE, @lifetime(copy 1) @inout NE) -> @lifetime(copy 0) @owned NE
47+
func sameTypeParam_sameTypeInoutParam(ne: NE, mutNE: inout NE) -> NE { ne }
48+
49+
struct NonEscapableSelf: ~Escapable {
50+
/* DEFAULT: @_lifetime(copy ne) */
51+
// CHECK: @$s30lifetime_depend_infer_defaults16NonEscapableSelfV2neA2C_tcfC : $@convention(method) (@owned NonEscapableSelf, @thin NonEscapableSelf.Type) -> @lifetime(copy 0) @owned NonEscapableSelf
52+
init(ne: NonEscapableSelf) {}
53+
54+
/* DEFAULT: @_lifetime(copy ne) */
55+
// CHECK: @$s30lifetime_depend_infer_defaults16NonEscapableSelfV2ne1cA2C_AA1CCtcfC : $@convention(method) (@owned NonEscapableSelf, @owned C, @thin NonEscapableSelf.Type) -> @lifetime(copy 0) @owned NonEscapableSelf
56+
init(ne: NonEscapableSelf, c: C) {}
57+
58+
/* DEFAULT: @_lifetime(copy self) */
59+
// CHECK: $s30lifetime_depend_infer_defaults16NonEscapableSelfV08sameTypeG8_noParamACyF : $@convention(method) (@guaranteed NonEscapableSelf) -> @lifetime(copy 0) @owned NonEscapableSelf
60+
func sameTypeSelf_noParam() -> Self { self }
61+
62+
/* DEFAULT: @_lifetime(copy self) */
63+
// CHECK: @$s30lifetime_depend_infer_defaults16NonEscapableSelfV017sameTypeConsumingG8_noParamACyF : $@convention(method) (@owned NonEscapableSelf) -> @lifetime(copy 0) @owned NonEscapableSelf
64+
consuming func sameTypeConsumingSelf_noParam() -> Self { self }
65+
66+
/* DEFAULT: @_lifetime(copy self) */
67+
// CHECK: @$s30lifetime_depend_infer_defaults16NonEscapableSelfV017sameTypeBorrowingG8_noParamACyF : $@convention(method) (@guaranteed NonEscapableSelf) -> @lifetime(copy 0) @owned NonEscapableSelf
68+
borrowing func sameTypeBorrowingSelf_noParam() -> Self { self }
69+
70+
/* DEFAULT: @_lifetime(copy self, copy ne) */
71+
// CHECK: @$s30lifetime_depend_infer_defaults16NonEscapableSelfV08sameTypeg1_hI5Param2neA2C_tF : $@convention(method) (@guaranteed NonEscapableSelf, @guaranteed NonEscapableSelf) -> @lifetime(copy 0, copy 1) @owned NonEscapableSelf
72+
func sameTypeSelf_sameTypeParam(ne: NonEscapableSelf) -> Self { self }
73+
74+
/* DEFAULT: @_lifetime(copy self) */
75+
// CHECK: @$s30lifetime_depend_infer_defaults16NonEscapableSelfV08sameTypeg6_otherI5Param1cAcA1CC_tF : $@convention(method) (@guaranteed C, @guaranteed NonEscapableSelf) -> @lifetime(copy 1) @owned NonEscapableSelf
76+
func sameTypeSelf_otherTypeParam(c: C) -> Self { self }
77+
78+
/* DEFAULT: @_lifetime(copy self) */
79+
// CHECK: @$s30lifetime_depend_infer_defaults16NonEscapableSelfV08sameTypeg1_hI10InoutParam5mutNEA2Cz_tF : $@convention(method) (@lifetime(copy 0) @inout NonEscapableSelf, @guaranteed NonEscapableSelf) -> @lifetime(copy 1) @owned NonEscapableSelf
80+
func sameTypeSelf_sameTypeInoutParam(mutNE: inout NonEscapableSelf) -> Self { self }
81+
}
82+
2183
// =============================================================================
2284
// Single parameter default rule for functions
2385
// =============================================================================
@@ -112,7 +174,8 @@ struct EscapableTrivialSelf {
112174
func inoutNEParam_void(ne: inout NE) {} // OK
113175

114176
/* DEFAULT: @_lifetime(0: copy 0) */
115-
// CHECK: @$s30lifetime_depend_infer_defaults013inoutNEParam_F5_voidyyAA2NEVz_ADtF : $@convention(thin) (@lifetime(copy 0) @inout NE, @guaranteed NE) -> ()
177+
// CHECK: @$s30lifetime_depend_infer_defaults013inoutNEParam_F5_voidyyAA2NEVz_ADtF : $@convention(thin) (@lifetime(copy
178+
// 0, copy 1) @inout NE, @guaranteed NE) -> ()
116179
func inoutNEParam_NEParam_void(_: inout NE, _: NE) {} // OK
117180

118181
/* DEFAULT: @_lifetime(0: copy 0) */

test/Sema/lifetime_depend_noattr.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@
1313
struct EmptyNonEscapable: ~Escapable {} // OK - no dependence
1414

1515
// Don't allow non-Escapable return values.
16-
func neReturn(span: RawSpan) -> RawSpan { span } // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow span)' or '@_lifetime(copy span)'}}
16+
func neReturn(span: RawSpan) -> RawSpan { span }
1717

1818
func neInout(span: inout RawSpan) {} // OK - inferred
1919

2020
struct S {
21-
func neReturn(span: RawSpan) -> RawSpan { span } // expected-error{{a method with a ~Escapable result requires '@_lifetime(...)}}
21+
func neReturn(span: RawSpan) -> RawSpan { span }
2222

2323
func neInout(span: inout RawSpan) {} // OK - inferred
2424
}
2525

2626
class C {
27-
func neReturn(span: RawSpan) -> RawSpan { span } // expected-error{{a method with a ~Escapable result requires '@_lifetime(...)'}}
27+
func neReturn(span: RawSpan) -> RawSpan { span }
2828

2929
func neInout(span: inout RawSpan) {} // OK - inferred
3030
}

0 commit comments

Comments
 (0)