Skip to content

Commit 7e770fd

Browse files
authored
Merge pull request swiftlang#33744 from CodaFi/options-contracts
[5.3] Remove The Parser Hack For If-Let
2 parents d716ba9 + e773dd2 commit 7e770fd

File tree

9 files changed

+31
-38
lines changed

9 files changed

+31
-38
lines changed

include/swift/Parse/Parser.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -1357,8 +1357,7 @@ class Parser {
13571357
ParserResult<Pattern> parsePatternTuple();
13581358

13591359
ParserResult<Pattern>
1360-
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P,
1361-
bool isOptional);
1360+
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P);
13621361
ParserResult<Pattern> parseMatchingPattern(bool isExprBasic);
13631362
ParserResult<Pattern> parseMatchingPatternAsLetOrVar(bool isLet,
13641363
SourceLoc VarLoc,

lib/AST/ASTPrinter.cpp

+2-10
Original file line numberDiff line numberDiff line change
@@ -2642,18 +2642,10 @@ void PrintAST::visitVarDecl(VarDecl *decl) {
26422642
Printer << ": ";
26432643
TypeLoc tyLoc;
26442644
if (auto *repr = decl->getTypeReprOrParentPatternTypeRepr()) {
2645-
// Workaround for if-let statements. The parser creates a `OptionalTypeRepr`
2646-
// even though the user-written declared type for the if-let variable
2647-
// is non-optional. Get the non-optional type so we can print it correctly.
2648-
if (auto *optRepr = dyn_cast<OptionalTypeRepr>(repr)) {
2649-
if (type && !isa<OptionalType>(type.getPointer())) {
2650-
repr = optRepr->getBase();
2651-
}
2652-
}
26532645
tyLoc = TypeLoc(repr, type);
2654-
} else
2646+
} else {
26552647
tyLoc = TypeLoc::withoutLoc(type);
2656-
2648+
}
26572649
Printer.printDeclResultTypePre(decl, tyLoc);
26582650

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

lib/Parse/ParsePattern.cpp

+1-11
Original file line numberDiff line numberDiff line change
@@ -1110,8 +1110,7 @@ ParserResult<Pattern> Parser::parsePatternTuple() {
11101110
/// pattern-type-annotation ::= (':' type)?
11111111
///
11121112
ParserResult<Pattern> Parser::
1113-
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
1114-
bool isOptional) {
1113+
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result) {
11151114
if (!Tok.is(tok::colon))
11161115
return result;
11171116

@@ -1138,15 +1137,6 @@ parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
11381137
if (!repr)
11391138
repr = new (Context) ErrorTypeRepr(PreviousLoc);
11401139

1141-
// In an if-let, the actual type of the expression is Optional of whatever
1142-
// was written.
1143-
// FIXME: This is not good, `TypeRepr`s are supposed to represent what the
1144-
// user actually wrote in source (that's why they don't have any `isImplicit`
1145-
// bit). This synthesized `OptionalTypeRepr` leads to workarounds in other
1146-
// parts where we want to reason about the types as perceived by the user.
1147-
if (isOptional)
1148-
repr = new (Context) OptionalTypeRepr(repr, SourceLoc());
1149-
11501140
return makeParserResult(status, new (Context) TypedPattern(P, repr));
11511141
}
11521142

lib/Parse/ParseStmt.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -1498,8 +1498,7 @@ Parser::parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
14981498
P->setImplicit();
14991499
}
15001500

1501-
ThePattern = parseOptionalPatternTypeAnnotation(ThePattern,
1502-
BindingKindStr != "case");
1501+
ThePattern = parseOptionalPatternTypeAnnotation(ThePattern);
15031502
if (ThePattern.hasCodeCompletion()) {
15041503
Status.setHasCodeCompletion();
15051504

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

lib/Sema/ConstraintSystem.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -4295,7 +4295,7 @@ SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
42954295
bool bindPatternVarsOneWay) {
42964296
// Determine the contextual type for the initialization.
42974297
TypeLoc contextualType;
4298-
if (!isa<OptionalSomePattern>(pattern) &&
4298+
if (!(isa<OptionalSomePattern>(pattern) && !pattern->isImplicit()) &&
42994299
patternType && !patternType->isHole()) {
43004300
contextualType = TypeLoc::withoutLoc(patternType);
43014301

lib/Sema/ConstraintSystem.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -1455,7 +1455,8 @@ class SolutionApplicationTarget {
14551455
bool isOptionalSomePatternInit() const {
14561456
return kind == Kind::expression &&
14571457
expression.contextualPurpose == CTP_Initialization &&
1458-
isa<OptionalSomePattern>(expression.pattern);
1458+
isa<OptionalSomePattern>(expression.pattern) &&
1459+
!expression.pattern->isImplicit();
14591460
}
14601461

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

lib/Sema/MiscDiagnostics.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -3791,10 +3791,9 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
37913791
// checking for a type, which forced it to be promoted to a double optional
37923792
// type.
37933793
if (auto ooType = subExpr->getType()->getOptionalObjectType()) {
3794-
if (auto TP = dyn_cast<TypedPattern>(p))
3794+
if (auto OSP = dyn_cast<OptionalSomePattern>(p)) {
37953795
// Check for 'if let' to produce a tuned diagnostic.
3796-
if (isa<OptionalSomePattern>(TP->getSubPattern()) &&
3797-
TP->getSubPattern()->isImplicit()) {
3796+
if (auto *TP = dyn_cast<TypedPattern>(OSP->getSubPattern())) {
37983797
ctx.Diags.diagnose(cond.getIntroducerLoc(),
37993798
diag::optional_check_promotion,
38003799
subExpr->getType())
@@ -3803,6 +3802,7 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
38033802
ooType->getString());
38043803
return;
38053804
}
3805+
}
38063806
ctx.Diags.diagnose(cond.getIntroducerLoc(),
38073807
diag::optional_pattern_match_promotion,
38083808
subExpr->getType(), cond.getInitializer()->getType())

lib/Sema/TypeCheckPattern.cpp

+18-7
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-
true);
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(), /*implicit*/ true);
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);
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

+1
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)