mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Remove The Parser Hack For If-Let
The parser used to rewrite if let x: T into if let x: T? This transformation is correct at face value, but relied on being able to construct TypeReprs with bogus source locations. Instead of having the parser kick semantic analysis into shape, let's perform this reinterpretation when we resolve if-let patterns in statement conditions.
This commit is contained in:
@@ -1359,8 +1359,7 @@ public:
|
|||||||
ParserResult<Pattern> parsePatternTuple();
|
ParserResult<Pattern> parsePatternTuple();
|
||||||
|
|
||||||
ParserResult<Pattern>
|
ParserResult<Pattern>
|
||||||
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P,
|
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P);
|
||||||
bool isOptional);
|
|
||||||
ParserResult<Pattern> parseMatchingPattern(bool isExprBasic);
|
ParserResult<Pattern> parseMatchingPattern(bool isExprBasic);
|
||||||
ParserResult<Pattern> parseMatchingPatternAsLetOrVar(bool isLet,
|
ParserResult<Pattern> parseMatchingPatternAsLetOrVar(bool isLet,
|
||||||
SourceLoc VarLoc,
|
SourceLoc VarLoc,
|
||||||
|
|||||||
@@ -1124,8 +1124,7 @@ ParserResult<Pattern> Parser::parsePatternTuple() {
|
|||||||
/// pattern-type-annotation ::= (':' type)?
|
/// pattern-type-annotation ::= (':' type)?
|
||||||
///
|
///
|
||||||
ParserResult<Pattern> Parser::
|
ParserResult<Pattern> Parser::
|
||||||
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
|
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result) {
|
||||||
bool isOptional) {
|
|
||||||
if (!Tok.is(tok::colon))
|
if (!Tok.is(tok::colon))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@@ -1152,15 +1151,6 @@ parseOptionalPatternTypeAnnotation(ParserResult<Pattern> result,
|
|||||||
if (!repr)
|
if (!repr)
|
||||||
repr = new (Context) ErrorTypeRepr(PreviousLoc);
|
repr = new (Context) ErrorTypeRepr(PreviousLoc);
|
||||||
|
|
||||||
// In an if-let, the actual type of the expression is Optional of whatever
|
|
||||||
// was written.
|
|
||||||
// FIXME: This is not good, `TypeRepr`s are supposed to represent what the
|
|
||||||
// user actually wrote in source (that's why they don't have any `isImplicit`
|
|
||||||
// bit). This synthesized `OptionalTypeRepr` leads to workarounds in other
|
|
||||||
// parts where we want to reason about the types as perceived by the user.
|
|
||||||
if (isOptional)
|
|
||||||
repr = new (Context) OptionalTypeRepr(repr, SourceLoc());
|
|
||||||
|
|
||||||
return makeParserResult(status, new (Context) TypedPattern(P, repr));
|
return makeParserResult(status, new (Context) TypedPattern(P, repr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1502,8 +1502,7 @@ Parser::parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
|
|||||||
P->setImplicit();
|
P->setImplicit();
|
||||||
}
|
}
|
||||||
|
|
||||||
ThePattern = parseOptionalPatternTypeAnnotation(ThePattern,
|
ThePattern = parseOptionalPatternTypeAnnotation(ThePattern);
|
||||||
BindingKindStr != "case");
|
|
||||||
if (ThePattern.hasCodeCompletion())
|
if (ThePattern.hasCodeCompletion())
|
||||||
Status.setHasCodeCompletion();
|
Status.setHasCodeCompletion();
|
||||||
|
|
||||||
@@ -2123,7 +2122,7 @@ ParserResult<Stmt> Parser::parseStmtForEach(LabeledStmtInfo LabelInfo) {
|
|||||||
llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
|
llvm::SaveAndRestore<decltype(InVarOrLetPattern)>
|
||||||
T(InVarOrLetPattern, Parser::IVOLP_InMatchingPattern);
|
T(InVarOrLetPattern, Parser::IVOLP_InMatchingPattern);
|
||||||
pattern = parseMatchingPattern(/*isExprBasic*/true);
|
pattern = parseMatchingPattern(/*isExprBasic*/true);
|
||||||
pattern = parseOptionalPatternTypeAnnotation(pattern, /*isOptional*/false);
|
pattern = parseOptionalPatternTypeAnnotation(pattern);
|
||||||
} else if (!IsCStyleFor || Tok.is(tok::kw_var)) {
|
} else if (!IsCStyleFor || Tok.is(tok::kw_var)) {
|
||||||
// Change the parser state to know that the pattern we're about to parse is
|
// Change the parser state to know that the pattern we're about to parse is
|
||||||
// implicitly mutable. Bound variables can be changed to mutable explicitly
|
// implicitly mutable. Bound variables can be changed to mutable explicitly
|
||||||
|
|||||||
@@ -4278,7 +4278,7 @@ SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
|
|||||||
bool bindPatternVarsOneWay) {
|
bool bindPatternVarsOneWay) {
|
||||||
// Determine the contextual type for the initialization.
|
// Determine the contextual type for the initialization.
|
||||||
TypeLoc contextualType;
|
TypeLoc contextualType;
|
||||||
if (!isa<OptionalSomePattern>(pattern) &&
|
if (!(isa<OptionalSomePattern>(pattern) && !pattern->isImplicit()) &&
|
||||||
patternType && !patternType->isHole()) {
|
patternType && !patternType->isHole()) {
|
||||||
contextualType = TypeLoc::withoutLoc(patternType);
|
contextualType = TypeLoc::withoutLoc(patternType);
|
||||||
|
|
||||||
|
|||||||
@@ -1434,7 +1434,8 @@ public:
|
|||||||
bool isOptionalSomePatternInit() const {
|
bool isOptionalSomePatternInit() const {
|
||||||
return kind == Kind::expression &&
|
return kind == Kind::expression &&
|
||||||
expression.contextualPurpose == CTP_Initialization &&
|
expression.contextualPurpose == CTP_Initialization &&
|
||||||
isa<OptionalSomePattern>(expression.pattern);
|
isa<OptionalSomePattern>(expression.pattern) &&
|
||||||
|
!expression.pattern->isImplicit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to bind the types of any variables within the pattern via
|
/// Whether to bind the types of any variables within the pattern via
|
||||||
|
|||||||
@@ -3752,10 +3752,9 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
|
|||||||
// checking for a type, which forced it to be promoted to a double optional
|
// checking for a type, which forced it to be promoted to a double optional
|
||||||
// type.
|
// type.
|
||||||
if (auto ooType = subExpr->getType()->getOptionalObjectType()) {
|
if (auto ooType = subExpr->getType()->getOptionalObjectType()) {
|
||||||
if (auto TP = dyn_cast<TypedPattern>(p))
|
if (auto OSP = dyn_cast<OptionalSomePattern>(p)) {
|
||||||
// Check for 'if let' to produce a tuned diagnostic.
|
// Check for 'if let' to produce a tuned diagnostic.
|
||||||
if (isa<OptionalSomePattern>(TP->getSubPattern()) &&
|
if (auto *TP = dyn_cast<TypedPattern>(OSP->getSubPattern())) {
|
||||||
TP->getSubPattern()->isImplicit()) {
|
|
||||||
ctx.Diags.diagnose(cond.getIntroducerLoc(),
|
ctx.Diags.diagnose(cond.getIntroducerLoc(),
|
||||||
diag::optional_check_promotion,
|
diag::optional_check_promotion,
|
||||||
subExpr->getType())
|
subExpr->getType())
|
||||||
@@ -3764,6 +3763,7 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
|
|||||||
ooType->getString());
|
ooType->getString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ctx.Diags.diagnose(cond.getIntroducerLoc(),
|
ctx.Diags.diagnose(cond.getIntroducerLoc(),
|
||||||
diag::optional_pattern_match_promotion,
|
diag::optional_pattern_match_promotion,
|
||||||
subExpr->getType(), cond.getInitializer()->getType())
|
subExpr->getType(), cond.getInitializer()->getType())
|
||||||
|
|||||||
@@ -655,12 +655,8 @@ Pattern *TypeChecker::resolvePattern(Pattern *P, DeclContext *DC,
|
|||||||
|
|
||||||
// "if let" implicitly looks inside of an optional, so wrap it in an
|
// "if let" implicitly looks inside of an optional, so wrap it in an
|
||||||
// OptionalSome pattern.
|
// OptionalSome pattern.
|
||||||
InnerP = new (Context) OptionalSomePattern(InnerP, InnerP->getEndLoc());
|
P = new (Context) OptionalSomePattern(P, P->getEndLoc());
|
||||||
InnerP->setImplicit();
|
P->setImplicit();
|
||||||
if (auto *TP = dyn_cast<TypedPattern>(P))
|
|
||||||
TP->setSubPattern(InnerP);
|
|
||||||
else
|
|
||||||
P = InnerP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return P;
|
return P;
|
||||||
@@ -811,9 +807,24 @@ Type PatternTypeRequest::evaluate(Evaluator &evaluator,
|
|||||||
//
|
//
|
||||||
// Refutable patterns occur when checking the PatternBindingDecls in if/let,
|
// Refutable patterns occur when checking the PatternBindingDecls in if/let,
|
||||||
// while/let, and let/else conditions.
|
// while/let, and let/else conditions.
|
||||||
|
case PatternKind::OptionalSome: {
|
||||||
|
// Annotated if-let patterns are rewritten by TypeChecker::resolvePattern
|
||||||
|
// to have an enclosing implicit (...)? pattern. If we can resolve the inner
|
||||||
|
// typed pattern, the resulting pattern must have optional type.
|
||||||
|
auto somePat = cast<OptionalSomePattern>(P);
|
||||||
|
if (somePat->isImplicit() && isa<TypedPattern>(somePat->getSubPattern())) {
|
||||||
|
auto resolution = TypeResolution::forContextual(dc, options);
|
||||||
|
TypedPattern *TP = cast<TypedPattern>(somePat->getSubPattern());
|
||||||
|
auto type = validateTypedPattern(resolution, TP, options);
|
||||||
|
if (type && !type->hasError()) {
|
||||||
|
return OptionalType::get(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LLVM_FALLTHROUGH;
|
||||||
|
}
|
||||||
|
|
||||||
case PatternKind::Is:
|
case PatternKind::Is:
|
||||||
case PatternKind::EnumElement:
|
case PatternKind::EnumElement:
|
||||||
case PatternKind::OptionalSome:
|
|
||||||
case PatternKind::Bool:
|
case PatternKind::Bool:
|
||||||
case PatternKind::Expr:
|
case PatternKind::Expr:
|
||||||
// In a let/else, these always require an initial value to match against.
|
// In a let/else, these always require an initial value to match against.
|
||||||
|
|||||||
@@ -556,6 +556,7 @@ func testThrowNil() throws {
|
|||||||
// condition may have contained a SequenceExpr.
|
// condition may have contained a SequenceExpr.
|
||||||
func r23684220(_ b: Any) {
|
func r23684220(_ b: Any) {
|
||||||
if let _ = b ?? b {} // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'Any', so the right side is never used}}
|
if let _ = b ?? b {} // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'Any', so the right side is never used}}
|
||||||
|
// expected-error@-1 {{initializer for conditional binding must have Optional type, not 'Any'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user