Skip to content

Commit d74b97c

Browse files
authored
Merge pull request #4445 from jtbandes/diagnose-optional
[QoI] fix diagnosis of non-Optional enum used in optional pattern
2 parents aa485e8 + 14dc422 commit d74b97c

File tree

3 files changed

+20
-71
lines changed

3 files changed

+20
-71
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,8 +1455,10 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
14551455

14561456
case PatternKind::OptionalSome: {
14571457
auto *OP = cast<OptionalSomePattern>(P);
1458-
auto *enumDecl = type->getEnumOrBoundGenericEnum();
1459-
if (!enumDecl) {
1458+
OptionalTypeKind optionalKind;
1459+
Type elementType = type->getAnyOptionalObjectType(optionalKind);
1460+
1461+
if (elementType.isNull()) {
14601462
auto diagID = diag::optional_element_pattern_not_valid_type;
14611463
SourceLoc loc = OP->getQuestionLoc();
14621464
// Produce tailored diagnostic for if/let and other conditions.
@@ -1469,35 +1471,10 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
14691471
return true;
14701472
}
14711473

1472-
// If the element decl was not resolved (because it was spelled without a
1473-
// type as `.Foo`), resolve it now that we have a type.
1474-
if (!OP->getElementDecl()) {
1475-
auto *element = lookupEnumMemberElement(*this, dc, type, Context.Id_some,
1476-
OP->getLoc());
1477-
if (!element) {
1478-
diagnose(OP->getLoc(), diag::enum_element_pattern_member_not_found,
1479-
"Some", type);
1480-
return true;
1481-
}
1482-
OP->setElementDecl(element);
1483-
}
1484-
1485-
EnumElementDecl *elt = OP->getElementDecl();
1486-
// Is the enum element actually part of the enum type we're matching?
1487-
if (elt->getParentEnum() != enumDecl) {
1488-
diagnose(OP->getLoc(), diag::enum_element_pattern_not_member_of_enum,
1489-
"Some", type);
1490-
return true;
1491-
}
1474+
EnumElementDecl *elementDecl = Context.getOptionalSomeDecl(optionalKind);
1475+
assert(elementDecl && "missing optional some decl?!");
1476+
OP->setElementDecl(elementDecl);
14921477

1493-
// Check the subpattern & push the enum element type down onto it.
1494-
Type elementType;
1495-
if (elt->hasArgumentType())
1496-
elementType = type->getTypeOfMember(elt->getModuleContext(),
1497-
elt, this,
1498-
elt->getArgumentInterfaceType());
1499-
else
1500-
elementType = TupleType::getEmpty(Context);
15011478
Pattern *sub = OP->getSubPattern();
15021479
if (coercePatternToType(sub, dc, elementType,
15031480
subOptions|TR_FromNonInferredPattern|TR_EnumPatternPayload,

test/SILGen/statements.swift

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -591,45 +591,6 @@ func testRequireOptional2(_ a : String?) -> String {
591591
return t
592592
}
593593

594-
enum MyOptional<Wrapped> {
595-
case none
596-
case some(Wrapped)
597-
}
598-
599-
// CHECK-LABEL: sil hidden @_TF10statements28testAddressOnlyEnumInRequire
600-
// CHECK: bb0(%0 : $*T, %1 : $*MyOptional<T>):
601-
// CHECK-NEXT: debug_value_addr %1 : $*MyOptional<T>, let, name "a"
602-
// CHECK-NEXT: %3 = alloc_stack $T, let, name "t"
603-
// CHECK-NEXT: %4 = alloc_stack $MyOptional<T>
604-
// CHECK-NEXT: copy_addr %1 to [initialization] %4 : $*MyOptional<T>
605-
// CHECK-NEXT: switch_enum_addr %4 : $*MyOptional<T>, case #MyOptional.some!enumelt.1: bb2, default bb1
606-
func testAddressOnlyEnumInRequire<T>(_ a: MyOptional<T>) -> T {
607-
// CHECK: bb1:
608-
// CHECK-NEXT: dealloc_stack %4
609-
// CHECK-NEXT: dealloc_stack %3
610-
// CHECK-NEXT: br bb3
611-
guard let t = a else { abort() }
612-
613-
// CHECK: bb2:
614-
// CHECK-NEXT: %10 = unchecked_take_enum_data_addr %4 : $*MyOptional<T>, #MyOptional.some!enumelt.1
615-
// CHECK-NEXT: copy_addr [take] %10 to [initialization] %3 : $*T
616-
// CHECK-NEXT: dealloc_stack %4
617-
// CHECK-NEXT: copy_addr [take] %3 to [initialization] %0 : $*T
618-
// CHECK-NEXT: dealloc_stack %3
619-
// CHECK-NEXT: destroy_addr %1 : $*MyOptional<T>
620-
// CHECK-NEXT: tuple ()
621-
// CHECK-NEXT: return
622-
623-
// CHECK: bb3:
624-
// CHECK-NEXT: // function_ref statements.abort () -> Swift.Never
625-
// CHECK-NEXT: %18 = function_ref @_TF10statements5abortFT_Os5Never
626-
// CHECK-NEXT: %19 = apply %18() : $@convention(thin) () -> Never
627-
// CHECK-NEXT: unreachable
628-
629-
return t
630-
}
631-
632-
633594

634595
// CHECK-LABEL: sil hidden @_TF10statements19testCleanupEmission
635596
// <rdar://problem/20563234> let-else problem: cleanups for bound patterns shouldn't be run in the else block

test/stmt/if_while_var.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
// RUN: %target-parse-verify-swift
22

3+
struct NonOptionalStruct {}
4+
enum NonOptionalEnum { case foo }
5+
36
func foo() -> Int? { return .none }
4-
func nonOptional() -> Int { return 0 }
7+
func nonOptionalStruct() -> NonOptionalStruct { fatalError() }
8+
func nonOptionalEnum() -> NonOptionalEnum { fatalError() }
59
func use(_ x: Int) {}
610
func modify(_ x: inout Int) {}
711

@@ -19,7 +23,14 @@ if var x = foo() {
1923

2024
use(x) // expected-error{{unresolved identifier 'x'}}
2125

22-
if let x = nonOptional() { } // expected-error{{initializer for conditional binding must have Optional type, not 'Int'}}
26+
if let x = nonOptionalStruct() { } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalStruct'}}
27+
if let x = nonOptionalEnum() { } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalEnum'}}
28+
29+
guard let _ = nonOptionalStruct() else { fatalError() } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalStruct'}}
30+
guard let _ = nonOptionalEnum() else { fatalError() } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalEnum'}}
31+
32+
if case let x? = nonOptionalStruct() { } // expected-error{{'?' pattern cannot match values of type 'NonOptionalStruct'}}
33+
if case let x? = nonOptionalEnum() { } // expected-error{{'?' pattern cannot match values of type 'NonOptionalEnum'}}
2334

2435
class B {} // expected-note * {{did you mean 'B'?}}
2536
class D : B {}// expected-note * {{did you mean 'D'?}}

0 commit comments

Comments
 (0)