Skip to content

Commit 7011f32

Browse files
authored
Merge pull request #22486 from theblixguy/fix/SR-7799
[Typechecker] Allow matching an enum case against an optional enum without '?'
2 parents dc89cc0 + 0bd6ca9 commit 7011f32

File tree

3 files changed

+74
-15
lines changed

3 files changed

+74
-15
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,19 +1388,26 @@ bool TypeChecker::coercePatternToType(Pattern *&P, TypeResolution resolution,
13881388
goto recur;
13891389
}
13901390

1391-
auto diag = diagnose(EEP->getLoc(),
1392-
diag::enum_element_pattern_member_not_found,
1393-
EEP->getName().str(), type);
1394-
1395-
// If we have an optional type let's try to see if the case
1396-
// exists in its base type, if so we can suggest a fix-it for that.
1391+
// If we have an optional type, let's try to see if the case
1392+
// exists in its base type and if it does then synthesize an
1393+
// OptionalSomePattern that wraps the case. This uses recursion
1394+
// to add multiple levels of OptionalSomePattern if the optional
1395+
// is nested.
13971396
if (auto baseType = type->getOptionalObjectType()) {
1398-
if (lookupEnumMemberElement(*this, dc, baseType, EEP->getName(),
1399-
EEP->getLoc()))
1400-
diag.fixItInsertAfter(EEP->getEndLoc(), "?");
1397+
if (lookupEnumMemberElement(*this, dc,
1398+
baseType->lookThroughAllOptionalTypes(),
1399+
EEP->getName(), EEP->getLoc())) {
1400+
P = new (Context)
1401+
OptionalSomePattern(EEP, EEP->getEndLoc(), /*implicit*/true);
1402+
return coercePatternToType(P, resolution, type, options);
1403+
} else {
1404+
diagnose(EEP->getLoc(),
1405+
diag::enum_element_pattern_member_not_found,
1406+
EEP->getName().str(), type);
1407+
return true;
1408+
}
14011409
}
14021410
}
1403-
return true;
14041411
}
14051412
enumTy = type;
14061413
} else {

test/Constraints/patterns.swift

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ enum SR2057 {
254254
}
255255

256256
let sr2057: SR2057?
257-
if case .foo = sr2057 { } // expected-error{{enum case 'foo' not found in type 'SR2057?'}}
257+
if case .foo = sr2057 { } // Ok
258258

259259

260260
// Invalid 'is' pattern
@@ -332,10 +332,10 @@ struct S_32241441 {
332332
func rdar32241441() {
333333
let s: S_32241441? = S_32241441()
334334

335-
switch s?.type {
336-
case .foo: // expected-error {{enum case 'foo' not found in type 'S_32241441.E_32241441?'}} {{12-12=?}}
335+
switch s?.type { // expected-error {{switch must be exhaustive}} expected-note {{add missing case: '.none'}}
336+
case .foo: // Ok
337337
break;
338-
case .bar: // expected-error {{enum case 'bar' not found in type 'S_32241441.E_32241441?'}} {{12-12=?}}
338+
case .bar: // Ok
339339
break;
340340
}
341341
}
@@ -408,4 +408,26 @@ func test8347() -> String {
408408
}
409409
}
410410

411+
enum SR_7799 {
412+
case baz
413+
case bar
414+
}
415+
416+
let sr7799: SR_7799? = .bar
417+
418+
switch sr7799 {
419+
case .bar?: break // Ok
420+
case .baz: break // Ok
421+
default: break
422+
}
423+
424+
let sr7799_1: SR_7799?? = .baz
425+
426+
switch sr7799_1 {
427+
case .bar?: break // Ok
428+
case .baz: break // Ok
429+
default: break
430+
}
411431

432+
if case .baz = sr7799_1 {} // Ok
433+
if case .bar? = sr7799_1 {} // Ok

test/SILGen/enum.swift

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,4 +238,34 @@ func useTrailingClosureGeneric<T>(t: T) {
238238
_ = TrailingClosureGeneric<T>.noLabel { t }
239239
_ = TrailingClosureGeneric<T>.twoElementsLabel(x: t) { t }
240240
_ = TrailingClosureGeneric<T>.twoElementsNoLabel(t) { t }
241-
}
241+
}
242+
243+
enum SR7799 {
244+
case one
245+
case two
246+
}
247+
248+
// CHECK-LABEL: sil hidden [ossa] @$s4enum6sr77993baryAA6SR7799OSg_tF : $@convention(thin) (Optional<SR7799>) -> () {
249+
// CHECK: bb0(%0 : $Optional<SR7799>):
250+
// CHECK-NEXT: debug_value %0 : $Optional<SR7799>, let, name "bar", argno 1
251+
// CHECK-NEXT: switch_enum %0 : $Optional<SR7799>, case #Optional.some!enumelt.1: bb1, default bb4
252+
// CHECK: bb1(%3 : $SR7799):
253+
// CHECK-NEXT: switch_enum %3 : $SR7799, case #SR7799.one!enumelt: bb2, case #SR7799.two!enumelt: bb3
254+
func sr7799(bar: SR7799?) {
255+
switch bar {
256+
case .one: print("one")
257+
case .two?: print("two")
258+
default: print("default")
259+
}
260+
}
261+
262+
// CHECK-LABEL: sil hidden [ossa] @$s4enum8sr7799_13baryAA6SR7799OSgSg_tF : $@convention(thin) (Optional<Optional<SR7799>>) -> () {
263+
// CHECK: bb0(%0 : $Optional<Optional<SR7799>>):
264+
// CHECK-NEXT: debug_value %0 : $Optional<Optional<SR7799>>, let, name "bar", argno 1
265+
// CHECK-NEXT: switch_enum %0 : $Optional<Optional<SR7799>>, case #Optional.none!enumelt: bb1, default bb2
266+
func sr7799_1(bar: SR7799??) {
267+
switch bar {
268+
case .none: print("none")
269+
default: print("default")
270+
}
271+
}

0 commit comments

Comments
 (0)