Skip to content

Commit ae1ca94

Browse files
authored
Merge pull request #41815 from CodaFi/switch-hitter
2 parents 8eb762e + fe6cefc commit ae1ca94

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,10 +1269,10 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
12691269
case PatternKind::Expr: {
12701270
assert(cast<ExprPattern>(P)->isResolved()
12711271
&& "coercing unresolved expr pattern!");
1272+
auto *EP = cast<ExprPattern>(P);
12721273
if (type->isBool()) {
12731274
// The type is Bool.
12741275
// Check if the pattern is a Bool literal
1275-
auto EP = cast<ExprPattern>(P);
12761276
if (auto *BLE = dyn_cast<BooleanLiteralExpr>(
12771277
EP->getSubExpr()->getSemanticsProvidingExpr())) {
12781278
P = new (Context) BoolPattern(BLE->getLoc(), BLE->getValue());
@@ -1282,20 +1282,27 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
12821282
}
12831283

12841284
// case nil is equivalent to .none when switching on Optionals.
1285-
if (type->getOptionalObjectType()) {
1286-
auto EP = cast<ExprPattern>(P);
1287-
if (auto *NLE = dyn_cast<NilLiteralExpr>(EP->getSubExpr())) {
1285+
if (auto *NLE = dyn_cast<NilLiteralExpr>(EP->getSubExpr())) {
1286+
if (type->getOptionalObjectType()) {
12881287
auto *NoneEnumElement = Context.getOptionalNoneDecl();
12891288
auto *BaseTE = TypeExpr::createImplicit(type, Context);
12901289
P = new (Context) EnumElementPattern(
12911290
BaseTE, NLE->getLoc(), DeclNameLoc(NLE->getLoc()),
12921291
NoneEnumElement->createNameRef(), NoneEnumElement, nullptr);
12931292
return TypeChecker::coercePatternToType(
12941293
pattern.forSubPattern(P, /*retainTopLevel=*/true), type, options);
1294+
} else {
1295+
// ...but for non-optional types it can never match! Diagnose it.
1296+
diags.diagnose(NLE->getLoc(),
1297+
diag::value_type_comparison_with_nil_illegal, type)
1298+
.warnUntilSwiftVersion(6);
1299+
1300+
if (type->getASTContext().isSwiftVersionAtLeast(6))
1301+
return nullptr;
12951302
}
12961303
}
12971304

1298-
if (TypeChecker::typeCheckExprPattern(cast<ExprPattern>(P), dc, type))
1305+
if (TypeChecker::typeCheckExprPattern(EP, dc, type))
12991306
return nullptr;
13001307

13011308
return P;

test/Constraints/result_builder_diags.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,3 +811,30 @@ func test_redeclations() {
811811
let (foo, foo) = (5, 6) // expected-error {{invalid redeclaration of 'foo'}} expected-note {{'foo' previously declared here}}
812812
}
813813
}
814+
815+
func test_rdar89742267() {
816+
@resultBuilder
817+
struct Builder {
818+
static func buildBlock<T>(_ t: T) -> T { t }
819+
static func buildEither<T>(first: T) -> T { first }
820+
static func buildEither<T>(second: T) -> T { second }
821+
}
822+
823+
struct S {}
824+
825+
enum Hey {
826+
case listen
827+
}
828+
829+
struct MyView {
830+
var entry: Hey
831+
832+
@Builder var body: S {
833+
switch entry {
834+
case .listen: S()
835+
case nil: S() // expected-warning {{type 'Hey' is not optional, value can never be nil; this is an error in Swift 6}}
836+
default: S()
837+
}
838+
}
839+
}
840+
}

test/stmt/switch_nil.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
enum Hey {
4+
case listen
5+
}
6+
7+
func test() {
8+
switch Hey.listen {
9+
case nil: // expected-warning {{type 'Hey' is not optional, value can never be nil}}
10+
break
11+
default:
12+
break
13+
}
14+
}

0 commit comments

Comments
 (0)