Skip to content

[Parser, NameLookup, ASTScope] Parser changes for lazy ASTScopes #26768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 23, 2019
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
10 changes: 7 additions & 3 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -926,11 +926,13 @@ class TapExpr : public Expr {
void setBody(BraceStmt * b) { Body = b; }

SourceLoc getLoc() const { return SubExpr ? SubExpr->getLoc() : SourceLoc(); }

SourceRange getSourceRange() const {
return SubExpr ? SubExpr->getSourceRange() : SourceRange();
SourceLoc getStartLoc() const {
return SubExpr ? SubExpr->getStartLoc() : SourceLoc();
}

SourceLoc getEndLoc() const;

static bool classof(const Expr *E) {
return E->getKind() == ExprKind::Tap;
}
Expand Down Expand Up @@ -1027,6 +1029,8 @@ class InterpolatedStringLiteralExpr : public LiteralExpr {
// token, so the range should be (Start == End).
return Loc;
}

/// Could also be computed by relexing.
SourceLoc getTrailingQuoteLoc() const {
return TrailingQuoteLoc;
}
Expand Down
18 changes: 17 additions & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ class Parser {

/// Retrieve the location just past the end of the previous
/// source location.
SourceLoc getEndOfPreviousLoc();
SourceLoc getEndOfPreviousLoc() const;

/// If the current token is the specified kind, consume it and
/// return true. Otherwise, return false without consuming it.
Expand Down Expand Up @@ -812,6 +812,19 @@ class Parser {
bool parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag,
SourceLoc OtherLoc);

/// Returns the proper location for a missing right brace, parenthesis, etc.
SourceLoc getLocForMissingMatchingToken() const;

/// When encountering an error or a missing matching token (e.g. '}'), return
/// the location to use for it. This value should be at the last token in
/// the ASTNode being parsed so that it nests within any enclosing nodes, and,
/// for ASTScope lookups, it does not preceed any identifiers to be looked up.
/// However, the latter case does not hold when parsing an interpolated
/// string literal because there may be identifiers to be looked up in the
/// literal and their locations will not precede the location of a missing
/// close brace.
SourceLoc getErrorOrMissingLoc() const;

/// Parse a comma separated list of some elements.
ParserStatus parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc,
bool AllowSepAfterLast, Diag<> ErrorDiag,
Expand Down Expand Up @@ -1068,6 +1081,9 @@ class Parser {

ParserResult<TypeRepr> parseDeclResultType(Diag<> MessageID);

/// Get the location for a type error.
SourceLoc getTypeErrorLoc() const;

//===--------------------------------------------------------------------===//
// Type Parsing

Expand Down
4 changes: 3 additions & 1 deletion lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3654,7 +3654,9 @@ class Verifier : public ASTWalker {
if (D->isImplicit())
return;
// FIXME: This is not working well for decl parents.
return;
// But it must work when using lazy ASTScopes for IterableDeclContexts
if (!isa<IterableDeclContext>(D))
return;
} else if (Stmt *S = Parent.getAsStmt()) {
Enclosing = S->getSourceRange();
if (S->isImplicit())
Expand Down
14 changes: 14 additions & 0 deletions lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2227,6 +2227,20 @@ VarDecl * TapExpr::getVar() const {
return dyn_cast<VarDecl>(Body->getElement(0).dyn_cast<Decl *>());
}

SourceLoc TapExpr::getEndLoc() const {
// Include the body in the range, assuming the body follows the SubExpr.
// Also, be (perhaps overly) defensive about null pointers & invalid
// locations.
if (auto *const b = getBody()) {
const auto be = b->getEndLoc();
if (be.isValid())
return be;
}
if (auto *const se = getSubExpr())
return se->getEndLoc();
return SourceLoc();
}

// See swift/Basic/Statistic.h for declaration: this enables tracing Exprs, is
// defined here to avoid too much layering violation / circular linkage
// dependency.
Expand Down
6 changes: 5 additions & 1 deletion lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1992,6 +1992,9 @@ ParserResult<Expr> Parser::parseExprStringLiteral() {
llvm::SaveAndRestore<Token> SavedTok(Tok);
llvm::SaveAndRestore<ParsedTrivia> SavedLeadingTrivia(LeadingTrivia);
llvm::SaveAndRestore<ParsedTrivia> SavedTrailingTrivia(TrailingTrivia);
// For errors, we need the real PreviousLoc, i.e. the start of the
// whole InterpolatedStringLiteral.
llvm::SaveAndRestore<SourceLoc> SavedPreviousLoc(PreviousLoc);

// We're not in a place where an interpolation would be valid.
if (!CurLocalContext) {
Expand Down Expand Up @@ -3426,7 +3429,8 @@ ParserResult<Expr> Parser::parseExprCollection() {

if (Status.isError()) {
// If we've already got errors, don't emit missing RightK diagnostics.
RSquareLoc = Tok.is(tok::r_square) ? consumeToken() : PreviousLoc;
RSquareLoc = Tok.is(tok::r_square) ? consumeToken()
: getLocForMissingMatchingToken();
} else if (parseMatchingToken(tok::r_square, RSquareLoc,
diag::expected_rsquare_array_expr,
LSquareLoc)) {
Expand Down
11 changes: 9 additions & 2 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,8 @@ ParserResult<TypeRepr> Parser::parseDeclResultType(Diag<> MessageID) {
auto diag = diagnose(Tok, diag::extra_rbracket);
diag.fixItInsert(result.get()->getStartLoc(), getTokenText(tok::l_square));
consumeToken();
return makeParserErrorResult(new (Context) ErrorTypeRepr(Tok.getLoc()));
return makeParserErrorResult(new (Context)
ErrorTypeRepr(getTypeErrorLoc()));
} else if (!result.isParseError() && Tok.is(tok::colon)) {
auto colonTok = consumeToken();
auto secondType = parseType(diag::expected_dictionary_value_type);
Expand All @@ -534,11 +535,17 @@ ParserResult<TypeRepr> Parser::parseDeclResultType(Diag<> MessageID) {
diag.fixItInsertAfter(secondType.get()->getEndLoc(), getTokenText(tok::r_square));
}
}
return makeParserErrorResult(new (Context) ErrorTypeRepr(Tok.getLoc()));
return makeParserErrorResult(new (Context)
ErrorTypeRepr(getTypeErrorLoc()));
}
return result;
}

SourceLoc Parser::getTypeErrorLoc() const {
// Use the same location as a missing close brace, etc.
return getErrorOrMissingLoc();
}

ParserStatus Parser::parseGenericArguments(SmallVectorImpl<TypeRepr *> &Args,
SourceLoc &LAngleLoc,
SourceLoc &RAngleLoc) {
Expand Down
30 changes: 25 additions & 5 deletions lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ ParsedTokenSyntax Parser::consumeTokenSyntax() {
return ParsedToken;
}

SourceLoc Parser::getEndOfPreviousLoc() {
SourceLoc Parser::getEndOfPreviousLoc() const {
return Lexer::getLocForEndOfToken(SourceMgr, PreviousLoc);
}

Expand Down Expand Up @@ -968,8 +968,6 @@ bool Parser::parseToken(tok K, SourceLoc &TokLoc, const Diagnostic &D) {
return true;
}

/// Parse the specified expected token and return its location on success. On failure, emit the specified
/// error diagnostic, a note at the specified note location, and return the location of the previous token.
bool Parser::parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag,
SourceLoc OtherLoc) {
Diag<> OtherNote;
Expand All @@ -982,13 +980,34 @@ bool Parser::parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag,
if (parseToken(K, TokLoc, ErrorDiag)) {
diagnose(OtherLoc, OtherNote);

TokLoc = PreviousLoc;
TokLoc = getLocForMissingMatchingToken();
return true;
}

return false;
}

SourceLoc Parser::getLocForMissingMatchingToken() const {
// At present, use the same location whether it's an error or whether
// the matching token is missing.
// Both cases supply a location for something the user didn't type.
return getErrorOrMissingLoc();
}

SourceLoc Parser::getErrorOrMissingLoc() const {
// The next token might start a new enclosing construct,
// and SourceLoc's are always at the start of a token (for example, for
// fixits, so use the previous token's SourceLoc and allow a subnode to end
// right at the same place as its supernode.

// The tricky case is when the previous token is an InterpolatedStringLiteral.
// Then, there will be names in scope whose SourceLoc is *after* the
// the location of a missing close brace.
// ASTScope tree creation will have to cope.

return PreviousLoc;
}

static SyntaxKind getListElementKind(SyntaxKind ListKind) {
switch (ListKind) {
case SyntaxKind::FunctionCallArgumentList:
Expand Down Expand Up @@ -1094,7 +1113,8 @@ Parser::parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc,

if (Status.isError()) {
// If we've already got errors, don't emit missing RightK diagnostics.
RightLoc = Tok.is(RightK) ? consumeToken() : PreviousLoc;
RightLoc =
Tok.is(RightK) ? consumeToken() : getLocForMissingMatchingToken();
} else if (parseMatchingToken(RightK, RightLoc, ErrorDiag, LeftLoc)) {
Status.setIsParseError();
}
Expand Down