Skip to content

Commit 7949224

Browse files
committed
Improve module selector type lookup diagnostics
1 parent ffaa358 commit 7949224

File tree

6 files changed

+149
-21
lines changed

6 files changed

+149
-21
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,10 @@ ERROR(cannot_find_type_in_cast_expression,none,
11911191
"type-casting operator expects a type on its right-hand side (got: %kind0)", (const ValueDecl *))
11921192
ERROR(cannot_find_type_in_scope_did_you_mean,none,
11931193
"cannot find type %0 in scope; did you mean to use '%1'?", (DeclNameRef, StringRef))
1194+
ERROR(wrong_module_selector,none,
1195+
"%0 is not imported through module %1", (DeclName, Identifier))
1196+
NOTE(note_change_module_selector,none,
1197+
"did you mean module %0?", (Identifier))
11941198
NOTE(note_typo_candidate_implicit_member,none,
11951199
"did you mean the implicitly-synthesized %kindbase0?", (const ValueDecl *))
11961200
NOTE(note_remapped_type,none,

include/swift/AST/NameLookup.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,18 @@ class LookupResult {
155155
: Results(Results.begin(), Results.end()),
156156
IndexOfFirstOuterResult(indexOfFirstOuterResult) {}
157157

158+
using const_iterator = SmallVectorImpl<LookupResultEntry>::const_iterator;
159+
const_iterator begin() const { return Results.begin(); }
160+
const_iterator end() const {
161+
return Results.begin() + IndexOfFirstOuterResult;
162+
}
163+
158164
using iterator = SmallVectorImpl<LookupResultEntry>::iterator;
159165
iterator begin() { return Results.begin(); }
160166
iterator end() {
161167
return Results.begin() + IndexOfFirstOuterResult;
162168
}
169+
163170
unsigned size() const { return innerResults().size(); }
164171
bool empty() const { return innerResults().empty(); }
165172

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,3 +1153,45 @@ void swift::diagnoseMissingImports(SourceFile &sf) {
11531153
}
11541154
}
11551155
}
1156+
1157+
ModuleSelectorCorrection::
1158+
ModuleSelectorCorrection(const LookupResult &candidates) {
1159+
// Produce a list of *unique* module selector diagnostics so we don't
1160+
// emit a bunch of duplicates.
1161+
for (auto result : candidates) {
1162+
ValueDecl * decl = result.getValueDecl();
1163+
auto owningModule = decl->getModuleContext();
1164+
candidateModules.insert(owningModule->getName());
1165+
}
1166+
}
1167+
1168+
ModuleSelectorCorrection::
1169+
ModuleSelectorCorrection(const LookupTypeResult &candidates) {
1170+
// Produce a list of *unique* module selector diagnostics so we don't
1171+
// emit a bunch of duplicates.
1172+
for (auto result : candidates) {
1173+
auto owningModule = result.Member->getModuleContext();
1174+
candidateModules.insert(owningModule->getName());
1175+
}
1176+
}
1177+
1178+
bool ModuleSelectorCorrection::diagnose(ASTContext &ctx,
1179+
DeclNameLoc nameLoc,
1180+
DeclNameRef originalName) const {
1181+
if (candidateModules.empty())
1182+
return false;
1183+
1184+
ctx.Diags.diagnose(nameLoc, diag::wrong_module_selector,
1185+
originalName.getFullName(),
1186+
originalName.getModuleSelector());
1187+
1188+
SourceLoc moduleSelectorLoc = nameLoc.getModuleSelectorLoc();
1189+
1190+
for (auto moduleName : candidateModules) {
1191+
ctx.Diags.diagnose(moduleSelectorLoc, diag::note_change_module_selector,
1192+
moduleName)
1193+
.fixItReplace(moduleSelectorLoc, moduleName.str());
1194+
}
1195+
1196+
return true;
1197+
}

lib/Sema/TypeCheckType.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,6 +1534,18 @@ static Type diagnoseUnknownType(const TypeResolution &resolution,
15341534
return ErrorType::get(ctx);
15351535
}
15361536

1537+
// Is there an incorrect module selector?
1538+
if (repr->getNameRef().hasModuleSelector()) {
1539+
auto anyModuleName = DeclNameRef(repr->getNameRef().getFullName());
1540+
ModuleSelectorCorrection correction(
1541+
TypeChecker::lookupUnqualifiedType(dc, anyModuleName, repr->getLoc(),
1542+
lookupOptions));
1543+
if (correction.diagnose(ctx, repr->getNameLoc(), repr->getNameRef())) {
1544+
// FIXME: Can we recover by assuming the first/best result is correct?
1545+
return ErrorType::get(ctx);
1546+
}
1547+
}
1548+
15371549
// Try ignoring access control.
15381550
NameLookupOptions relookupOptions = lookupOptions;
15391551
relookupOptions |= NameLookupFlags::IgnoreAccessControl;
@@ -1625,6 +1637,19 @@ static Type diagnoseUnknownType(const TypeResolution &resolution,
16251637
return ErrorType::get(ctx);
16261638
}
16271639

