Skip to content

Commit 18f5f94

Browse files
committed
Sema: Check for duplicate parameter and generic parameter names when parser lookup is off
The existing redeclaration checking can be extended for declarations in local scope, but it won't catch these.
1 parent d585838 commit 18f5f94

File tree

5 files changed

+162
-19
lines changed

5 files changed

+162
-19
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3206,12 +3206,6 @@ void AttributeChecker::visitNonEphemeralAttr(NonEphemeralAttr *attr) {
32063206
attr->setInvalid();
32073207
}
32083208

3209-
void TypeChecker::checkParameterAttributes(ParameterList *params) {
3210-
for (auto param: *params) {
3211-
checkDeclAttributes(param);
3212-
}
3213-
}
3214-
32153209
void AttributeChecker::checkOriginalDefinedInAttrs(Decl *D,
32163210
ArrayRef<OriginallyDefinedInAttr*> Attrs) {
32173211
if (Attrs.empty())

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,28 @@ static void checkForEmptyOptionSet(const VarDecl *VD) {
397397
.fixItReplace(args->getSourceRange(), "([])");
398398
}
399399

400+
template<typename T>
401+
static void diagnoseDuplicateDecls(const T &decls) {
402+
llvm::SmallDenseMap<DeclBaseName, const ValueDecl *> names;
403+
for (auto *current : decls) {
404+
if (!current->getASTContext().LangOpts.DisableParserLookup)
405+
return;
406+
407+
if (!current->hasName() || current->isImplicit())
408+
continue;
409+
410+
auto found = names.insert(std::make_pair(current->getBaseName(), current));
411+
if (!found.second) {
412+
auto *other = found.first->second;
413+
414+
current->getASTContext().Diags.diagnoseWithNotes(
415+
current->diagnose(diag::invalid_redecl,
416+
current->getName()), [&]() {
417+
other->diagnose(diag::invalid_redecl_prev, other->getName());
418+
});
419+
}
420+
}
421+
}
400422

401423
/// Check the inheritance clauses generic parameters along with any
402424
/// requirements stored within the generic parameter list.
@@ -410,10 +432,13 @@ static void checkGenericParams(GenericContext *ownerCtx) {
410432
checkInheritanceClause(gp);
411433
}
412434

413-
// Force visitation of each of the requirements here.
435+
// Force resolution of interface types written in requirements here.
414436
WhereClauseOwner(ownerCtx)
415437
.visitRequirements(TypeResolutionStage::Interface,
416438
[](Requirement, RequirementRepr *) { return false; });
439+
440+
// Check for duplicate generic parameter names.
441+
diagnoseDuplicateDecls(*genericParams);
417442
}
418443

419444
template <typename T>
@@ -1288,6 +1313,22 @@ static void maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl) {
12881313
diagnoseClassWithoutInitializers(classDecl);
12891314
}
12901315

