Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 15 additions & 21 deletions include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,35 +216,29 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr
/// A TypeRepr for a type with a syntax error. Can be used both as a
/// top-level TypeRepr and as a part of other TypeRepr.
///
/// The client can either emit a detailed diagnostic at the construction time
/// (in the parser) or store a zero-arg diagnostic in this TypeRepr to be
/// emitted after parsing, during type resolution.
///
/// All uses of this type should be ignored and not re-diagnosed.
class ErrorTypeRepr : public TypeRepr {
SourceRange Range;
std::optional<ZeroArgDiagnostic> DelayedDiag;

ErrorTypeRepr(SourceRange Range, std::optional<ZeroArgDiagnostic> Diag)
: TypeRepr(TypeReprKind::Error), Range(Range), DelayedDiag(Diag) {}
/// The original expression that failed to be resolved as a TypeRepr. Like
/// ErrorExpr's original expr, this exists to ensure that semantic
/// functionality can still work correctly, and is used to ensure we don't
/// drop nodes from the AST.
Expr *OriginalExpr;

public:
static ErrorTypeRepr *
create(ASTContext &Context, SourceRange Range,
std::optional<ZeroArgDiagnostic> DelayedDiag = std::nullopt) {
assert((!DelayedDiag || Range) && "diagnostic needs a location");
return new (Context) ErrorTypeRepr(Range, DelayedDiag);
}
ErrorTypeRepr(SourceRange Range, Expr *OriginalExpr)
: TypeRepr(TypeReprKind::Error), Range(Range),
OriginalExpr(OriginalExpr) {}

static ErrorTypeRepr *
create(ASTContext &Context, SourceLoc Loc = SourceLoc(),
std::optional<ZeroArgDiagnostic> DelayedDiag = std::nullopt) {
return create(Context, SourceRange(Loc), DelayedDiag);
public:
static ErrorTypeRepr *create(ASTContext &Context, SourceRange Range,
Expr *OriginalExpr = nullptr) {
return new (Context) ErrorTypeRepr(Range, OriginalExpr);
}

/// If there is a delayed diagnostic stored in this TypeRepr, consumes and
/// emits that diagnostic.
void dischargeDiagnostic(ASTContext &Context);
/// Retrieve the original expression that failed to be resolved as a TypeRepr.
Expr *getOriginalExpr() const { return OriginalExpr; }
void setOriginalExpr(Expr *newExpr) { OriginalExpr = newExpr; }

static bool classof(const TypeRepr *T) {
return T->getKind() == TypeReprKind::Error;
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4619,6 +4619,8 @@ class PrintTypeRepr : public TypeReprVisitor<PrintTypeRepr, void, Label>,

void visitErrorTypeRepr(ErrorTypeRepr *T, Label label) {
printCommon("type_error", label);
if (auto *originalExpr = T->getOriginalExpr())
printRec(originalExpr, Label::optional("original_expr"));
}

void visitAttributedTypeRepr(AttributedTypeRepr *T, Label label) {
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/ASTWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2267,6 +2267,12 @@ Pattern *Traversal::visitBoolPattern(BoolPattern *P) {

#pragma mark Type representation traversal
bool Traversal::visitErrorTypeRepr(ErrorTypeRepr *T) {
if (auto *originalExpr = T->getOriginalExpr()) {
auto *newExpr = doIt(originalExpr);
if (!newExpr)
return true;
T->setOriginalExpr(newExpr);
}
return false;
}

Expand Down
8 changes: 5 additions & 3 deletions lib/AST/Pattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,15 @@ namespace {
return Action::Continue(E);
}

PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
// ErrorTypeReprs can contain invalid expressions.
return Action::Continue();
}

// Don't walk into anything else.
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
return Action::SkipNode(S);
}
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
return Action::SkipNode();
}
PreWalkAction walkToParameterListPre(ParameterList *PL) override {
return Action::SkipNode();
}
Expand Down
9 changes: 0 additions & 9 deletions lib/AST/TypeRepr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -970,15 +970,6 @@ void IntegerTypeRepr::printImpl(ASTPrinter &Printer,
Printer.printText(getValue());
}

void ErrorTypeRepr::dischargeDiagnostic(swift::ASTContext &Context) {
if (!DelayedDiag)
return;

// Consume and emit the diagnostic.
Context.Diags.diagnose(Range.Start, *DelayedDiag).highlight(Range);
DelayedDiag = std::nullopt;
}

// See swift/Basic/Statistic.h for declaration: this enables tracing
// TypeReprs, is defined here to avoid too much layering violation / circular
// linkage dependency.
Expand Down
3 changes: 2 additions & 1 deletion lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9935,7 +9935,8 @@ Parser::parseDeclSubscript(SourceLoc StaticLoc,

if (ElementTy.isNull()) {
// Always set an element type.
ElementTy = makeParserResult(ElementTy, ErrorTypeRepr::create(Context));
ElementTy = makeParserResult(
ElementTy, ErrorTypeRepr::create(Context, getTypeErrorLoc()));
}
}

Expand Down
12 changes: 7 additions & 5 deletions lib/Sema/PreCheckTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2347,14 +2347,17 @@ TypeExpr *PreCheckTarget::simplifyTypeExpr(Expr *E) {
return nullptr;
};

auto makeErrorTypeRepr = [&](Expr *E) -> ErrorTypeRepr * {
return ErrorTypeRepr::create(Ctx, E->getSourceRange(), E);
};

TupleTypeRepr *ArgsTypeRepr = extractInputTypeRepr(AE->getArgsExpr());
if (!ArgsTypeRepr) {
Ctx.Diags.diagnose(AE->getArgsExpr()->getLoc(),
diag::expected_type_before_arrow);
auto ArgRange = AE->getArgsExpr()->getSourceRange();
auto ErrRepr = ErrorTypeRepr::create(Ctx, ArgRange);
auto ErrRepr = makeErrorTypeRepr(AE->getArgsExpr());
ArgsTypeRepr =
TupleTypeRepr::create(Ctx, {ErrRepr}, ArgRange);
TupleTypeRepr::create(Ctx, {ErrRepr}, ErrRepr->getSourceRange());
}

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

auto NewTypeRepr = new (Ctx)
Expand Down
1 change: 0 additions & 1 deletion lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2766,7 +2766,6 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,

switch (repr->getKind()) {
case TypeReprKind::Error:
cast<ErrorTypeRepr>(repr)->dischargeDiagnostic(getASTContext());
return ErrorType::get(getASTContext());

case TypeReprKind::Attributed:
Expand Down
29 changes: 26 additions & 3 deletions test/Parse/type_expr.swift
Original file line number Diff line number Diff line change
Expand Up @@ -313,13 +313,24 @@ func testFunctionCollectionTypes() {
_ = [() -> Int]()
_ = [(Int) -> ()]()

_ = 2 + () -> Int // expected-error {{expected type before '->'}}
_ = () -> (Int, Int).2 // expected-error {{expected type after '->'}}
// This is folded as '(2 + ()) -> Int'
_ = 2 + () -> Int
// expected-error@-1 {{expected type before '->'}}
// expected-error@-2 {{cannot convert value of type '()' to expected argument type 'Int'}}

_ = () -> (Int, Int).2
// expected-error@-1 {{expected type after '->'}}
// expected-error@-2 {{value of tuple type '(Int, Int)' has no member '2'}}

_ = (Int) -> Int // expected-error {{expected member name or initializer call after type name}} expected-note{{use '.self' to reference the type object}}

_ = @convention(c) () -> Int // expected-error{{expected member name or initializer call after type name}} expected-note{{use '.self' to reference the type object}}
_ = 1 + (@convention(c) () -> Int).self // expected-error{{cannot convert value of type '(@convention(c) () -> Int).Type' to expected argument type 'Int'}}
_ = (@autoclosure () -> Int) -> (Int, Int).2 // expected-error {{expected type after '->'}}

_ = (@autoclosure () -> Int) -> (Int, Int).2
// expected-error@-1 {{expected type after '->'}}
// expected-error@-2 {{value of tuple type '(Int, Int)' has no member '2'}}

_ = ((@autoclosure () -> Int) -> (Int, Int)).1 // expected-error {{type '(@autoclosure () -> Int) -> (Int, Int)' has no member '1'}}
_ = ((inout Int) -> Void).self

Expand All @@ -331,6 +342,18 @@ func testFunctionCollectionTypes() {
let _ = [Int throws Int](); // expected-error{{'throws' may only occur before '->'}} expected-error {{consecutive statements on a line must be separated by ';'}}
}

func testInvalidArrowWithClosure() {
_ = { undefined -> undefined2 }
// expected-error@-1 {{cannot find 'undefined' in scope}}
// expected-error@-2 {{cannot find 'undefined2' in scope}}
// expected-error@-3 {{expected type before '->'}}
// expected-error@-4 {{expected type after '->'}}

() -> { let x: Int = "" }
// expected-error@-1 {{expected type after '->'}}
// expected-error@-2 {{cannot convert value of type 'String' to specified type 'Int'}}
}

func compositionType() {
_ = P1 & P2 // expected-error {{expected member name or initializer call after type name}} expected-note{{use '.self'}} {{7-7=(}} {{14-14=).self}}
_ = any P1 & P1 // expected-error {{expected member name or initializer call after type name}} expected-note{{use '.self'}} {{7-7=(}} {{18-18=).self}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// {"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"}
// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s
// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s
0 -> \ a#^^#
!
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// {"kind":"complete","signature":"swift::constraints::TypeVarRefCollector::walkToStmtPre(swift::Stmt*)","signatureAssert":"Assertion failed: (result), function getClosureType"}
// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s
// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s
a -> { let b = switch { case return } func c -> #^COMPLETE^#
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// {"kind":"typecheck","original":"01146903","signature":"swift::NamingPatternRequest::evaluate(swift::Evaluator&, swift::VarDecl*) const"}
// RUN: not %target-swift-frontend -typecheck %s
switch {
case let .a -> b b
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// {"kind":"typecheck","original":"01146903","signature":"(anonymous namespace)::ConstraintWalker::walkToExprPost(swift::Expr*)"}
// RUN: not %target-swift-frontend -typecheck %s
switch <#expression#> {
case let .a -> b:
b
}