1640+
// Is there an incorrect module selector?
1641+
if (repr->getNameRef().hasModuleSelector()) {
1642+
auto anyModuleName = DeclNameRef(repr->getNameRef().getFullName());
1643+
ModuleSelectorCorrection correction(
1644+
TypeChecker::lookupMemberType(dc, parentType, anyModuleName,
1645+
repr->getLoc(), lookupOptions));
1646+
1647+
if (correction.diagnose(ctx, repr->getNameLoc(), repr->getNameRef())) {
1648+
// FIXME: Can we recover by assuming the first/best result is correct?
1649+
return ErrorType::get(ctx);
1650+
}
1651+
}
1652+
16281653
// Try ignoring access control.
16291654
NameLookupOptions relookupOptions = lookupOptions;
16301655
relookupOptions |= NameLookupFlags::IgnoreAccessControl;

lib/Sema/TypeChecker.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,14 @@ class LookupTypeResult {
9595
SmallVector<LookupTypeResultEntry, 4> Results;
9696

9797
public:
98+
using const_iterator = SmallVectorImpl<LookupTypeResultEntry>::const_iterator;
99+
const_iterator begin() const { return Results.begin(); }
100+
const_iterator end() const { return Results.end(); }
101+
98102
using iterator = SmallVectorImpl<LookupTypeResultEntry>::iterator;
99103
iterator begin() { return Results.begin(); }
100104
iterator end() { return Results.end(); }
105+
101106
unsigned size() const { return Results.size(); }
102107

103108
LookupTypeResultEntry operator[](unsigned index) const {
@@ -299,6 +304,29 @@ class CheckGenericArgumentsResult {
299304
CheckRequirementsResult getKind() const { return Kind; }
300305
};
301306

307+
/// Helper type for diagnosing a lookup that failed merely because it was
308+
/// restricted by a module selector.
309+
///
310+
/// To use this, perform the lookup again without its module selector and
311+
/// construct a \c ModuleSelectorCorrection from the lookup result. If
312+
/// there are any results, the \c diagnose() method will emit an error and a
313+
/// set of fix-it notes.
314+
class ModuleSelectorCorrection {
315+
using CandidateModule = Identifier;
316+
SmallSetVector<CandidateModule, 4> candidateModules;
317+
318+
public:
319+
ModuleSelectorCorrection(const LookupResult &candidates);
320+
ModuleSelectorCorrection(const LookupTypeResult &candidates);
321+
322+
/// Emit an error and warnings if there were any candidates.
323+
///
324+
/// \returns \c true if an error was diagnosed.
325+
bool diagnose(ASTContext &ctx,
326+
DeclNameLoc nameLoc,
327+
DeclNameRef originalName) const;
328+
};
329+
302330
/// Describes the kind of checked cast operation being performed.
303331
enum class CheckedCastContextKind {
304332
/// None: we're just establishing how to perform the checked cast. This

test/NameLookup/module_selector.swift

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,23 @@ extension A: @retroactive Swift::Equatable {
6969
// Test resolution of main:: using `B`
7070

7171
extension main::B {}
72-
// FIXME improve: expected-error@-1 {{cannot find type 'main::B' in scope}}
72+
// expected-error@-1 {{'B' is not imported through module 'main'}}
73+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{11-15=ModuleSelectorTestingKit}}
7374

7475
extension B: @retroactive main::Equatable {
75-
// FIXME improve: expected-error@-1 {{cannot find type 'main::Equatable' in scope}}
76+
// expected-error@-1 {{'Equatable' is not imported through module 'main'}}
77+
// expected-note@-2 {{did you mean module 'Swift'?}} {{27-31=Swift}}
7678

7779
@_implements(main::Equatable, ==(_:_:))
78-
// FIXME improve: expected-error@-1 {{cannot find type 'main::Equatable' in scope}}
80+
// expected-error@-1 {{'Equatable' is not imported through module 'main'}}
81+
// expected-note@-2 {{did you mean module 'Swift'?}} {{16-20=Swift}}
7982

8083
public static func equals(_: main::B, _: main::B) -> main::Bool {
81-
// FIXME improve: expected-error@-1 {{cannot find type 'main::B' in scope}}
82-
// FIXME improve: expected-error@-2 {{cannot find type 'main::B' in scope}}
83-
// FIXME improve: expected-error@-3 {{cannot find type 'main::Bool' in scope}}
84+
// expected-error@-1 2{{'B' is not imported through module 'main'}}
85+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{32-36=ModuleSelectorTestingKit}}
86+
// expected-note@-3 {{did you mean module 'ModuleSelectorTestingKit'?}} {{44-48=ModuleSelectorTestingKit}}
87+
// expected-error@-4 {{'Bool' is not imported through module 'main'}}
88+
// expected-note@-5 {{did you mean module 'Swift'?}} {{56-60=Swift}}
8489
main::fatalError()
8590
// FIXME improve: expected-error@-1 {{cannot find 'main::fatalError' in scope}}
8691
}
@@ -93,12 +98,16 @@ extension B: @retroactive main::Equatable {
9398

9499
mutating func myNegate() {
95100
let fn: (main::Int, main::Int) -> main::Int =
96-
// FIXME improve: expected-error@-1 3{{cannot find type 'main::Int' in scope}}
101+
// expected-error@-1 3{{'Int' is not imported through module 'main'}}
102+
// expected-note@-2 {{did you mean module 'Swift'?}} {{14-18=Swift}}
103+
// expected-note@-3 {{did you mean module 'Swift'?}} {{25-29=Swift}}
104+
// expected-note@-4 {{did you mean module 'Swift'?}} {{39-43=Swift}}
97105
(main::+)
98106
// FIXME improve: expected-error@-1 {{cannot find operator 'main::+' in scope}}
99107

100108
let magnitude: Int.main::Magnitude = main::magnitude
101-
// FIXME improve: expected-error@-1 {{'main::Magnitude' is not a member type of struct 'Swift.Int'}}
109+
// expected-error@-1 {{'Magnitude' is not imported through module 'main'}}
110+
// expected-note@-2 {{did you mean module 'Swift'?}} {{24-28=Swift}}
102111

103112
_ = (fn, magnitude)
104113

@@ -124,7 +133,8 @@ extension B: @retroactive main::Equatable {
124133
// FIXME improve: expected-error@-1 {{cannot find 'main::fatalError' in scope}}
125134

126135
_ = \main::A.magnitude
127-
// FIXME improve: expected-error@-1 {{'main::A' in scope}} -- different diagnostic wording for legacy parser vs. ASTGen
136+
// expected-error@-1 {{'A' is not imported through module 'main'}}
137+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{10-14=ModuleSelectorTestingKit}}
128138
_ = \A.main::magnitude
129139
// FIXME improve: expected-error@-1 {{value of type 'A' has no member 'main::magnitude'}}
130140

@@ -143,13 +153,16 @@ extension B: @retroactive main::Equatable {
143153
extension ModuleSelectorTestingKit::C {}
144154

145155
extension C: @retroactive ModuleSelectorTestingKit::Equatable {
146-
// FIXME improve: expected-error@-1 {{cannot find type 'ModuleSelectorTestingKit::Equatable' in scope}}
156+
// expected-error@-1 {{'Equatable' is not imported through module 'ModuleSelectorTestingKit'}}
157+
// expected-note@-2 {{did you mean module 'Swift'?}} {{27-51=Swift}}
147158

148159
@_implements(ModuleSelectorTestingKit::Equatable, ==(_:_:))
149-
// FIXME improve: expected-error@-1 {{cannot find type 'ModuleSelectorTestingKit::Equatable' in scope}}
160+
// expected-error@-1 {{'Equatable' is not imported through module 'ModuleSelectorTestingKit'}}
161+
// expected-note@-2 {{did you mean module 'Swift'?}} {{16-40=Swift}}
150162

151163
public static func equals(_: ModuleSelectorTestingKit::C, _: ModuleSelectorTestingKit::C) -> ModuleSelectorTestingKit::Bool {
152-
// FIXME improve: expected-error@-1 {{cannot find type 'ModuleSelectorTestingKit::Bool' in scope}}
164+
// expected-error@-1 {{'Bool' is not imported through module 'ModuleSelectorTestingKit'}}
165+
// expected-note@-2 {{did you mean module 'Swift'?}} {{96-120=Swift}}
153166

154167
ModuleSelectorTestingKit::fatalError()
155168
// FIXME improve: expected-error@-1 {{cannot find 'ModuleSelectorTestingKit::fatalError' in scope}}
@@ -162,13 +175,17 @@ extension C: @retroactive ModuleSelectorTestingKit::Equatable {
162175

163176
mutating func myNegate() {
164177
let fn: (ModuleSelectorTestingKit::Int, ModuleSelectorTestingKit::Int) -> ModuleSelectorTestingKit::Int =
165-
// FIXME improve: expected-error@-1 3{{cannot find type 'ModuleSelectorTestingKit::Int' in scope}}
178+
// expected-error@-1 3{{'Int' is not imported through module 'ModuleSelectorTestingKit'}}
179+
// expected-note@-2 {{did you mean module 'Swift'?}} {{14-38=Swift}}
180+
// expected-note@-3 {{did you mean module 'Swift'?}} {{45-69=Swift}}
181+
// expected-note@-4 {{did you mean module 'Swift'?}} {{79-103=Swift}}
166182
(ModuleSelectorTestingKit::+)
167183
// FIXME improve: expected-error@-1 {{cannot find operator 'ModuleSelectorTestingKit::+' in scope}}
168184

169185
let magnitude: Int.ModuleSelectorTestingKit::Magnitude = ModuleSelectorTestingKit::magnitude
170-
// FIXME improve: expected-error@-1 {{'ModuleSelectorTestingKit::Magnitude' is not a member type of struct 'Swift.Int'}}
171-
// FIXME improve: expected-error@-2 {{cannot find 'ModuleSelectorTestingKit::magnitude' in scope}}
186+
// expected-error@-1 {{'Magnitude' is not imported through module 'ModuleSelectorTestingKit'}}
187+
// expected-note@-2 {{did you mean module 'Swift'?}} {{24-48=Swift}}
188+
// FIXME improve: expected-error@-3 {{cannot find 'ModuleSelectorTestingKit::magnitude' in scope}}
172189

173190
_ = (fn, magnitude)
174191

@@ -206,15 +223,17 @@ extension C: @retroactive ModuleSelectorTestingKit::Equatable {
206223
// Test resolution of Swift:: using `D`
207224

208225
extension Swift::D {}
209-
// FIXME improve: expected-error@-1 {{cannot find type 'Swift::D' in scope}}
226+
// expected-error@-1 {{'D' is not imported through module 'Swift'}}
227+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{11-16=ModuleSelectorTestingKit}}
210228

211229
extension D: @retroactive Swift::Equatable {
212230
// Caused by Swift::D failing to typecheck in `equals(_:_:)`: expected-error@-1 *{{extension outside of file declaring struct 'D' prevents automatic synthesis of '==' for protocol 'Equatable'}} expected-note@-1 *{{add stubs for conformance}}
213231

214232
@_implements(Swift::Equatable, ==(_:_:))
215233
public static func equals(_: Swift::D, _: Swift::D) -> Swift::Bool {
216-
// expected-error@-1 {{cannot find type 'Swift::D' in scope}}
217-
// expected-error@-2 {{cannot find type 'Swift::D' in scope}}
234+
// expected-error@-1 2{{'D' is not imported through module 'Swift'}}
235+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{32-37=ModuleSelectorTestingKit}}
236+
// expected-note@-3 {{did you mean module 'ModuleSelectorTestingKit'?}} {{45-50=ModuleSelectorTestingKit}}
218237
Swift::fatalError() // no-error -- not typechecking function bodies
219238
}
220239

@@ -255,7 +274,8 @@ extension D: @retroactive Swift::Equatable {
255274
Swift::fatalError()
256275

257276
_ = \Swift::A.magnitude
258-
// FIXME improve: expected-error@-1 {{'Swift::A' in scope}} -- different diagnostic wording for legacy parser vs. ASTGen
277+
// expected-error@-1 {{'A' is not imported through module 'Swift'}}
278+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{10-15=ModuleSelectorTestingKit}}
259279
_ = \A.Swift::magnitude
260280
// FIXME improve: expected-error@-1 {{value of type 'A' has no member 'Swift::magnitude'}}
261281

@@ -306,7 +326,8 @@ func builderUser4(@Swift::MyBuilder fn: () -> Void) {}
306326

307327
func decl1(
308328
p1: main::A,
309-
// FIXME: expected-error@-1 {{cannot find type 'main::A' in scope}}
329+
// expected-error@-1 {{'A' is not imported through module 'main'}}
330+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{7-11=ModuleSelectorTestingKit}}
310331
label p2: inout A,
311332
label p3: @escaping () -> A
312333
) {
@@ -336,7 +357,8 @@ func decl1(
336357
}
337358

338359
typealias decl5 = main::Bool
339-
// FIXME improve: expected-error@-1 {{cannot find type 'main::Bool' in scope}}
360+
// expected-error@-1 {{'Bool' is not imported through module 'main'}}
361+
// expected-note@-2 {{did you mean module 'Swift'?}} {{19-23=Swift}}
340362

341363
func badModuleNames() {
342364
NonexistentModule::print()

0 commit comments

Comments
 (0)