Skip to content

Commit ea516bc

Browse files
authored
Merge pull request swiftlang#31760 from CodaFi/patternak
Remove The Parser Hack For If-Let
2 parents d8f5b20 + ea2084e commit ea516bc

File tree

9 files changed

+31
-38
lines changed

9 files changed

+31
-38
lines changed

include/swift/Parse/Parser.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,8 +1359,7 @@ class Parser {
13591359
ParserResult<Pattern> parsePatternTuple();
13601360

13611361
ParserResult<Pattern>
1362-
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P,
1363-
bool isOptional);
1362+
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P);
13641363
ParserResult<Pattern> parseMatchingPattern(bool isExprBasic);
13651364
ParserResult<Pattern> parseMatchingPatternAsLetOrVar(bool isLet,
13661365
SourceLoc VarLoc,

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2613,18 +2613,10 @@ void PrintAST::visitVarDecl(VarDecl *decl) {
26132613
Printer << ": ";
26142614
TypeLoc tyLoc;
26152615
if (auto *repr = decl->getTypeReprOrParentPatternTypeRepr()) {
2616-
// Workaround for if-let statements. The parser creates a `OptionalTypeRepr`
2617-
// even though the user-written declared type for the if-let variable
2618-
// is non-optional. Get the non-optional type so we can print it correctly.
2619-
if (auto *optRepr = dyn_cast<OptionalTypeRepr>(repr)) {
2620-
if (type && !isa<OptionalType>(type.getPointer())) {
2621-
repr = optRepr->getBase();
2622-
}
2623-
}
26242616
tyLoc = TypeLoc(repr, type);
2625-
} else
2617+
} else {
26262618
tyLoc = TypeLoc::withoutLoc(type);
2627-
2619+
}
26282620
Printer.printDeclResultTypePre(decl, tyLoc);
26292621

26302622
// HACK: When printing result types for vars with opaque result types,

lib/Parse/ParsePattern.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,8 +1124,7 @@ ParserResult<Pattern> Parser::parsePatternTuple() {
11241124
/// pattern-type-annotation ::= (':' type)?
11251125
///
11261126
ParserResult<Pattern> Parser::
1127-
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
1128-
bool isOptional) {
1127+
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result) {
11291128
if (!Tok.is(tok::colon))
11301129
return result;
11311130

@@ -1152,15 +1151,6 @@ parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
11521151
if (!repr)
11531152
repr = new (Context) ErrorTypeRepr(PreviousLoc);
11541153

1155-
// In an if-let, the actual type of the expression is Optional of whatever
1156-
// was written.
1157-
// FIXME: This is not good, `TypeRepr`s are supposed to represent what the
1158-
// user actually wrote in source (that's why they don't have any `isImplicit`
1159-
// bit). This synthesized `OptionalTypeRepr` leads to workarounds in other
1160-
// parts where we want to reason about the types as perceived by the user.
1161-
if (isOptional)
1162-
repr = new (Context) OptionalTypeRepr(repr, SourceLoc());
1163-
11641154
return makeParserResult(status, new (Context) TypedPattern(P, repr));
11651155
}
11661156

lib/Parse/ParseStmt.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,8 +1502,7 @@ Parser::parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
15021502
P->setImplicit();
15031503
}
15041504

1505-
ThePattern = parseOptionalPatternTypeAnnotation(ThePattern,
1506-
BindingKindStr != "case");
1505+
ThePattern = parseOptionalPatternTypeAnnotation(ThePattern);
15071506
if (ThePattern.hasCodeCompletion())
15081507
Status.setHasCodeCompletion();
15091508