1316+
void TypeChecker::checkParameterList(ParameterList *params) {
1317+
for (auto param: *params) {
1318+
checkDeclAttributes(param);
1319+
}
1320+
1321+
// Check for duplicate parameter names.
1322+
diagnoseDuplicateDecls(*params);
1323+
}
1324+
1325+
void TypeChecker::diagnoseDuplicateBoundVars(Pattern *pattern) {
1326+
SmallVector<VarDecl *, 2> boundVars;
1327+
pattern->collectVariables(boundVars);
1328+
1329+
diagnoseDuplicateDecls(boundVars);
1330+
}
1331+
12911332
namespace {
12921333
class DeclChecker : public DeclVisitor<DeclChecker> {
12931334
public:
@@ -1709,7 +1750,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
17091750
(void) SD->isSetterMutating();
17101751
(void) SD->getImplInfo();
17111752

1712-
TypeChecker::checkParameterAttributes(SD->getIndices());
1753+
TypeChecker::checkParameterList(SD->getIndices());
17131754

17141755
checkDefaultArguments(SD->getIndices());
17151756

@@ -1735,6 +1776,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
17351776

17361777
TypeChecker::checkDeclAttributes(TAD);
17371778
checkAccessControl(TAD);
1779+
checkGenericParams(TAD);
17381780
}
17391781

17401782
void visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) {
@@ -2260,15 +2302,18 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22602302
(void) FD->getOperatorDecl();
22612303
(void) FD->getDynamicallyReplacedDecl();
22622304

2263-
if (!FD->isInvalid()) {
2264-
checkGenericParams(FD);
2265-
TypeChecker::checkReferencedGenericParams(FD);
2266-
TypeChecker::checkProtocolSelfRequirements(FD);
2267-
}
2305+
if (!isa<AccessorDecl>(FD)) {
2306+
if (!FD->isInvalid()) {
2307+
checkGenericParams(FD);
2308+
TypeChecker::checkReferencedGenericParams(FD);
2309+
TypeChecker::checkProtocolSelfRequirements(FD);
2310+
}
22682311

2269-
checkAccessControl(FD);
2312+
checkAccessControl(FD);
2313+
2314+
TypeChecker::checkParameterList(FD->getParameters());
2315+
}
22702316

2271-
TypeChecker::checkParameterAttributes(FD->getParameters());
22722317
TypeChecker::checkDeclAttributes(FD);
22732318

22742319
if (!checkOverrides(FD)) {
@@ -2376,7 +2421,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
23762421
TypeChecker::checkDeclAttributes(EED);
23772422

23782423
if (auto *PL = EED->getParameterList()) {
2379-
TypeChecker::checkParameterAttributes(PL);
2424+
TypeChecker::checkParameterList(PL);
23802425

23812426
checkDefaultArguments(PL);
23822427
}
@@ -2532,7 +2577,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
25322577
}
25332578

25342579
TypeChecker::checkDeclAttributes(CD);
2535-
TypeChecker::checkParameterAttributes(CD->getParameters());
2580+
TypeChecker::checkParameterList(CD->getParameters());
25362581

25372582
// Check whether this initializer overrides an initializer in its
25382583
// superclass.

lib/Sema/TypeCheckStmt.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,8 @@ static bool typeCheckConditionForStatement(LabeledConditionalStmt *stmt,
504504
}
505505
elt.setPattern(pattern);
506506

507+
TypeChecker::diagnoseDuplicateBoundVars(pattern);
508+
507509
// Check the pattern, it allows unspecified types because the pattern can
508510
// provide type information.
509511
auto contextualPattern = ContextualPattern::forRawPattern(pattern, dc);
@@ -956,6 +958,8 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
956958
if (TypeChecker::typeCheckForEachBinding(DC, S))
957959
return nullptr;
958960

961+
TypeChecker::diagnoseDuplicateBoundVars(S->getPattern());
962+
959963
// Type-check the body of the loop.
960964
auto sourceFile = DC->getParentSourceFile();
961965
checkLabeledStmtShadowing(getASTContext(), sourceFile, S);
@@ -1032,6 +1036,8 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
10321036
}
10331037
labelItem.setPattern(pattern, /*resolved=*/true);
10341038

1039+
TypeChecker::diagnoseDuplicateBoundVars(pattern);
1040+
10351041
// Otherwise for each variable in the pattern, make sure its type is
10361042
// identical to the initial case decl and stash the previous case decl as
10371043
// the parent of the decl.
@@ -2039,7 +2045,7 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
20392045
}
20402046

