2
2
//
3
3
// This source file is part of the Swift.org open source project
4
4
//
5
- // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
5
+ // Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6
6
// Licensed under Apache License v2.0 with Runtime Library Exception
7
7
//
8
8
// See https://swift.org/LICENSE.txt for license information
@@ -2766,6 +2766,7 @@ void Parser::delayParseFromBeginningToHere(ParserPosition BeginParserPosition,
2766
2766
// / \endverbatim
2767
2767
ParserResult<Decl>
2768
2768
Parser::parseDecl (ParseDeclOptions Flags,
2769
+ bool IsAtStartOfLineOrPreviousHadSemi,
2769
2770
llvm::function_ref<void (Decl*)> Handler) {
2770
2771
ParserPosition BeginParserPosition;
2771
2772
if (isCodeCompletionFirstPass ())
@@ -2854,6 +2855,30 @@ Parser::parseDecl(ParseDeclOptions Flags,
2854
2855
auto OrigTok = Tok;
2855
2856
bool MayNeedOverrideCompletion = false ;
2856
2857
2858
+ auto parseLetOrVar = [&](bool HasLetOrVarKeyword) {
2859
+ // Collect all modifiers into a modifier list.
2860
+ DeclParsingContext.setCreateSyntax (SyntaxKind::VariableDecl);
2861
+ llvm::SmallVector<Decl *, 4 > Entries;
2862
+ DeclResult = parseDeclVar (Flags, Attributes, Entries, StaticLoc,
2863
+ StaticSpelling, tryLoc, HasLetOrVarKeyword);
2864
+ StaticLoc = SourceLoc (); // we handled static if present.
2865
+ MayNeedOverrideCompletion = true ;
2866
+ if (DeclResult.hasCodeCompletion () && isCodeCompletionFirstPass ())
2867
+ return ;
2868
+ std::for_each (Entries.begin (), Entries.end (), Handler);
2869
+ if (auto *D = DeclResult.getPtrOrNull ())
2870
+ markWasHandled (D);
2871
+ };
2872
+
2873
+ auto parseFunc = [&](bool HasFuncKeyword) {
2874
+ // Collect all modifiers into a modifier list.
2875
+ DeclParsingContext.setCreateSyntax (SyntaxKind::FunctionDecl);
2876
+ DeclResult = parseDeclFunc (StaticLoc, StaticSpelling, Flags, Attributes,
2877
+ HasFuncKeyword);
2878
+ StaticLoc = SourceLoc (); // we handled static if present.
2879
+ MayNeedOverrideCompletion = true ;
2880
+ };
2881
+
2857
2882
switch (Tok.getKind ()) {
2858
2883
case tok::kw_import:
2859
2884
DeclParsingContext.setCreateSyntax (SyntaxKind::ImportDecl);
@@ -2865,18 +2890,7 @@ Parser::parseDecl(ParseDeclOptions Flags,
2865
2890
break ;
2866
2891
case tok::kw_let:
2867
2892
case tok::kw_var: {
2868
- // Collect all modifiers into a modifier list.
2869
- DeclParsingContext.setCreateSyntax (SyntaxKind::VariableDecl);
2870
- llvm::SmallVector<Decl *, 4 > Entries;
2871
- DeclResult = parseDeclVar (Flags, Attributes, Entries, StaticLoc,
2872
- StaticSpelling, tryLoc);
2873
- StaticLoc = SourceLoc (); // we handled static if present.
2874
- MayNeedOverrideCompletion = true ;
2875
- if (DeclResult.hasCodeCompletion () && isCodeCompletionFirstPass ())
2876
- break ;
2877
- std::for_each (Entries.begin (), Entries.end (), Handler);
2878
- if (auto *D = DeclResult.getPtrOrNull ())
2879
- markWasHandled (D);
2893
+ parseLetOrVar (/* HasLetOrVarKeyword=*/ true );
2880
2894
break ;
2881
2895
}
2882
2896
case tok::kw_typealias:
@@ -2932,11 +2946,7 @@ Parser::parseDecl(ParseDeclOptions Flags,
2932
2946
DeclResult = parseDeclProtocol (Flags, Attributes);
2933
2947
break ;
2934
2948
case tok::kw_func:
2935
- // Collect all modifiers into a modifier list.
2936
- DeclParsingContext.setCreateSyntax (SyntaxKind::FunctionDecl);
2937
- DeclResult = parseDeclFunc (StaticLoc, StaticSpelling, Flags, Attributes);
2938
- StaticLoc = SourceLoc (); // we handled static if present.
2939
- MayNeedOverrideCompletion = true ;
2949
+ parseFunc (/* HasFuncKeyword=*/ true );
2940
2950
break ;
2941
2951
case tok::kw_subscript: {
2942
2952
DeclParsingContext.setCreateSyntax (SyntaxKind::SubscriptDecl);
@@ -2982,6 +2992,77 @@ Parser::parseDecl(ParseDeclOptions Flags,
2982
2992
2983
2993
// Obvious nonsense.
2984
2994
default :
2995
+
2996
+ if (Flags.contains (PD_HasContainerType) &&
2997
+ IsAtStartOfLineOrPreviousHadSemi) {
2998
+
2999
+ // Emit diagnostics if we meet an identifier/operator where a declaration
3000
+ // is expected, perhaps the user forgot the 'func' or 'var' keyword.
3001
+ //
3002
+ // Must not confuse it with trailing closure syntax, so we only
3003
+ // recover in contexts where there can be no statements.
3004
+
3005
+ const bool IsProbablyVarDecl =
3006
+ Tok.isIdentifierOrUnderscore () &&
3007
+ peekToken ().isAny (tok::colon, tok::equal, tok::comma);
3008
+
3009
+ const bool IsProbablyTupleDecl =
3010
+ Tok.is (tok::l_paren) && peekToken ().isIdentifierOrUnderscore ();
3011
+
3012
+ if (IsProbablyVarDecl || IsProbablyTupleDecl) {
3013
+
3014
+ DescriptiveDeclKind DescriptiveKind;
3015
+
3016
+ switch (StaticSpelling) {
3017
+ case StaticSpellingKind::None:
3018
+ DescriptiveKind = DescriptiveDeclKind::Property;
3019
+ break ;
3020
+ case StaticSpellingKind::KeywordStatic:
3021
+ DescriptiveKind = DescriptiveDeclKind::StaticProperty;
3022
+ break ;
3023
+ case StaticSpellingKind::KeywordClass:
3024
+ llvm_unreachable (" kw_class is only parsed as a modifier if it's "
3025
+ " followed by a keyword" );
3026
+ }
3027
+
3028
+ diagnose (Tok.getLoc (), diag::expected_keyword_in_decl, " var" ,
3029
+ DescriptiveKind)
3030
+ .fixItInsert (Tok.getLoc (), " var " );
3031
+ parseLetOrVar (/* HasLetOrVarKeyword=*/ false );
3032
+ break ;
3033
+ }
3034
+
3035
+ const bool IsProbablyFuncDecl =
3036
+ Tok.isIdentifierOrUnderscore () || Tok.isAnyOperator ();
3037
+
3038
+ if (IsProbablyFuncDecl) {
3039
+
3040
+ DescriptiveDeclKind DescriptiveKind;
3041
+
3042
+ if (Tok.isAnyOperator ()) {
3043
+ DescriptiveKind = DescriptiveDeclKind::OperatorFunction;
3044
+ } else {
3045
+ switch (StaticSpelling) {
3046
+ case StaticSpellingKind::None:
3047
+ DescriptiveKind = DescriptiveDeclKind::Method;
3048
+ break ;
3049
+ case StaticSpellingKind::KeywordStatic:
3050
+ DescriptiveKind = DescriptiveDeclKind::StaticMethod;
3051
+ break ;
3052
+ case StaticSpellingKind::KeywordClass:
3053
+ llvm_unreachable (" kw_class is only parsed as a modifier if it's "
3054
+ " followed by a keyword" );
3055
+ }
3056
+ }
3057
+
3058
+ diagnose (Tok.getLoc (), diag::expected_keyword_in_decl, " func" ,
3059
+ DescriptiveKind)
3060
+ .fixItInsert (Tok.getLoc (), " func " );
3061
+ parseFunc (/* HasFuncKeyword=*/ false );
3062
+ break ;
3063
+ }
3064
+ }
3065
+
2985
3066
diagnose (Tok, diag::expected_decl);
2986
3067
2987
3068
if (CurDeclContext) {
@@ -3166,7 +3247,9 @@ void Parser::parseDeclDelayed() {
3166
3247
Scope S (this , DelayedState->takeScope ());
3167
3248
ContextChange CC (*this , DelayedState->ParentContext );
3168
3249
3169
- parseDecl (ParseDeclOptions (DelayedState->Flags ), [&](Decl *D) {
3250
+ parseDecl (ParseDeclOptions (DelayedState->Flags ),
3251
+ /* IsAtStartOfLineOrPreviousHadSemi=*/ true ,
3252
+ [&](Decl *D) {
3170
3253
if (auto *parent = DelayedState->ParentContext ) {
3171
3254
if (auto *NTD = dyn_cast<NominalTypeDecl>(parent)) {
3172
3255
NTD->addMember (D);
@@ -3517,7 +3600,9 @@ ParserStatus Parser::parseDeclItem(bool &PreviousHadSemi,
3517
3600
3518
3601
// If the previous declaration didn't have a semicolon and this new
3519
3602
// declaration doesn't start a line, complain.
3520
- if (!PreviousHadSemi && !Tok.isAtStartOfLine () && !Tok.is (tok::unknown)) {
3603
+ const bool IsAtStartOfLineOrPreviousHadSemi =
3604
+ PreviousHadSemi || Tok.isAtStartOfLine () || Tok.is (tok::unknown);
3605
+ if (!IsAtStartOfLineOrPreviousHadSemi) {
3521
3606
auto endOfPrevious = getEndOfPreviousLoc ();
3522
3607
diagnose (endOfPrevious, diag::declaration_same_line_without_semi)
3523
3608
.fixItInsert (endOfPrevious, " ;" );
@@ -3536,7 +3621,7 @@ ParserStatus Parser::parseDeclItem(bool &PreviousHadSemi,
3536
3621
if (loadCurrentSyntaxNodeFromCache ()) {
3537
3622
return ParserStatus ();
3538
3623
}
3539
- Result = parseDecl (Options, handler);
3624
+ Result = parseDecl (Options, IsAtStartOfLineOrPreviousHadSemi, handler);
3540
3625
if (Result.isParseError ())
3541
3626
skipUntilDeclRBrace (tok::semi, tok::pound_endif);
3542
3627
SourceLoc SemiLoc;
@@ -5134,7 +5219,8 @@ Parser::parseDeclVar(ParseDeclOptions Flags,
5134
5219
SmallVectorImpl<Decl *> &Decls,
5135
5220
SourceLoc StaticLoc,
5136
5221
StaticSpellingKind StaticSpelling,
5137
- SourceLoc TryLoc) {
5222
+ SourceLoc TryLoc,
5223
+ bool HasLetOrVarKeyword) {
5138
5224
assert (StaticLoc.isInvalid () || StaticSpelling != StaticSpellingKind::None);
5139
5225
5140
5226
if (StaticLoc.isValid ()) {
@@ -5152,9 +5238,11 @@ Parser::parseDeclVar(ParseDeclOptions Flags,
5152
5238
}
5153
5239
}
5154
5240
5155
- bool isLet = Tok.is (tok::kw_let);
5156
- assert (Tok.getKind () == tok::kw_let || Tok.getKind () == tok::kw_var);
5157
- SourceLoc VarLoc = consumeToken ();
5241
+ bool isLet = HasLetOrVarKeyword && Tok.is (tok::kw_let);
5242
+ assert (!HasLetOrVarKeyword || Tok.getKind () == tok::kw_let ||
5243
+ Tok.getKind () == tok::kw_var);
5244
+
5245
+ SourceLoc VarLoc = HasLetOrVarKeyword ? consumeToken () : Tok.getLoc ();
5158
5246
5159
5247
// If this is a var in the top-level of script/repl source file, wrap the
5160
5248
// PatternBindingDecl in a TopLevelCodeDecl, since it represents executable
@@ -5464,9 +5552,11 @@ void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD,
5464
5552
// / \endverbatim
5465
5553
// /
5466
5554
// / \note The caller of this method must ensure that the next token is 'func'.
5467
- ParserResult<FuncDecl>
5468
- Parser::parseDeclFunc (SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
5469
- ParseDeclOptions Flags, DeclAttributes &Attributes) {
5555
+ ParserResult<FuncDecl> Parser::parseDeclFunc (SourceLoc StaticLoc,
5556
+ StaticSpellingKind StaticSpelling,
5557
+ ParseDeclOptions Flags,
5558
+ DeclAttributes &Attributes,
5559
+ bool HasFuncKeyword) {
5470
5560
assert (StaticLoc.isInvalid () || StaticSpelling != StaticSpellingKind::None);
5471
5561
5472
5562
if (StaticLoc.isValid ()) {
@@ -5488,7 +5578,8 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
5488
5578
}
5489
5579
}
5490
5580
5491
- SourceLoc FuncLoc = consumeToken (tok::kw_func);
5581
+ SourceLoc FuncLoc =
5582
+ HasFuncKeyword ? consumeToken (tok::kw_func) : Tok.getLoc ();
5492
5583
5493
5584
// Parse function name.
5494
5585
Identifier SimpleName;
0 commit comments