@@ -2123,7 +2122,7 @@ ParserResult<Stmt> Parser::parseStmtForEach(LabeledStmtInfo LabelInfo) {
21232122
llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
21242123
T(InVarOrLetPattern, Parser::IVOLP_InMatchingPattern);
21252124
pattern = parseMatchingPattern(/*isExprBasic*/true);
2126-
pattern = parseOptionalPatternTypeAnnotation(pattern, /*isOptional*/false);
2125+
pattern = parseOptionalPatternTypeAnnotation(pattern);
21272126
} else if (!IsCStyleFor || Tok.is(tok::kw_var)) {
21282127
// Change the parser state to know that the pattern we're about to parse is
21292128
// implicitly mutable. Bound variables can be changed to mutable explicitly

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4284,7 +4284,7 @@ SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
42844284
bool bindPatternVarsOneWay) {
42854285
// Determine the contextual type for the initialization.
42864286
TypeLoc contextualType;
4287-
if (!isa<OptionalSomePattern>(pattern) &&
4287+
if (!(isa<OptionalSomePattern>(pattern) && !pattern->isImplicit()) &&
42884288
patternType && !patternType->isHole()) {
42894289
contextualType = TypeLoc::withoutLoc(patternType);
42904290

lib/Sema/ConstraintSystem.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1444,7 +1444,8 @@ class SolutionApplicationTarget {
14441444
bool isOptionalSomePatternInit() const {
14451445
return kind == Kind::expression &&
14461446
expression.contextualPurpose == CTP_Initialization &&
1447-
isa<OptionalSomePattern>(expression.pattern);
1447+
isa<OptionalSomePattern>(expression.pattern) &&
1448+
!expression.pattern->isImplicit();
14481449
}
14491450

14501451
/// Whether to bind the types of any variables within the pattern via

lib/Sema/MiscDiagnostics.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3752,10 +3752,9 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
37523752
// checking for a type, which forced it to be promoted to a double optional
37533753
// type.
37543754
if (auto ooType = subExpr->getType()->getOptionalObjectType()) {
3755-
if (auto TP = dyn_cast<TypedPattern>(p))
3755+
if (auto OSP = dyn_cast<OptionalSomePattern>(p)) {
37563756
// Check for 'if let' to produce a tuned diagnostic.
3757-
if (isa<OptionalSomePattern>(TP->getSubPattern()) &&
3758-
TP->getSubPattern()->isImplicit()) {
3757+
if (auto *TP = dyn_cast<TypedPattern>(OSP->getSubPattern())) {
37593758
ctx.Diags.diagnose(cond.getIntroducerLoc(),
37603759
diag::optional_check_promotion,
37613760
subExpr->getType())
@@ -3764,6 +3763,7 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
37643763
ooType->getString());
37653764
return;
37663765
}
3766+
}
37673767
ctx.Diags.diagnose(cond.getIntroducerLoc(),
37683768
diag::optional_pattern_match_promotion,
37693769
subExpr->getType(), cond.getInitializer()->getType())

lib/Sema/TypeCheckPattern.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -655,12 +655,8 @@ Pattern *TypeChecker::resolvePattern(Pattern *P, DeclContext *DC,
655655

656656
// "if let" implicitly looks inside of an optional, so wrap it in an
657657
// OptionalSome pattern.
658-
InnerP = new (Context) OptionalSomePattern(InnerP, InnerP->getEndLoc());
659-
InnerP->setImplicit();
660-
if (auto *TP = dyn_cast<TypedPattern>(P))
661-
TP->setSubPattern(InnerP);
662-
else
663-
P = InnerP;
658+
P = new (Context) OptionalSomePattern(P, P->getEndLoc());
659+
P->setImplicit();
664660
}
665661

666662
return P;
@@ -811,9 +807,24 @@ Type PatternTypeRequest::evaluate(Evaluator &evaluator,
811807
//
812808
// Refutable patterns occur when checking the PatternBindingDecls in if/let,
813809
// while/let, and let/else conditions.
810+
case PatternKind::OptionalSome: {
811+
// Annotated if-let patterns are rewritten by TypeChecker::resolvePattern
812+
// to have an enclosing implicit (...)? pattern. If we can resolve the inner
813+
// typed pattern, the resulting pattern must have optional type.
814+
auto somePat = cast<OptionalSomePattern>(P);
815+
if (somePat->isImplicit() && isa<TypedPattern>(somePat->getSubPattern())) {
816+
auto resolution = TypeResolution::forContextual(dc, options);
817+
TypedPattern *TP = cast<TypedPattern>(somePat->getSubPattern());
818+
auto type = validateTypedPattern(resolution, TP, options);
819+
if (type && !type->hasError()) {
820+
return OptionalType::get(type);
821+
}
822+
}
823+
LLVM_FALLTHROUGH;
824+
}
825+
814826
case PatternKind::Is:
815827
case PatternKind::EnumElement:
816-
case PatternKind::OptionalSome:
817828
case PatternKind::Bool:
818829
case PatternKind::Expr:
819830
// In a let/else, these always require an initial value to match against.

test/stmt/statements.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ func testThrowNil() throws {
556556
// condition may have contained a SequenceExpr.
557557
func r23684220(_ b: Any) {
558558
if let _ = b ?? b {} // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'Any', so the right side is never used}}
559+
// expected-error@-1 {{initializer for conditional binding must have Optional type, not 'Any'}}
559560
}
560561

561562

0 commit comments

Comments
 (0)