20412047
bool TypeChecker::typeCheckClosureBody(ClosureExpr *closure) {
2042-
checkParameterAttributes(closure->getParameters());
2048+
TypeChecker::checkParameterList(closure->getParameters());
20432049

20442050
BraceStmt *body = closure->getBody();
20452051

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,9 @@ void typeCheckDecl(Decl *D);
497497

498498
void addImplicitDynamicAttribute(Decl *D);
499499
void checkDeclAttributes(Decl *D);
500-
void checkParameterAttributes(ParameterList *params);
500+
void checkParameterList(ParameterList *params);
501+
502+
void diagnoseDuplicateBoundVars(Pattern *pattern);
501503

502504
Type checkReferenceOwnershipAttr(VarDecl *D, Type interfaceType,
503505
ReferenceOwnershipAttr *attr);
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// RUN: %target-typecheck-verify-swift -disable-parser-lookup
2+
3+
// Test redeclaration checking in local context.
4+
5+
func test1() {
6+
let x = 123 // expected-note{{'x' previously declared here}}
7+
func f() {} // expected-note{{'f()' previously declared here}}
8+
struct S {} // expected-note{{'S' previously declared here}}
9+
let x = 321 // expected-error{{invalid redeclaration of 'x'}}
10+
func f() {} // expected-error{{invalid redeclaration of 'f()'}}
11+
struct S {} // expected-error{{invalid redeclaration of 'S'}}
12+
}
13+
14+
func test2() {
15+
let x = 123 // expected-warning {{never used}}
16+
func f() {}
17+
struct S {}
18+
do {
19+
let x = 321 // expected-warning {{never used}}
20+
func f() {}
21+
struct S {}
22+
}
23+
}
24+
25+
func test3<T, T>(_: T, _: T) {}
26+
// expected-note@-1 {{'T' previously declared here}}
27+
// expected-error@-2 {{invalid redeclaration of 'T'}}
28+
// expected-error@-3 {{generic parameter 'T' is not used in function signature}}
29+
30+
func test4(x: Int, x: Int) {}
31+
// expected-note@-1 {{'x' previously declared here}}
32+
// expected-error@-2 {{invalid redeclaration of 'x'}}
33+
34+
struct Test4<T, T> {}
35+
// expected-note@-1 {{'T' previously declared here}}
36+
// expected-error@-2 {{invalid redeclaration of 'T'}}
37+
38+
typealias Test5<T, T> = ()
39+
// expected-note@-1 {{'T' previously declared here}}
40+
// expected-error@-2 {{invalid redeclaration of 'T'}}
41+
42+
enum E {
43+
case test6(x: Int, x: Int)
44+
// expected-note@-1 {{'x' previously declared here}}
45+
// expected-error@-2 {{invalid redeclaration of 'x'}}
46+
47+
subscript(x: Int, x: Int) -> Int { return 0 }
48+
// expected-note@-1 {{'x' previously declared here}}
49+
// expected-error@-2 {{invalid redeclaration of 'x'}}
50+
}
51+
52+
_ = { (x: Int, x: Int) in }
53+
// expected-note@-1 {{'x' previously declared here}}
54+
// expected-error@-2 {{invalid redeclaration of 'x'}}
55+
56+
enum MyError : Error {
57+
case error(Int, Int)
58+
}
59+
60+
func stmtTest() {
61+
let n: (Int, Int)? = nil
62+
63+
if case (let x, let x)? = n {}
64+
// expected-note@-1 {{'x' previously declared here}}
65+
// expected-error@-2 {{invalid redeclaration of 'x'}}
66+
// expected-warning@-3 2{{never used}}
67+
68+
for case (let x, let x) in [(Int, Int)]() {}
69+
// expected-note@-1 {{'x' previously declared here}}
70+
// expected-error@-2 {{invalid redeclaration of 'x'}}
71+
// expected-warning@-3 2{{never used}}
72+
73+
switch n {
74+
case (let x, let x)?: _ = ()
75+
// expected-note@-1 {{'x' previously declared here}}
76+
// expected-error@-2 {{invalid redeclaration of 'x'}}
77+
// expected-warning@-3 2{{never used}}
78+
case nil: _ = ()
79+
}
80+
81+
while case (let x, let x)? = n {}
82+
// expected-note@-1 {{'x' previously declared here}}
83+
// expected-error@-2 {{invalid redeclaration of 'x'}}
84+
// expected-warning@-3 2{{never used}}
85+
86+
guard case (let x, let x)? = n else {}
87+
// expected-note@-1 {{'x' previously declared here}}
88+
// expected-error@-2 {{invalid redeclaration of 'x'}}
89+
// expected-warning@-3 2{{never used}}
90+
91+
do {} catch MyError.error(let x, let x) {}
92+
// expected-note@-1 {{'x' previously declared here}}
93+
// expected-error@-2 {{invalid redeclaration of 'x'}}
94+
// expected-warning@-3 2{{never used}}
95+
// expected-warning@-4 {{unreachable}}
96+
}

0 commit comments

Comments
 (0)