Skip to content

Commit 9eaa365

Browse files
committed
CSGen: Disable optional flattening for try? on delegations to Optional initializers
We need the extra level of optionality here to discern between failures and constructed values.
1 parent c9f472b commit 9eaa365

File tree

3 files changed

+489
-4
lines changed

3 files changed

+489
-4
lines changed

lib/Sema/CSGen.cpp

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,9 +1718,48 @@ namespace {
17181718
if (!optTy)
17191719
return Type();
17201720

1721-
// Prior to Swift 5, 'try?' always adds an additional layer of optionality,
1722-
// even if the sub-expression was already optional.
1723-
if (CS.getASTContext().LangOpts.isSwiftVersionAtLeast(5)) {
1721+
bool isDelegationToOptionalInit = false;
1722+
{
1723+
Expr *e = expr->getSubExpr();
1724+
while (true) {
1725+
e = e->getSemanticsProvidingExpr();
1726+
1727+
// Look through force-value expressions.
1728+
if (auto *FVE = dyn_cast<ForceValueExpr>(e)) {
1729+
e = FVE->getSubExpr();
1730+
continue;
1731+
}
1732+
1733+
break;
1734+
}
1735+
1736+
if (auto *CE = dyn_cast<CallExpr>(e)) {
1737+
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(CE->getFn())) {
1738+
if (!CS.getType(UDE->getBase())->is<AnyMetatypeType>()) {
1739+
auto overload =
1740+
CS.findSelectedOverloadFor(CS.getConstraintLocator(
1741+
UDE, ConstraintLocator::ConstructorMember));
1742+
if (overload) {
1743+
auto *decl = overload->choice.getDeclOrNull();
1744+
if (decl && isa<ConstructorDecl>(decl) &&
1745+
decl->getDeclContext()
1746+
->getSelfNominalTypeDecl()
1747+
->isOptionalDecl())
1748+
isDelegationToOptionalInit = true;
1749+
}
1750+
}
1751+
}
1752+
}
1753+
}
1754+
1755+
// Prior to Swift 5, 'try?' always adds an additional layer of
1756+
// optionality, even if the sub-expression was already optional.
1757+
//
1758+
// NB Keep adding the additional layer in Swift 5 and on if this 'try?'
1759+
// applies to a delegation to an 'Optional' initializer, or else we won't
1760+
// discern the difference between a failure and a constructed value.
1761+
if (CS.getASTContext().LangOpts.isSwiftVersionAtLeast(5) &&
1762+
!isDelegationToOptionalInit) {
17241763
CS.addConstraint(ConstraintKind::Conversion,
17251764
CS.getType(expr->getSubExpr()), optTy,
17261765
CS.getConstraintLocator(expr));

test/SILGen/init_delegation_optional.swift

Lines changed: 326 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
1+
// 'try?' on delegations to 'Optional' initializers should never flatten
2+
// optionals, or else we do not discern the difference between a failure and a
3+
// constructed value. Run in compatibility modes that disable and enable
4+
// the flattening to verify this.
5+
// RUN: %target-swift-emit-silgen %s -swift-version 5 | %FileCheck %s
6+
// RUN: %target-swift-emit-silgen %s -swift-version 4.2 | %FileCheck %s
27

38
extension Optional {
49
init(nonFailable1: ()) {
@@ -96,6 +101,262 @@ extension Optional {
96101
// CHECK-NEXT: return [[RET]] : $()
97102
// CHECK-NEXT: }
98103
}
104+
105+
init(throws: ()) throws {
106+
self = .none
107+
}
108+
109+
// CHECK-LABEL: sil hidden [ossa] @$sSq24init_delegation_optionalE9failable3xSgSgyt_tcfC
110+
init?(failable3: ()) {
111+
// CHECK: bb0([[OUT:%[0-9]+]] : $*Optional<Optional<Wrapped>>, [[SELF_META:%[0-9]+]] : $@thin Optional<Wrapped>.Type):
112+
// CHECK-NEXT: [[SELF_BOX:%[0-9]+]] = alloc_box $<τ_0_0> { var Optional<τ_0_0> } <Wrapped>, var
113+
// CHECK-NEXT: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
114+
// CHECK-NEXT: [[SELF_LIFETIME:%[0-9]+]] = begin_borrow [lexical] [[MARKED_SELF_BOX]]
115+
// CHECK-NEXT: [[PB:%[0-9]+]] = project_box [[SELF_LIFETIME]]
116+
// CHECK: [[OPT_RESULT_ADDR:%[0-9]+]] = alloc_stack $Optional<Optional<Wrapped>>
117+
// CHECK-NEXT: [[OPT_RESULT_DATA_ADDR:%[0-9]+]] = init_enum_data_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
118+
// CHECK: [[DELEG_INIT:%[0-9]+]] = function_ref @$sSq24init_delegation_optionalE6throwsxSgyt_tKcfC
119+
// CHECK-NEXT: try_apply [[DELEG_INIT]]<Wrapped>([[OPT_RESULT_DATA_ADDR]], [[SELF_META]]) : {{.*}}, normal [[SUCC_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
120+
try? self.init(throws: ())
121+
//
122+
// CHECK: [[SUCC_BB]]
123+
// CHECK-NEXT: inject_enum_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
124+
// CHECK-NEXT: br bb2
125+
//
126+
// CHECK: bb2:
127+
// CHECK: [[SELECT:%[0-9]+]] = select_enum_addr [[OPT_RESULT_ADDR]]
128+
// CHECK-NEXT: cond_br [[SELECT]], [[SOME_BB:bb[0-9]]], [[NONE_BB:bb[0-9]]]
129+
//
130+
// CHECK: [[NONE_BB]]:
131+
// CHECK-NEXT: destroy_addr [[OPT_RESULT_ADDR]]
132+
// CHECK-NEXT: dealloc_stack [[OPT_RESULT_ADDR]]
133+
// CHECK-NEXT: br bb5
134+
//
135+
// CHECK: [[SOME_BB]]:
136+
// CHECK-NEXT: [[RESULT_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
137+
// CHECK-NEXT: copy_addr [take] [[RESULT_ADDR]] to [[PB]]
138+
// CHECK-NEXT: dealloc_stack [[OPT_RESULT_ADDR]]
139+
// CHECK-NEXT: [[OUT_DATA_ADDR:%[0-9]+]] = init_enum_data_addr [[OUT]] : {{.*}}, #Optional.some!enumelt
140+
// CHECK-NEXT: copy_addr [[PB]] to [initialization] [[OUT_DATA_ADDR]]
141+
// CHECK-NEXT: inject_enum_addr [[OUT]] : {{.*}}, #Optional.some!enumelt
142+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
143+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
144+
// CHECK-NEXT: br bb6
145+
//
146+
// CHECK: bb5:
147+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
148+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
149+
// CHECK-NEXT: inject_enum_addr [[OUT]] : {{.*}}, #Optional.none!enumelt
150+
// CHECK-NEXT: br bb6
151+
//
152+
// CHECK: bb6:
153+
// CHECK-NEXT: [[RET:%[0-9]+]] = tuple ()
154+
// CHECK-NEXT: return [[RET]] : $()
155+
//
156+
// CHECK: bb7([[ERR:%[0-9]+]] : @owned $Error):
157+
// CHECK-NEXT: destroy_value [[ERR]]
158+
// CHECK-NEXT: inject_enum_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.none!enumelt
159+
// CHECK-NEXT: br bb2
160+
//
161+
// CHECK: [[ERROR_BB]]([[ERR:%[0-9]+]] : @owned $Error):
162+
// CHECK-NEXT: br bb7([[ERR]] : $Error)
163+
// CHECK-NEXT: }
164+
}
165+
166+
init?(failableAndThrows: ()) throws {
167+
self = .none
168+
}
169+
170+
// CHECK-LABEL: sil hidden [ossa] @$sSq24init_delegation_optionalE9failable4xSgSgyt_tcfC
171+
init?(failable4: ()) {
172+
// CHECK: bb0([[OUT:%[0-9]+]] : $*Optional<Optional<Wrapped>>, [[SELF_META:%[0-9]+]] : $@thin Optional<Wrapped>.Type):
173+
// CHECK-NEXT: [[SELF_BOX:%[0-9]+]] = alloc_box $<τ_0_0> { var Optional<τ_0_0> } <Wrapped>, var
174+
// CHECK-NEXT: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
175+
// CHECK-NEXT: [[SELF_LIFETIME:%[0-9]+]] = begin_borrow [lexical] [[MARKED_SELF_BOX]]
176+
// CHECK-NEXT: [[PB:%[0-9]+]] = project_box [[SELF_LIFETIME]]
177+
// CHECK: [[OPT_OPT_RESULT_ADDR:%[0-9]+]] = alloc_stack $Optional<Optional<Optional<Wrapped>>>
178+
// CHECK-NEXT: [[OPT_OPT_RESULT_DATA_ADDR:%[0-9]+]] = init_enum_data_addr [[OPT_OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
179+
// CHECK: [[DELEG_INIT:%[0-9]+]] = function_ref @$sSq24init_delegation_optionalE17failableAndThrowsxSgSgyt_tKcfC
180+
// CHECK-NEXT: try_apply [[DELEG_INIT]]<Wrapped>([[OPT_OPT_RESULT_DATA_ADDR]], [[SELF_META]]) : {{.*}}, normal [[SUCC_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
181+
try? self.init(failableAndThrows: ())
182+
//
183+
// CHECK: [[SUCC_BB]]
184+
// CHECK-NEXT: inject_enum_addr [[OPT_OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
185+
// CHECK-NEXT: br bb2
186+
//
187+
// CHECK: bb2:
188+
// CHECK-NEXT: [[OPT_RESULT_ADDR:%[0-9]+]] = alloc_stack $Optional<Optional<Wrapped>>
189+
// CHECK-NEXT: switch_enum_addr [[OPT_OPT_RESULT_ADDR]] : {{.*}}, case #Optional.some!enumelt: [[OPT_OPT_SOME_BB:bb[0-9]]], case #Optional.none!enumelt: [[OPT_OPT_NONE_BB:bb[0-9]]]
190+
//
191+
// CHECK: [[OPT_OPT_SOME_BB]]:
192+
// CHECK-NEXT: [[DATA_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr [[OPT_OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
193+
// CHECK-NEXT: copy_addr [[DATA_ADDR]] to [initialization] [[OPT_RESULT_ADDR]]
194+
// CHECK-NEXT: destroy_addr [[DATA_ADDR]]
195+
// CHECK-NEXT: br bb5
196+
//
197+
// CHECK: [[OPT_OPT_NONE_BB]]:
198+
// CHECK-NEXT: inject_enum_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.none!enumelt
199+
// CHECK-NEXT: br bb5
200+
//
201+
// CHECK: bb5:
202+
// CHECK: [[SELECT:%[0-9]+]] = select_enum_addr [[OPT_RESULT_ADDR]]
203+
// CHECK-NEXT: cond_br [[SELECT]], [[OPT_SOME_BB:bb[0-9]]], [[OPT_NONE_BB:bb[0-9]]]
204+
//
205+
// CHECK: [[OPT_NONE_BB]]:
206+
// CHECK-NEXT: destroy_addr [[OPT_RESULT_ADDR]]
207+
// CHECK-NEXT: dealloc_stack [[OPT_RESULT_ADDR]]
208+
// CHECK-NEXT: dealloc_stack [[OPT_OPT_RESULT_ADDR]]
209+
// CHECK-NEXT: br bb8
210+
//
211+
// CHECK: [[OPT_SOME_BB]]:
212+
// CHECK-NEXT: [[RESULT_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr [[OPT_RESULT_ADDR]] : $*Optional<Optional<Wrapped>>, #Optional.some!enumelt
213+
// CHECK-NEXT: copy_addr [take] [[RESULT_ADDR]] to [[PB]]
214+
// CHECK-NEXT: dealloc_stack [[OPT_RESULT_ADDR]]
215+
// CHECK-NEXT: dealloc_stack [[OPT_OPT_RESULT_ADDR]]
216+
// CHECK-NEXT: [[OUT_DATA_ADDR:%[0-9]+]] = init_enum_data_addr [[OUT]] : {{.*}}, #Optional.some!enumelt
217+
// CHECK-NEXT: copy_addr [[PB]] to [initialization] [[OUT_DATA_ADDR]]
218+
// CHECK-NEXT: inject_enum_addr [[OUT]] : {{.*}}, #Optional.some!enumelt
219+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
220+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
221+
// CHECK-NEXT: br bb9
222+
//
223+
// CHECK: bb8:
224+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
225+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
226+
// CHECK-NEXT: inject_enum_addr [[OUT]] : {{.*}}, #Optional.none!enumelt
227+
// CHECK-NEXT: br bb9
228+
//
229+
// CHECK: bb9:
230+
// CHECK-NEXT: [[RET:%[0-9]+]] = tuple ()
231+
// CHECK-NEXT: return [[RET]] : $()
232+
//
233+
// CHECK: bb10([[ERROR:%[0-9]+]] : @owned $Error):
234+
// CHECK-NEXT: destroy_value [[ERROR]]
235+
// CHECK-NEXT: inject_enum_addr [[OPT_OPT_RESULT_ADDR]] : {{.*}}, #Optional.none!enumelt
236+
// CHECK-NEXT: br bb2
237+
//
238+
// CHECK: [[ERROR_BB]]([[ERROR:%[0-9]+]] : @owned $Error):
239+
// CHECK-NEXT: br bb10([[ERROR]] : $Error)
240+
// CHECK-NEXT: }
241+
}
242+
243+
// CHECK-LABEL: sil hidden [ossa] @$sSq24init_delegation_optionalE9failable5xSgSgyt_tcfC
244+
init?(failable5: ()) {
245+
// CHECK: bb0([[OUT:%[0-9]+]] : $*Optional<Optional<Wrapped>>, [[SELF_META:%[0-9]+]] : $@thin Optional<Wrapped>.Type):
246+
// CHECK-NEXT: [[SELF_BOX:%[0-9]+]] = alloc_box $<τ_0_0> { var Optional<τ_0_0> } <Wrapped>, var
247+
// CHECK-NEXT: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
248+
// CHECK-NEXT: [[SELF_LIFETIME:%[0-9]+]] = begin_borrow [lexical] [[MARKED_SELF_BOX]]
249+
// CHECK-NEXT: [[PB:%[0-9]+]] = project_box [[SELF_LIFETIME]]
250+
// CHECK: [[OPT_RESULT_ADDR:%[0-9]+]] = alloc_stack $Optional<Optional<Wrapped>>
251+
// CHECK-NEXT: [[OPT_RESULT_DATA_ADDR:%[0-9]+]] = init_enum_data_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
252+
// CHECK-NEXT: [[TMP_OPT_RESULT_ADDR:%[0-9]+]] = alloc_stack $Optional<Optional<Wrapped>>
253+
// CHECK: [[DELEG_INIT:%[0-9]+]] = function_ref @$sSq24init_delegation_optionalE17failableAndThrowsxSgSgyt_tKcfC
254+
// CHECK-NEXT: try_apply [[DELEG_INIT]]<Wrapped>([[TMP_OPT_RESULT_ADDR]], [[SELF_META]]) : {{.*}}, normal [[SUCC_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
255+
try? self.init(failableAndThrows: ())!
256+
//
257+
// CHECK: [[SUCC_BB]]
258+
// CHECK-NEXT: switch_enum_addr [[TMP_OPT_RESULT_ADDR]] : {{.*}}, case #Optional.some!enumelt: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
259+
//
260+
// CHECK: [[NONE_BB]]:
261+
// CHECK: unreachable
262+
//
263+
// CHECK: [[SOME_BB]]:
264+
// CHECK-NEXT: [[TMP_RESULT_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr [[TMP_OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
265+
// CHECK-NEXT: copy_addr [take] [[TMP_RESULT_ADDR]] to [initialization] [[OPT_RESULT_DATA_ADDR]]
266+
// CHECK-NEXT: inject_enum_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
267+
// CHECK-NEXT: dealloc_stack [[TMP_OPT_RESULT_ADDR]]
268+
// CHECK-NEXT: br bb4
269+
//
270+
// CHECK: bb4:
271+
// CHECK: [[SELECT:%[0-9]+]] = select_enum_addr [[OPT_RESULT_ADDR]]
272+
// CHECK-NEXT: cond_br [[SELECT]], [[SOME_BB:bb[0-9]]], [[NONE_BB:bb[0-9]]]
273+
//
274+
// CHECK: [[NONE_BB]]:
275+
// CHECK-NEXT: destroy_addr [[OPT_RESULT_ADDR]]
276+
// CHECK-NEXT: dealloc_stack [[OPT_RESULT_ADDR]]
277+
// CHECK-NEXT: br bb7
278+
//
279+
// CHECK: [[SOME_BB]]:
280+
// CHECK-NEXT: [[RESULT_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
281+
// CHECK-NEXT: copy_addr [take] [[RESULT_ADDR]] to [[PB]]
282+
// CHECK-NEXT: dealloc_stack [[OPT_RESULT_ADDR]]
283+
// CHECK-NEXT: [[OUT_DATA_ADDR:%[0-9]+]] = init_enum_data_addr [[OUT]] : {{.*}}, #Optional.some!enumelt
284+
// CHECK-NEXT: copy_addr [[PB]] to [initialization] [[OUT_DATA_ADDR]]
285+
// CHECK-NEXT: inject_enum_addr [[OUT]] : {{.*}}, #Optional.some!enumelt
286+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
287+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
288+
// CHECK-NEXT: br bb8
289+
//
290+
// CHECK: bb7:
291+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
292+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
293+
// CHECK-NEXT: inject_enum_addr [[OUT]] : {{.*}}, #Optional.none!enumelt
294+
// CHECK-NEXT: br bb8
295+
//
296+
// CHECK: bb8:
297+
// CHECK-NEXT: [[RET:%[0-9]+]] = tuple ()
298+
// CHECK-NEXT: return [[RET]] : $()
299+
//
300+
// CHECK: bb9([[ERROR:%[0-9]+]] : @owned $Error):
301+
// CHECK-NEXT: destroy_value [[ERROR]]
302+
// CHECK-NEXT: inject_enum_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.none!enumelt
303+
// CHECK-NEXT: br bb4
304+
//
305+
// CHECK: [[ERROR_BB]]([[ERROR:%[0-9]+]] : @owned $Error):
306+
// CHECK-NEXT: dealloc_stack [[TMP_OPT_RESULT_ADDR]]
307+
// CHECK-NEXT: br bb9([[ERROR]] : $Error)
308+
// CHECK-NEXT: }
309+
}
310+
311+
// CHECK-LABEL: sil hidden [ossa] @$sSq24init_delegation_optionalE9failable6xSgSgyt_tcfC
312+
init?(failable6: ()) {
313+
// CHECK: bb0([[OUT:%[0-9]+]] : $*Optional<Optional<Wrapped>>, [[SELF_META:%[0-9]+]] : $@thin Optional<Wrapped>.Type):
314+
// CHECK-NEXT: [[SELF_BOX:%[0-9]+]] = alloc_box $<τ_0_0> { var Optional<τ_0_0> } <Wrapped>, var
315+
// CHECK-NEXT: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
316+
// CHECK-NEXT: [[SELF_LIFETIME:%[0-9]+]] = begin_borrow [lexical] [[MARKED_SELF_BOX]]
317+
// CHECK-NEXT: [[PB:%[0-9]+]] = project_box [[SELF_LIFETIME]]
318+
// CHECK: [[OPT_RESULT_ADDR:%[0-9]+]] = alloc_stack $Optional<Optional<Wrapped>>
319+
// CHECK: [[DELEG_INIT:%[0-9]+]] = function_ref @$sSq24init_delegation_optionalE17failableAndThrowsxSgSgyt_tKcfC
320+
// CHECK-NEXT: try_apply [[DELEG_INIT]]<Wrapped>([[OPT_RESULT_ADDR]], [[SELF_META]]) : {{.*}}, normal [[SUCC_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
321+
try! self.init(failableAndThrows: ())
322+
//
323+
// CHECK: [[SUCC_BB]]
324+
// CHECK: [[SELECT:%[0-9]+]] = select_enum_addr [[OPT_RESULT_ADDR]]
325+
// CHECK-NEXT: cond_br [[SELECT]], [[SOME_BB:bb[0-9]]], [[NONE_BB:bb[0-9]]]
326+
//
327+
// CHECK: [[NONE_BB]]:
328+
// CHECK-NEXT: destroy_addr [[OPT_RESULT_ADDR]]
329+
// CHECK-NEXT: dealloc_stack [[OPT_RESULT_ADDR]]
330+
// CHECK-NEXT: br bb4
331+
//
332+
// CHECK: [[SOME_BB]]:
333+
// CHECK-NEXT: [[RESULT_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr [[OPT_RESULT_ADDR]] : {{.*}}, #Optional.some!enumelt
334+
// CHECK-NEXT: copy_addr [take] [[RESULT_ADDR]] to [[PB]]
335+
// CHECK-NEXT: dealloc_stack [[OPT_RESULT_ADDR]]
336+
// CHECK-NEXT: [[OUT_DATA_ADDR:%[0-9]+]] = init_enum_data_addr [[OUT]] : {{.*}}, #Optional.some!enumelt
337+
// CHECK-NEXT: copy_addr [[PB]] to [initialization] [[OUT_DATA_ADDR]]
338+
// CHECK-NEXT: inject_enum_addr [[OUT]] : {{.*}}, #Optional.some!enumelt
339+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
340+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
341+
// CHECK-NEXT: br bb5
342+
//
343+
// CHECK: bb4:
344+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
345+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
346+
// CHECK-NEXT: inject_enum_addr [[OUT]] : {{.*}}, #Optional.none!enumelt
347+
// CHECK-NEXT: br bb5
348+
//
349+
// CHECK: bb5:
350+
// CHECK-NEXT: [[RET:%[0-9]+]] = tuple ()
351+
// CHECK-NEXT: return [[RET]] : $()
352+
//
353+
// CHECK: bb6({{%[0-9]+}} : @owned $Error):
354+
// CHECK: unreachable
355+
//
356+
// CHECK: [[ERROR_BB]]([[ERROR:%[0-9]+]] : @owned $Error):
357+
// CHECK: br bb6([[ERROR]] : $Error)
358+
// CHECK-NEXT: }
359+
}
99360
}
100361

101362
extension Optional where Wrapped == Optional<Bool> {
@@ -162,4 +423,68 @@ extension Optional where Wrapped == Optional<Bool> {
162423
// CHECK-NEXT: }
163424
self.init(SpecFailable1: ())
164425
}
426+
427+
init?(SpecFailableAndThrows: ()) throws {
428+
self = .none
429+
}
430+
431+
// CHECK_LABEL: sil hidden [ossa] @$sSq24init_delegation_optionalSbSgRszlE13SpecFailable3ABSgSgyt_tcfC
432+
init?(SpecFailable3: ()) {
433+
// CHECK: bb0([[SELF_META:%[0-9]+]] : $@thin Optional<Optional<Bool>>.Type):
434+
// CHECK-NEXT: [[SELF_BOX:%[0-9]+]] = alloc_box ${ var Optional<Optional<Bool>> }, var
435+
// CHECK-NEXT: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [delegatingself] [[SELF_BOX]]
436+
// CHECK-NEXT: [[SELF_LIFETIME:%[0-9]+]] = begin_borrow [lexical] [[MARKED_SELF_BOX]]
437+
// CHECK-NEXT: [[PB:%[0-9]+]] = project_box [[SELF_LIFETIME]]
438+
// CHECK: [[DELEG_INIT:%[0-9]+]] = function_ref @$sSq24init_delegation_optionalSbSgRszlE21SpecFailableAndThrowsABSgSgyt_tKcfC
439+
// CHECK-NEXT: try_apply [[DELEG_INIT]]([[SELF_META]]) : {{.*}}, normal [[SUCC_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]]
440+
//
441+
// CHECK: [[SUCC_BB]]([[OPT_RESULT:%[0-9]+]] : $Optional<Optional<Optional<Bool>>>):
442+
// CHECK-NEXT: [[INJECT_INTO_OPT:%[0-9]+]] = enum $Optional<Optional<Optional<Optional<Bool>>>>, #Optional.some!enumelt, [[OPT_RESULT]]
443+
// CHECK-NEXT: br bb2([[INJECT_INTO_OPT]] : $Optional<Optional<Optional<Optional<Bool>>>>)
444+
//
445+
// CHECK: bb2([[OPT_OPT_RESULT:%[0-9]+]] : $Optional<Optional<Optional<Optional<Bool>>>>):
446+
// CHECK-NEXT: switch_enum [[OPT_OPT_RESULT]] : {{.*}}, case #Optional.some!enumelt: [[OPT_OPT_SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[OPT_OPT_NONE_BB:bb[0-9]+]]
447+
//
448+
// CHECK: [[OPT_OPT_SOME_BB]]([[OPT_RESULT:%[0-9]+]] : $Optional<Optional<Optional<Bool>>>):
449+
// CHECK-NEXT: br bb5([[OPT_RESULT]] : $Optional<Optional<Optional<Bool>>>)
450+
//
451+
// CHECK: [[OPT_OPT_NONE_BB]]:
452+
// CHECK-NEXT: [[NIL:%[0-9]+]] = enum $Optional<Optional<Optional<Bool>>>, #Optional.none!enumelt
453+
// CHECK-NEXT: br bb5([[NIL]] : $Optional<Optional<Optional<Bool>>>)
454+
//
455+
// CHECK: bb5([[OPT_RESULT:%[0-9]+]] : $Optional<Optional<Optional<Bool>>>):
456+
// CHECK: [[SELECT:%[0-9]+]] = select_enum [[OPT_RESULT]]
457+
// CHECK-NEXT: cond_br [[SELECT]], [[OPT_SOME_BB:bb[0-9]+]], [[OPT_NONE_BB:bb[0-9]+]]
458+
//
459+
// CHECK: [[OPT_NONE_BB]]:
460+
// CHECK-NEXT: br bb8
461+
//
462+
// CHECK: [[OPT_SOME_BB]]:
463+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = unchecked_enum_data [[OPT_RESULT]] : {{.*}}, #Optional.some!enumelt
464+
// CHECK-NEXT: assign [[RESULT]] to [[PB]]
465+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = load [trivial] [[PB]]
466+
// CHECK-NEXT: [[INJECT_INTO_OPT:%[0-9]+]] = enum $Optional<Optional<Optional<Bool>>>, #Optional.some!enumelt, [[RESULT]]
467+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
468+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
469+
// CHECK-NEXT: br bb9([[INJECT_INTO_OPT]] : $Optional<Optional<Optional<Bool>>>)
470+
//
471+
// CHECK: bb8:
472+
// CHECK-NEXT: end_borrow [[SELF_LIFETIME]]
473+
// CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]]
474+
// CHECK-NEXT: [[NIL:%[0-9]+]] = enum $Optional<Optional<Optional<Bool>>>, #Optional.none!enumelt
475+
// CHECK-NEXT: br bb9([[NIL]] : $Optional<Optional<Optional<Bool>>>)
476+
//
477+
// CHECK: bb9([[RET:%[0-9]+]] : $Optional<Optional<Optional<Bool>>>):
478+
// CHECK-NEXT: return [[RET]]
479+
//
480+
// CHECK: bb10([[ERROR:%[0-9]+]] : @owned $Error):
481+
// CHECK-NEXT: destroy_value [[ERROR]]
482+
// CHECK-NEXT: [[NIL:%[0-9]+]] = enum $Optional<Optional<Optional<Optional<Bool>>>>, #Optional.none!enumelt
483+
// CHECK-NEXT: br bb2([[NIL]] : $Optional<Optional<Optional<Optional<Bool>>>>)
484+
//
485+
// CHECK: [[ERROR_BB]]([[ERROR:%[0-9]+]] : @owned $Error):
486+
// CHECK-NEXT: br bb10([[ERROR]] : $Error)
487+
// CHECK-NEXT: }
488+
try? self.init(SpecFailableAndThrows: ())
489+
}
165490
}

0 commit comments

Comments
 (0)