Skip to content

Commit eb539e6

Browse files
committed
Parse: Diagnose where clauses early on non-generic top-level declarations
1 parent a60ffb9 commit eb539e6

File tree

5 files changed

+51
-41
lines changed

5 files changed

+51
-41
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,10 +1650,9 @@ ERROR(redundant_class_requirement,none,
16501650
"redundant 'class' requirement", ())
16511651
ERROR(late_class_requirement,none,
16521652
"'class' must come first in the requirement list", ())
1653-
ERROR(where_without_generic_params,none,
1654-
"'where' clause cannot be attached to "
1655-
"%select{a non-generic|a protocol|an associated type}0 "
1656-
"declaration", (unsigned))
1653+
ERROR(where_toplevel_nongeneric,none,
1654+
"'where' clause cannot be attached to non-generic "
1655+
"top-level declaration", ())
16571656
ERROR(where_inside_brackets,none,
16581657
"'where' clause next to generic parameters is obsolete, "
16591658
"must be written following the declaration's type", ())

include/swift/Parse/Parser.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ class Parser {
10661066
bool allowClassRequirement,
10671067
bool allowAnyObject);
10681068
ParserStatus parseDeclItem(bool &PreviousHadSemi,
1069-
Parser::ParseDeclOptions Options,
1069+
ParseDeclOptions Options,
10701070
llvm::function_ref<void(Decl*)> handler);
10711071
std::pair<std::vector<Decl *>, Optional<std::string>>
10721072
parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag,
@@ -1634,14 +1634,10 @@ class Parser {
16341634
void
16351635
diagnoseWhereClauseInGenericParamList(const GenericParamList *GenericParams);
16361636

1637-
enum class WhereClauseKind : unsigned {
1638-
Declaration,
1639-
Protocol,
1640-
AssociatedType
1641-
};
16421637
ParserStatus
1643-
parseFreestandingGenericWhereClause(GenericParamList *GPList,
1644-
WhereClauseKind kind=WhereClauseKind::Declaration);
1638+
parseFreestandingGenericWhereClause(GenericContext *genCtx,
1639+
GenericParamList *&GPList,
1640+
ParseDeclOptions flags);
16451641

16461642
ParserStatus parseGenericWhereClause(
16471643
SourceLoc &WhereLoc, SmallVectorImpl<RequirementRepr> &Requirements,

lib/Parse/ParseDecl.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4424,7 +4424,7 @@ void Parser::diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc,
44244424

44254425
/// Parse a Decl item in decl list.
44264426
ParserStatus Parser::parseDeclItem(bool &PreviousHadSemi,
4427-
Parser::ParseDeclOptions Options,
4427+
ParseDeclOptions Options,
44284428
llvm::function_ref<void(Decl*)> handler) {
44294429
if (Tok.is(tok::semi)) {
44304430
// Consume ';' without preceding decl.
@@ -5008,7 +5008,7 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) {
50085008
// Parse a 'where' clause if present, adding it to our GenericParamList.
50095009
if (Tok.is(tok::kw_where)) {
50105010
ContextChange CC(*this, TAD);
5011-
Status |= parseFreestandingGenericWhereClause(genericParams);
5011+
Status |= parseFreestandingGenericWhereClause(TAD, genericParams, Flags);
50125012
}
50135013

50145014
if (UnderlyingTy.isNull()) {
@@ -6348,7 +6348,7 @@ ParserResult<FuncDecl> Parser::parseDeclFunc(SourceLoc StaticLoc,
63486348
if (Tok.is(tok::kw_where)) {
63496349
ContextChange CC(*this, FD);
63506350

6351-
Status |= parseFreestandingGenericWhereClause(GenericParams);
6351+
Status |= parseFreestandingGenericWhereClause(FD, GenericParams, Flags);
63526352
if (Status.hasCodeCompletion() && !CodeCompletion) {
63536353
// Trigger delayed parsing, no need to continue.
63546354
return Status;
@@ -6603,12 +6603,13 @@ ParserResult<EnumDecl> Parser::parseDeclEnum(ParseDeclOptions Flags,
66036603

66046604
// Parse a 'where' clause if present, adding it to our GenericParamList.
66056605
if (Tok.is(tok::kw_where)) {
6606-
auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
6607-
Status |= whereStatus;
6606+
auto whereStatus =
6607+
parseFreestandingGenericWhereClause(ED, GenericParams, Flags);
66086608
if (whereStatus.hasCodeCompletion() && !CodeCompletion) {
66096609
// Trigger delayed parsing, no need to continue.
66106610
return whereStatus;
66116611
}
6612+
Status |= whereStatus;
66126613
}
66136614

66146615
SyntaxParsingContext BlockContext(SyntaxContext, SyntaxKind::MemberDeclBlock);
@@ -6889,12 +6890,13 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
68896890

68906891
// Parse a 'where' clause if present, adding it to our GenericParamList.
68916892
if (Tok.is(tok::kw_where)) {
6892-
auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
6893-
Status |= whereStatus;
6893+
auto whereStatus =
6894+
parseFreestandingGenericWhereClause(SD, GenericParams, Flags);
68946895
if (whereStatus.hasCodeCompletion() && !CodeCompletion) {
68956896
// Trigger delayed parsing, no need to continue.
68966897
return whereStatus;
68976898
}
6899+
Status |= whereStatus;
68986900
}
68996901

69006902
// Make the entities of the struct as a code block.
@@ -7005,12 +7007,13 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
70057007

70067008
// Parse a 'where' clause if present, adding it to our GenericParamList.
70077009
if (Tok.is(tok::kw_where)) {
7008-
auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
7009-
Status |= whereStatus;
7010+
auto whereStatus =
7011+
parseFreestandingGenericWhereClause(CD, GenericParams, Flags);
70107012
if (whereStatus.hasCodeCompletion() && !CodeCompletion) {
70117013
// Trigger delayed parsing, no need to continue.
70127014
return whereStatus;
70137015
}
7016+
Status |= whereStatus;
70147017
}
70157018

70167019
SyntaxParsingContext BlockContext(SyntaxContext, SyntaxKind::MemberDeclBlock);
@@ -7257,7 +7260,8 @@ Parser::parseDeclSubscript(SourceLoc StaticLoc,
72577260
if (Tok.is(tok::kw_where)) {
72587261
ContextChange CC(*this, Subscript);
72597262

7260-
Status |= parseFreestandingGenericWhereClause(GenericParams);
7263+
Status |= parseFreestandingGenericWhereClause(Subscript, GenericParams,
7264+
Flags);
72617265
if (Status.hasCodeCompletion() && !CodeCompletion) {
72627266
// Trigger delayed parsing, no need to continue.
72637267
return Status;
@@ -7399,7 +7403,7 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
73997403
if (Tok.is(tok::kw_where)) {
74007404
ContextChange(*this, CD);
74017405

7402-
Status |= parseFreestandingGenericWhereClause(GenericParams);
7406+
Status |= parseFreestandingGenericWhereClause(CD, GenericParams, Flags);
74037407
if (Status.hasCodeCompletion() && !CodeCompletion) {
74047408
// Trigger delayed parsing, no need to continue.
74057409
return Status;

lib/Parse/ParseGeneric.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -395,18 +395,11 @@ ParserStatus Parser::parseGenericWhereClause(
395395
/// Parse a free-standing where clause attached to a declaration, adding it to
396396
/// a generic parameter list that may (or may not) already exist.
397397
ParserStatus Parser::
398-
parseFreestandingGenericWhereClause(GenericParamList *genericParams,
399-
WhereClauseKind kind) {
398+
parseFreestandingGenericWhereClause(GenericContext *genCtx,
399+
GenericParamList *&genericParams,
400+
ParseDeclOptions flags) {
400401
assert(Tok.is(tok::kw_where) && "Shouldn't call this without a where");
401-
402-
// Push the generic arguments back into a local scope so that references will
403-
// find them.
404-
Scope S(this, ScopeKind::Generics);
405-
406-
if (genericParams)
407-
for (auto pd : genericParams->getParams())
408-
addToScope(pd);
409-
402+
410403
SmallVector<RequirementRepr, 4> Requirements;
411404
SourceLoc WhereLoc;
412405
bool FirstTypeInComplete;
@@ -415,10 +408,23 @@ parseFreestandingGenericWhereClause(GenericParamList *genericParams,
415408
if (result.shouldStopParsing() || Requirements.empty())
416409
return result;
417410

418-
if (!genericParams)
419-
diagnose(WhereLoc, diag::where_without_generic_params, unsigned(kind));
420-
else
411+
if (genericParams) {
412+
// Push the generic arguments back into a local scope so that references will
413+
// find them.
414+
Scope S(this, ScopeKind::Generics);
415+
for (auto pd : genericParams->getParams())
416+
addToScope(pd);
417+
421418
genericParams->addTrailingWhereClause(Context, WhereLoc, Requirements);
419+
420+
// A where clause that references only outer generic parameters?
421+
} else if (flags.contains(PD_HasContainerType)) {
422+
genCtx->setTrailingWhereClause(
423+
TrailingWhereClause::create(Context, WhereLoc, Requirements));
424+
} else {
425+
diagnose(WhereLoc, diag::where_toplevel_nongeneric);
426+
}
427+
422428
return ParserStatus();
423429
}
424430

test/Generics/invalid.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
// RUN: %target-typecheck-verify-swift
22

3-
func bet() where A : B {} // expected-error {{'where' clause cannot be attached to a non-generic declaration}}
3+
func bet() where A : B {} // expected-error {{'where' clause cannot be attached to non-generic top-level declaration}}
44

5-
typealias gimel where A : B // expected-error {{'where' clause cannot be attached to a non-generic declaration}}
6-
// expected-error@-1 {{expected '=' in type alias declaration}}
5+
typealias gimel = Int where A : B // expected-error {{'where' clause cannot be attached to non-generic top-level declaration}}
76

8-
class dalet where A : B {} // expected-error {{'where' clause cannot be attached to a non-generic declaration}}
7+
class dalet where A : B {} // expected-error {{'where' clause cannot be attached to non-generic top-level declaration}}
8+
9+
struct Where {
10+
func bet() where A == B {} // expected-error {{'where' clause on non-generic member declaration requires a generic context}}
11+
typealias gimel = Int where A : B // expected-error {{'where' clause on non-generic member declaration requires a generic context}}
12+
class dalet where A : B {} // expected-error {{'where' clause on non-generic member declaration requires a generic context}}
13+
}
914

1015
protocol he where A : B { // expected-error {{use of undeclared type 'A'}}
1116
// expected-error@-1 {{use of undeclared type 'B'}}

0 commit comments

Comments
 (0)