Skip to content

Commit f592b5c

Browse files
committed
[Parse] Recover slightly better from bad shorthand if let
Instead of assuming that `if let <expr>` is meant to be `if case <expr> = ...`, turn it into `if let _ = <expr>`, which is consistent with the fix-it we suggest. This currently doesn't have much of an effect on the diagnostics we produce, but will be important once we start doing bidirectional inference for ExprPatterns, as it avoids unhelpful diagnostics.
1 parent 9b55e39 commit f592b5c

File tree

2 files changed

+22
-3
lines changed

2 files changed

+22
-3
lines changed

lib/Parse/ParseStmt.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,16 @@ Parser::parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
17251725
auto diagLoc = ThePattern.get()->getSemanticsProvidingPattern()->getStartLoc();
17261726
diagnose(diagLoc, diag::conditional_var_valid_identifiers_only)
17271727
.fixItInsert(diagLoc, "<#identifier#> = ");
1728+
1729+
// For better recovery, assume the expression pattern as the initializer,
1730+
// and synthesize an optional AnyPattern.
1731+
auto *semanticPattern = ThePattern.get()->getSemanticsProvidingPattern();
1732+
if (auto *EP = dyn_cast<ExprPattern>(semanticPattern)) {
1733+
Init = makeParserResult(EP->getSubExpr());
1734+
auto *AP = AnyPattern::createImplicit(Context);
1735+
ThePattern =
1736+
makeParserResult(OptionalSomePattern::createImplicit(Context, AP));
1737+
}
17281738
} else {
17291739
diagnose(Tok, diag::conditional_var_initializer_required);
17301740
}

test/stmt/if_while_var.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,13 @@ if var nonOptional { nonOptional = nonOptionalStruct(); _ = nonOptional } // exp
4242
guard let nonOptional else { _ = nonOptional; fatalError() } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalStruct'}}
4343
guard var nonOptional else { _ = nonOptional; fatalError() } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalStruct'}}
4444

45-
if let nonOptional.property { } // expected-error{{unwrap condition requires a valid identifier}} expected-error{{pattern matching in a condition requires the 'case' keyword}}
46-
if var nonOptional.property { } // expected-error{{unwrap condition requires a valid identifier}} expected-error{{pattern matching in a condition requires the 'case' keyword}}
45+
if let nonOptional.property { }
46+
// expected-error@-1 {{unwrap condition requires a valid identifier}}
47+
// expected-error@-2 {{initializer for conditional binding must have Optional type, not 'Any'}}
48+
49+
if var nonOptional.property { }
50+
// expected-error@-1 {{unwrap condition requires a valid identifier}}
51+
// expected-error@-2 {{initializer for conditional binding must have Optional type, not 'Any'}}
4752

4853
guard let _ = nonOptionalStruct() else { fatalError() } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalStruct'}}
4954
guard let _ = nonOptionalEnum() else { fatalError() } // expected-error{{initializer for conditional binding must have Optional type, not 'NonOptionalEnum'}}
@@ -65,7 +70,11 @@ class B {} // expected-note * {{did you mean 'B'?}}
6570
class D : B {}// expected-note * {{did you mean 'D'?}}
6671

6772
// TODO poor recovery in these cases
68-
if let {} // expected-error {{expected '{' after 'if' condition}} expected-error {{pattern matching in a condition requires the 'case' keyword}} expected-error {{unwrap condition requires a valid identifier}}
73+
if let {}
74+
// expected-error@-1 {{expected '{' after 'if' condition}}
75+
// expected-error@-2 {{unwrap condition requires a valid identifier}}
76+
// expected-error@-3 {{initializer for conditional binding must have Optional type, not '() -> ()'}}
77+
6978
if let x = { } // expected-error{{'{' after 'if'}} expected-error{{initializer for conditional binding must have Optional type, not '() -> ()'}}
7079
// expected-warning@-1{{value 'x' was defined but never used}}
7180

0 commit comments

Comments
 (0)