-
Notifications
You must be signed in to change notification settings - Fork 10.5k
SR-13098 Diagnostic improvement: encountering an unexpected statement at type scope #32984
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
Changes from all commits
7da4d8c
b849800
baf14e6
e484569
9501414
92bb52c
608ac92
8a56bb8
1be6f2c
100c8fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ | |
#include "swift/AST/LazyResolver.h" | ||
#include "swift/AST/DebuggerClient.h" | ||
#include "swift/AST/DiagnosticsParse.h" | ||
#include "swift/AST/DiagnosticSuppression.h" | ||
#include "swift/AST/Initializer.h" | ||
#include "swift/AST/Module.h" | ||
#include "swift/AST/ParameterList.h" | ||
|
@@ -3926,9 +3927,46 @@ Parser::parseDecl(ParseDeclOptions Flags, | |
break; | ||
} | ||
|
||
const bool IsProbablyFuncDecl = | ||
Tok.isIdentifierOrUnderscore() || Tok.isAnyOperator(); | ||
bool IsProbablyFuncDecl = false; | ||
|
||
if (Tok.isIdentifierOrUnderscore() || Tok.isAnyOperator()) { | ||
|
||
// This is a probe, so backtrack when we're done | ||
// and don't emit diagnostics. | ||
BacktrackingScope backtrackingScope(*this); | ||
DiagnosticSuppression diagnosticSuppression(Diags); | ||
|
||
// TODO make sure we can't get these from the environment | ||
SourceLoc staticLoc; | ||
StaticSpellingKind staticSpelling = StaticSpellingKind::None; | ||
DeclAttributes attributes; | ||
bool hasFuncKeyword = false; | ||
|
||
ParserResult<FuncDecl> parserResult = | ||
parseDeclFunc(staticLoc, | ||
staticSpelling, | ||
Flags, | ||
attributes, | ||
hasFuncKeyword); | ||
|
||
// it looks like we always get a good parse result. | ||
// But if there are no parentheses | ||
// the left and right parens will be at the beginning of | ||
// the expression and will be equal so we use | ||
// this to reject degenerate declarations. | ||
|
||
if (parserResult.isNonNull()) { | ||
auto parameterList = parserResult.get()->getParameters(); | ||
if (parameterList->getLParenLoc() != parameterList->getRParenLoc()) { | ||
IsProbablyFuncDecl = true; | ||
} | ||
} | ||
// backtrackingScope and diagnostic suppression are both RAII | ||
// when they go out of scope, Tok returns to the beginning of | ||
// the identifier, and diagnostics are unsuppressed. | ||
Comment on lines
+3964
to
+3966
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We generally try to avoid comments which explain what is going on (which can be understood by reading the code) and try to focus on the why, unless something is particularly complicated. I would avoid this comment and similar comments above and below.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with you that the specific comment you’re marking here (about RAII variables) is unnecessary, but I actually think the comments about probing are helpful “why” comments. (Maybe they could be shortened slightly—“This is a probe, so we will always backtrack after we’re done.” is definitely a helpful “why” comment.) |
||
} | ||
|
||
// if probe succeeded, then do it for real | ||
if (IsProbablyFuncDecl) { | ||
|
||
DescriptiveDeclKind DescriptiveKind; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// RUN: %target-typecheck-verify-swift | ||
|
||
struct Bar { // expected-note {{in declaration of 'Bar'}} | ||
var fisr = 0x5F3759DF | ||
var a: Int | ||
|
||
// ensure that the id.id pattern is not interpreted as a function | ||
a.foo = 345 // expected-error {{expected declaration}} | ||
// ensure that the id.id pattern generating an expected declaration | ||
// diagnostic does not block further diagnostics. | ||
fisr.bar = 345 | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite follow the reasoning here. Why is the degenerate case rejected? Also, if the parser always succeeds, there must be something wrong with it... Not every syntactic form is a valid function declaration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is confusing.
parseDeclFunc
returns a non-null parse result even when it does not completely parse a function. It's pretty liberal in what it will accept. That's part of why this was happening originally--it thought the statement was a function then tried to parse it and sent out a lot of confusing diagnostics.The situation we are guarding against is a statement at the type level when there should be a function.
parseDeclFunc
is returning a non-nullParserResult<FuncDecl>
in that situation and the only indicator (empirically) is that the left and right paren locations are identical in theParserResult<FuncDecl>
.I did not re-run all this through the debugger today. But as I remember it the parentheses are not the sensitive point--there are a couple of things that can happen in
parseFuncDecl
and still return aParserResult<FuncDecl>
. The location of the parens is just the differentiator the situation where we expect a function decl and can't parse one. You might also get a nullparserRequest
in other situations.Maybe
parseFuncDecl
should be tighter in what it accepts and return null when it does not get a full declaration. I'm not sure right how if that change would break anything else though. The code is not that intricate but the effects could be large.I'm sort of assuming that the normal clients of
parseFuncDecl
want to get as much information as possible out of it, while for this specific problem we want to inhibit some of those situations in the probe to skip to our diagnostic.Does that make sense?