Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c84d2ab

Browse files
committed
[AST] Allow storing original expression in ErrorTypeRepr
This is useful for ArrowExpr when the sub-expressions aren't valid TypeExprs. Rather than throwing away the AST, attach it to the ErrorTypeRepr to ensure we can still type-check it. This ensures semantic functionality still works correctly, and fixes a crash where we'd stop visiting an invalid binding pattern, losing track of the nested VarDecl.
1 parent d2deaa9 commit c84d2ab

File tree

10 files changed

+74
-18
lines changed

10 files changed

+74
-18
lines changed

include/swift/AST/TypeRepr.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,26 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr
220220
class ErrorTypeRepr : public TypeRepr {
221221
SourceRange Range;
222222

223-
ErrorTypeRepr(SourceRange Range)
224-
: TypeRepr(TypeReprKind::Error), Range(Range) {}
223+
/// The original expression that failed to be resolved as a TypeRepr. Like
224+
/// ErrorExpr's original expr, this exists to ensure that semantic
225+
/// functionality can still work correctly, and is used to ensure we don't
226+
/// drop nodes from the AST.
227+
Expr *OriginalExpr;
228+
229+
ErrorTypeRepr(SourceRange Range, Expr *OriginalExpr)
230+
: TypeRepr(TypeReprKind::Error), Range(Range),
231+
OriginalExpr(OriginalExpr) {}
225232

226233
public:
227-
static ErrorTypeRepr *
228-
create(ASTContext &Context, SourceRange Range) {
229-
return new (Context) ErrorTypeRepr(Range);
234+
static ErrorTypeRepr *create(ASTContext &Context, SourceRange Range,
235+
Expr *OriginalExpr = nullptr) {
236+
return new (Context) ErrorTypeRepr(Range, OriginalExpr);
230237
}
231238

239+
/// Retrieve the original expression that failed to be resolved as a TypeRepr.
240+
Expr *getOriginalExpr() const { return OriginalExpr; }
241+
void setOriginalExpr(Expr *newExpr) { OriginalExpr = newExpr; }
242+
232243
static bool classof(const TypeRepr *T) {
233244
return T->getKind() == TypeReprKind::Error;
234245
}

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4619,6 +4619,8 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr, void, Label>,
46194619

46204620
void visitErrorTypeRepr(ErrorTypeRepr *T, Label label) {
46214621
printCommon("type_error", label);
4622+
if (auto *originalExpr = T->getOriginalExpr())
4623+
printRec(originalExpr, Label::optional("original_expr"));
46224624
}
46234625

46244626
void visitAttributedTypeRepr(AttributedTypeRepr *T, Label label) {

lib/AST/ASTWalker.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2267,6 +2267,12 @@ Pattern *Traversal::visitBoolPattern(BoolPattern *P) {
22672267

22682268
#pragma mark Type representation traversal
22692269
bool Traversal::visitErrorTypeRepr(ErrorTypeRepr *T) {
2270+
if (auto *originalExpr = T->getOriginalExpr()) {
2271+
auto *newExpr = doIt(originalExpr);
2272+
if (!newExpr)
2273+
return true;
2274+
T->setOriginalExpr(newExpr);
2275+
}
22702276
return false;
22712277
}
22722278

lib/AST/Pattern.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,15 @@ namespace {
221221
return Action::Continue(E);
222222
}
223223

224+
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
225+
// ErrorTypeReprs can contain invalid expressions.
226+
return Action::Continue();
227+
}
228+
224229
// Don't walk into anything else.
225230
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
226231
return Action::SkipNode(S);
227232
}
228-
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
229-
return Action::SkipNode();
230-
}
231233
PreWalkAction walkToParameterListPre(ParameterList *PL) override {
232234
return Action::SkipNode();
233235
}

lib/Sema/PreCheckTarget.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,14 +2347,17 @@ TypeExpr *PreCheckTarget::simplifyTypeExpr(Expr *E) {
23472347
return nullptr;
23482348
};
23492349

2350+
auto makeErrorTypeRepr = [&](Expr *E) -> ErrorTypeRepr * {
2351+
return ErrorTypeRepr::create(Ctx, E->getSourceRange(), E);
2352+
};
2353+
23502354
TupleTypeRepr *ArgsTypeRepr = extractInputTypeRepr(AE->getArgsExpr());
23512355
if (!ArgsTypeRepr) {
23522356
Ctx.Diags.diagnose(AE->getArgsExpr()->getLoc(),
23532357
diag::expected_type_before_arrow);
2354-
auto ArgRange = AE->getArgsExpr()->getSourceRange();
2355-
auto ErrRepr = ErrorTypeRepr::create(Ctx, ArgRange);
2358+
auto ErrRepr = makeErrorTypeRepr(AE->getArgsExpr());
23562359
ArgsTypeRepr =
2357-
TupleTypeRepr::create(Ctx, {ErrRepr}, ArgRange);
2360+
TupleTypeRepr::create(Ctx, {ErrRepr}, ErrRepr->getSourceRange());
23582361
}
23592362

23602363
TypeRepr *ThrownTypeRepr = nullptr;
@@ -2367,8 +2370,7 @@ TypeExpr *PreCheckTarget::simplifyTypeExpr(Expr *E) {
23672370
if (!ResultTypeRepr) {
23682371
Ctx.Diags.diagnose(AE->getResultExpr()->getLoc(),
23692372
diag::expected_type_after_arrow);
2370-
ResultTypeRepr =
2371-
ErrorTypeRepr::create(Ctx, AE->getResultExpr()->getSourceRange());
2373+
ResultTypeRepr = makeErrorTypeRepr(AE->getResultExpr());
23722374
}
23732375

23742376
auto NewTypeRepr = new (Ctx)

test/Parse/type_expr.swift

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,24 @@ func testFunctionCollectionTypes() {
313313
_ = [() -> Int]()
314314
_ = [(Int) -> ()]()
315315

316-
_ = 2 + () -> Int // expected-error {{expected type before '->'}}
317-
_ = () -> (Int, Int).2 // expected-error {{expected type after '->'}}
316+
// This is folded as '(2 + ()) -> Int'
317+
_ = 2 + () -> Int
318+
// expected-error@-1 {{expected type before '->'}}
319+
// expected-error@-2 {{cannot convert value of type '()' to expected argument type 'Int'}}
320+
321+
_ = () -> (Int, Int).2
322+
// expected-error@-1 {{expected type after '->'}}
323+
// expected-error@-2 {{value of tuple type '(Int, Int)' has no member '2'}}
324+
318325
_ = (Int) -> Int // expected-error {{expected member name or initializer call after type name}} expected-note{{use '.self' to reference the type object}}
319326

320327
_ = @convention(c) () -> Int // expected-error{{expected member name or initializer call after type name}} expected-note{{use '.self' to reference the type object}}
321328
_ = 1 + (@convention(c) () -> Int).self // expected-error{{cannot convert value of type '(@convention(c) () -> Int).Type' to expected argument type 'Int'}}
322-
_ = (@autoclosure () -> Int) -> (Int, Int).2 // expected-error {{expected type after '->'}}
329+
330+
_ = (@autoclosure () -> Int) -> (Int, Int).2
331+
// expected-error@-1 {{expected type after '->'}}
332+
// expected-error@-2 {{value of tuple type '(Int, Int)' has no member '2'}}
333+
323334
_ = ((@autoclosure () -> Int) -> (Int, Int)).1 // expected-error {{type '(@autoclosure () -> Int) -> (Int, Int)' has no member '1'}}
324335
_ = ((inout Int) -> Void).self
325336
@@ -331,6 +342,18 @@ func testFunctionCollectionTypes() {
331342
let _ = [Int throws Int](); // expected-error{{'throws' may only occur before '->'}} expected-error {{consecutive statements on a line must be separated by ';'}}
332343
}
333344

345+
func testInvalidArrowWithClosure() {
346+
_ = { undefined -> undefined2 }
347+
// expected-error@-1 {{cannot find 'undefined' in scope}}
348+
// expected-error@-2 {{cannot find 'undefined2' in scope}}
349+
// expected-error@-3 {{expected type before '->'}}
350+
// expected-error@-4 {{expected type after '->'}}
351+
352+
() -> { let x: Int = "" }
353+
// expected-error@-1 {{expected type after '->'}}
354+
// expected-error@-2 {{cannot convert value of type 'String' to specified type 'Int'}}
355+
}
356+
334357
func compositionType() {
335358
_ = P1 & P2 // expected-error {{expected member name or initializer call after type name}} expected-note{{use '.self'}} {{7-7=(}} {{14-14=).self}}
336359
_ = any P1 & P1 // expected-error {{expected member name or initializer call after type name}} expected-note{{use '.self'}} {{7-7=(}} {{18-18=).self}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// {"kind":"complete","original":"2ad6764c","signature":"swift::constraints::Solution::getType(swift::KeyPathExpr const*, unsigned int) const","signatureAssert":"Assertion failed: (hasType(KP, I) && \"Expected type to have been set!\"), function getType"}
2-
// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s
2+
// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s
33
0 -> \ a#^^#
44
!
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// {"kind":"complete","signature":"swift::constraints::TypeVarRefCollector::walkToStmtPre(swift::Stmt*)","signatureAssert":"Assertion failed: (result), function getClosureType"}
2-
// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s
2+
// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s
33
a -> { let b = switch { case return } func c -> #^COMPLETE^#
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// {"kind":"typecheck","original":"01146903","signature":"swift::NamingPatternRequest::evaluate(swift::Evaluator&, swift::VarDecl*) const"}
2+
// RUN: not %target-swift-frontend -typecheck %s
3+
switch {
4+
case let .a -> b b
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// {"kind":"typecheck","original":"01146903","signature":"(anonymous namespace)::ConstraintWalker::walkToExprPost(swift::Expr*)"}
2+
// RUN: not %target-swift-frontend -typecheck %s
3+
switch <#expression#> {
4+
case let .a -> b:
5+
b
6+
}

0 commit comments

Comments
 (0)