Skip to content

Commit d1e3910

Browse files
committed
Improve module selector expr lookup diagnostics
1 parent 7949224 commit d1e3910

File tree

5 files changed

+142
-31
lines changed

5 files changed

+142
-31
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,6 +1195,12 @@ ERROR(wrong_module_selector,none,
11951195
"%0 is not imported through module %1", (DeclName, Identifier))
11961196
NOTE(note_change_module_selector,none,
11971197
"did you mean module %0?", (Identifier))
1198+
NOTE(note_remove_module_selector_local_decl,none,
1199+
"did you mean the local declaration?", ())
1200+
NOTE(note_remove_module_selector_outer_type,none,
1201+
"did you mean an outer type member?", ())
1202+
NOTE(note_add_explicit_self_with_module_selector,none,
1203+
"did you mean the member of 'self'?", ())
11981204
NOTE(note_typo_candidate_implicit_member,none,
11991205
"did you mean the implicitly-synthesized %kindbase0?", (const ValueDecl *))
12001206
NOTE(note_remapped_type,none,

lib/Sema/PreCheckTarget.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,18 @@ static Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC,
620620
}
621621

622622
if (!Lookup) {
623+
// Is there an incorrect module selector?
624+
if (Name.hasModuleSelector()) {
625+
auto anyModuleName = DeclNameRef(LookupName.getFullName());
626+
ModuleSelectorCorrection correction(
627+
TypeChecker::lookupUnqualified(DC, anyModuleName, Loc, lookupOptions));
628+
629+
if (correction.diagnose(Context, UDRE->getNameLoc(), LookupName)) {
630+
// FIXME: Can we recover by assuming the first/best result is correct?
631+
return errorResult();
632+
}
633+
}
634+
623635
// For the purpose of diagnosing inaccessible results, try the lookup again
624636
// but ignore access control.
625637
NameLookupOptions relookupOptions = lookupOptions;

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,8 +1160,23 @@ ModuleSelectorCorrection(const LookupResult &candidates) {
11601160
// emit a bunch of duplicates.
11611161
for (auto result : candidates) {
11621162
ValueDecl * decl = result.getValueDecl();
1163+
1164+
CandidateKind kind;
1165+
if (!result.getDeclContext()) {
1166+
if (decl->getDeclContext()->isLocalContext())
1167+
kind = CandidateKind::Local;
1168+
else
1169+
kind = CandidateKind::ContextFree;
1170+
} else {
1171+
if (result.getDeclContext()->isTypeContext())
1172+
kind = CandidateKind::MemberViaContext;
1173+
else // found through result.getDeclContext()'s implicit `self`
1174+
kind = CandidateKind::MemberViaSelf;
1175+
}
1176+
11631177
auto owningModule = decl->getModuleContext();
1164-
candidateModules.insert(owningModule->getName());
1178+
candidateModules.insert(
1179+
{ owningModule->getName(), kind });
11651180
}
11661181
}
11671182

@@ -1171,7 +1186,8 @@ ModuleSelectorCorrection(const LookupTypeResult &candidates) {
11711186
// emit a bunch of duplicates.
11721187
for (auto result : candidates) {
11731188
auto owningModule = result.Member->getModuleContext();
1174-
candidateModules.insert(owningModule->getName());
1189+
candidateModules.insert(
1190+
{ owningModule->getName(), CandidateKind::ContextFree });
11751191
}
11761192
}
11771193

@@ -1187,10 +1203,47 @@ bool ModuleSelectorCorrection::diagnose(ASTContext &ctx,
11871203

11881204
SourceLoc moduleSelectorLoc = nameLoc.getModuleSelectorLoc();
11891205

1190-
for (auto moduleName : candidateModules) {
1191-
ctx.Diags.diagnose(moduleSelectorLoc, diag::note_change_module_selector,
1192-
moduleName)
1193-
.fixItReplace(moduleSelectorLoc, moduleName.str());
1206+
for (auto pair : candidateModules) {
1207+
Identifier moduleName = pair.first;
1208+
switch (pair.second) {
1209+
case CandidateKind::ContextFree:
1210+
ctx.Diags.diagnose(moduleSelectorLoc, diag::note_change_module_selector,
1211+
moduleName)
1212+
.fixItReplace(moduleSelectorLoc, moduleName.str());
1213+
break;
1214+
1215+
case CandidateKind::MemberViaSelf: {
1216+
SmallString<64> replacement("self.");
1217+
if (moduleName != originalName.getModuleSelector()) {
1218+
// The module selector specified the wrong module; replace it.
1219+
replacement += moduleName.str();
1220+
1221+
ctx.Diags.diagnose(moduleSelectorLoc, diag::note_change_module_selector,
1222+
moduleName)
1223+
.fixItReplace(moduleSelectorLoc, replacement);
1224+
} else {
1225+
// The module selector specified the right module, but we need to
1226+
// make the `self.` explicit.
1227+
ctx.Diags.diagnose(moduleSelectorLoc,
1228+
diag::note_add_explicit_self_with_module_selector)
1229+
.fixItInsert(moduleSelectorLoc, replacement);
1230+
}
1231+
break;
1232+
}
1233+
case CandidateKind::MemberViaContext:
1234+
// FIXME: If we had more info here, we could construct a reference
1235+
// to the outer type in question.
1236+
ctx.Diags.diagnose(moduleSelectorLoc,
1237+
diag::note_remove_module_selector_outer_type)
1238+
.fixItRemoveChars(moduleSelectorLoc, nameLoc.getBaseNameLoc());
1239+
break;
1240+
1241+
case CandidateKind::Local:
1242+
ctx.Diags.diagnose(moduleSelectorLoc,
1243+
diag::note_remove_module_selector_local_decl)
1244+
.fixItRemoveChars(moduleSelectorLoc, nameLoc.getBaseNameLoc());
1245+
break;
1246+
}
11941247
}
11951248

11961249
return true;

lib/Sema/TypeChecker.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,20 @@ class CheckGenericArgumentsResult {
312312
/// there are any results, the \c diagnose() method will emit an error and a
313313
/// set of fix-it notes.
314314
class ModuleSelectorCorrection {
315-
using CandidateModule = Identifier;
315+
enum class CandidateKind {
316+
/// A declaration that is found without depending on context.
317+
/// Usually either a top-level type or a member with an explicit base type.
318+
ContextFree,
319+
/// A member declaration accessed via implicit \c self .
320+
MemberViaSelf,
321+
/// A member declaration not accessed via implicit \c self (usually a static
322+
/// member of an enclosing type).
323+
MemberViaContext,
324+
/// A local declaration.
325+
Local
326+
};
327+
328+
using CandidateModule = std::pair<Identifier, CandidateKind>;
316329
SmallSetVector<CandidateModule, 4> candidateModules;
317330

318331
public:

test/NameLookup/module_selector.swift

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ extension B: @retroactive main::Equatable {
8787
// expected-error@-4 {{'Bool' is not imported through module 'main'}}
8888
// expected-note@-5 {{did you mean module 'Swift'?}} {{56-60=Swift}}
8989
main::fatalError()
90-
// FIXME improve: expected-error@-1 {{cannot find 'main::fatalError' in scope}}
90+
// expected-error@-1 {{'fatalError' is not imported through module 'main'}}
91+
// expected-note@-2 {{did you mean module 'Swift'?}} {{5-9=Swift}}
9192
}
9293

9394
// FIXME: Add tests with autodiff @_differentiable(jvp:vjp:) and
@@ -103,7 +104,9 @@ extension B: @retroactive main::Equatable {
103104
// expected-note@-3 {{did you mean module 'Swift'?}} {{25-29=Swift}}
104105
// expected-note@-4 {{did you mean module 'Swift'?}} {{39-43=Swift}}
105106
(main::+)
106-
// FIXME improve: expected-error@-1 {{cannot find operator 'main::+' in scope}}
107+
// expected-error@-1 {{'+' is not imported through module 'main'}}
108+
// expected-note@-2 {{did you mean module 'Swift'?}} {{8-12=Swift}}
109+
// expected-note@-3 {{did you mean module '_Concurrency'?}} {{8-12=_Concurrency}} FIXME: Accept and suggest 'Swift::' instead?
107110

108111
let magnitude: Int.main::Magnitude = main::magnitude
109112
// expected-error@-1 {{'Magnitude' is not imported through module 'main'}}
@@ -112,15 +115,18 @@ extension B: @retroactive main::Equatable {
112115
_ = (fn, magnitude)
113116

114117
if main::Bool.main::random() {
115-
// FIXME improve: expected-error@-1 {{cannot find 'main::Bool' in scope}}
118+
// expected-error@-1 {{'Bool' is not imported through module 'main'}}
119+
// expected-note@-2 {{did you mean module 'Swift'?}} {{8-12=Swift}}
116120

117121
main::negate()
118-
// FIXME improve: expected-error@-1 {{cannot find 'main::negate' in scope}}
122+
// expected-error@-1 {{'negate' is not imported through module 'main'}}
123+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{7-11=self.ModuleSelectorTestingKit}}
119124
}
120125
else {
121126
self = main::B(value: .main::min)
122-
// FIXME improve: expected-error@-1 {{cannot find 'main::B' in scope}}
123-
// expected-error@-2 {{cannot infer contextual base in reference to member 'main::min'}}
127+
// expected-error@-1 {{'B' is not imported through module 'main'}}
128+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{14-18=ModuleSelectorTestingKit}}
129+
// expected-error@-3 {{cannot infer contextual base in reference to member 'main::min'}}
124130

125131
self = B.main::init(value: .min)
126132
// FIXME improve: expected-error@-1 {{'B' cannot be constructed because it has no accessible initializers}}
@@ -130,13 +136,15 @@ extension B: @retroactive main::Equatable {
130136
self.main::myNegate()
131137

132138
main::fatalError()
133-
// FIXME improve: expected-error@-1 {{cannot find 'main::fatalError' in scope}}
139+
// expected-error@-1 {{'fatalError' is not imported through module 'main'}}
140+
// expected-note@-2 {{did you mean module 'Swift'?}} {{5-9=Swift}}
134141

135142
_ = \main::A.magnitude
136143
// expected-error@-1 {{'A' is not imported through module 'main'}}
137144
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{10-14=ModuleSelectorTestingKit}}
138145
_ = \A.main::magnitude
139-
// FIXME improve: expected-error@-1 {{value of type 'A' has no member 'main::magnitude'}}
146+
// expected-error@-1 {{'magnitude' is not imported through module 'main'}}
147+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{none}}
140148

141149
_ = #main::ExprMacro
142150
// expected-error@-1 {{no macro named 'main::ExprMacro'}}
@@ -165,7 +173,8 @@ extension C: @retroactive ModuleSelectorTestingKit::Equatable {
165173
// expected-note@-2 {{did you mean module 'Swift'?}} {{96-120=Swift}}
166174

167175
ModuleSelectorTestingKit::fatalError()
168-
// FIXME improve: expected-error@-1 {{cannot find 'ModuleSelectorTestingKit::fatalError' in scope}}
176+
// expected-error@-1 {{'fatalError' is not imported through module 'ModuleSelectorTestingKit'}}
177+
// expected-note@-2 {{did you mean module 'Swift'?}} {{5-29=Swift}}
169178
}
170179

171180
// FIXME: Add tests with autodiff @_differentiable(jvp:vjp:) and
@@ -174,26 +183,33 @@ extension C: @retroactive ModuleSelectorTestingKit::Equatable {
174183
@_dynamicReplacement(for: ModuleSelectorTestingKit::negate())
175184

176185
mutating func myNegate() {
186+
// expected-note@-1 {{did you mean 'myNegate'?}}
187+
177188
let fn: (ModuleSelectorTestingKit::Int, ModuleSelectorTestingKit::Int) -> ModuleSelectorTestingKit::Int =
178189
// expected-error@-1 3{{'Int' is not imported through module 'ModuleSelectorTestingKit'}}
179190
// expected-note@-2 {{did you mean module 'Swift'?}} {{14-38=Swift}}
180191
// expected-note@-3 {{did you mean module 'Swift'?}} {{45-69=Swift}}
181192
// expected-note@-4 {{did you mean module 'Swift'?}} {{79-103=Swift}}
182193
(ModuleSelectorTestingKit::+)
183-
// FIXME improve: expected-error@-1 {{cannot find operator 'ModuleSelectorTestingKit::+' in scope}}
194+
// expected-error@-1 {{'+' is not imported through module 'ModuleSelectorTestingKit'}}
195+
// expected-note@-2 {{did you mean module 'Swift'?}} {{8-32=Swift}}
196+
// expected-note@-3 {{did you mean module '_Concurrency'?}} {{8-32=_Concurrency}} FIXME: Accept and suggest 'Swift::' instead?
184197

185198
let magnitude: Int.ModuleSelectorTestingKit::Magnitude = ModuleSelectorTestingKit::magnitude
186199
// expected-error@-1 {{'Magnitude' is not imported through module 'ModuleSelectorTestingKit'}}
187200
// expected-note@-2 {{did you mean module 'Swift'?}} {{24-48=Swift}}
188-
// FIXME improve: expected-error@-3 {{cannot find 'ModuleSelectorTestingKit::magnitude' in scope}}
201+
// expected-error@-3 {{'magnitude' is not imported through module 'ModuleSelectorTestingKit'}}
202+
// expected-note@-4 {{did you mean the local declaration?}} {{62-88=}}
189203

190204
_ = (fn, magnitude)
191205

192206
if ModuleSelectorTestingKit::Bool.ModuleSelectorTestingKit::random() {
193-
// FIXME improve: expected-error@-1 {{cannot find 'ModuleSelectorTestingKit::Bool' in scope}}
207+
// expected-error@-1 {{'Bool' is not imported through module 'ModuleSelectorTestingKit'}}
208+
// expected-note@-2 {{did you mean module 'Swift'?}} {{8-32=Swift}}
194209

195210
ModuleSelectorTestingKit::negate()
196-
// expected-error@-1 {{cannot find 'ModuleSelectorTestingKit::negate' in scope}}
211+
// expected-error@-1 {{'negate' is not imported through module 'ModuleSelectorTestingKit'}}
212+
// expected-note@-2 {{did you mean the member of 'self'?}} {{7-7=self.}}
197213
}
198214
else {
199215
self = ModuleSelectorTestingKit::C(value: .ModuleSelectorTestingKit::min)
@@ -206,7 +222,8 @@ extension C: @retroactive ModuleSelectorTestingKit::Equatable {
206222
// FIXME improve: expected-error@-1 {{value of type 'C' has no member 'ModuleSelectorTestingKit::myNegate'}}
207223

208224
ModuleSelectorTestingKit::fatalError()
209-
// FIXME improve: expected-error@-1 {{cannot find 'ModuleSelectorTestingKit::fatalError' in scope}}
225+
// expected-error@-1 {{'fatalError' is not imported through module 'ModuleSelectorTestingKit'}}
226+
// expected-note@-2 {{did you mean module 'Swift'?}} {{5-29=Swift}}
210227

211228
_ = \ModuleSelectorTestingKit::A.magnitude
212229
_ = \A.ModuleSelectorTestingKit::magnitude
@@ -244,24 +261,28 @@ extension D: @retroactive Swift::Equatable {
244261
// FIXME improve: expected-error@-1 {{replaced function 'Swift::negate()' could not be found}}
245262

246263
mutating func myNegate() {
264+
// expected-note@-1 {{did you mean 'myNegate'?}}
247265

248266
let fn: (Swift::Int, Swift::Int) -> Swift::Int =
249267
(Swift::+)
250268

251269
let magnitude: Int.Swift::Magnitude = Swift::magnitude
252-
// expected-error@-1 {{cannot find 'Swift::magnitude' in scope}}
270+
// expected-error@-1 {{'magnitude' is not imported through module 'Swift'}}
271+
// expected-note@-2 {{did you mean the local declaration?}} {{43-50=}}
253272

254273
_ = (fn, magnitude)
255274

256275
if Swift::Bool.Swift::random() {
257276

258277
Swift::negate()
259-
// FIXME improve: expected-error@-1 {{cannot find 'Swift::negate' in scope}}
278+
// expected-error@-1 {{'negate' is not imported through module 'Swift'}}
279+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{7-12=self.ModuleSelectorTestingKit}}
260280
}
261281
else {
262282
self = Swift::D(value: .Swift::min)
263-
// FIXME improve: expected-error@-1 {{cannot find 'Swift::D' in scope}}
264-
// expected-error@-2 {{cannot infer contextual base in reference to member 'Swift::min'}}
283+
// expected-error@-1 {{'D' is not imported through module 'Swift'}}
284+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{14-19=ModuleSelectorTestingKit}}
285+
// expected-error@-3 {{cannot infer contextual base in reference to member 'Swift::min'}}
265286

266287
self = D.Swift::init(value: .min)
267288
// FIXME improve: expected-error@-1 {{'D' cannot be constructed because it has no accessible initializers}}
@@ -277,7 +298,8 @@ extension D: @retroactive Swift::Equatable {
277298
// expected-error@-1 {{'A' is not imported through module 'Swift'}}
278299
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{10-15=ModuleSelectorTestingKit}}
279300
_ = \A.Swift::magnitude
280-
// FIXME improve: expected-error@-1 {{value of type 'A' has no member 'Swift::magnitude'}}
301+
// expected-error@-1 {{'magnitude' is not imported through module 'Swift'}}
302+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{none}}
281303

282304
_ = #Swift::ExprMacro
283305
// expected-error@-1 {{no macro named 'Swift::ExprMacro'}}
@@ -293,7 +315,8 @@ let mog: Never = fatalError()
293315

294316
func localVarsCantBeAccessedByModuleSelector() {
295317
let mag: Int.Swift::Magnitude = main::mag
296-
// expected-error@-1 {{cannot find 'main::mag' in scope}}
318+
// expected-error@-1 {{'mag' is not imported through module 'main'}}
319+
// expected-note@-2 {{did you mean the local declaration?}} {{35-41=}}
297320

298321
let mog: Never = main::mog
299322
}
@@ -332,23 +355,26 @@ func decl1(
332355
label p3: @escaping () -> A
333356
) {
334357
switch Optional(main::p2) {
335-
// expected-error@-1 {{cannot find 'main::p2' in scope}}
358+
// expected-error@-1 {{'p2' is not imported through module 'main'}}
359+
// expected-note@-2 {{did you mean the local declaration?}} {{19-25=}}
336360
case Optional.some(let decl1i):
337361
break
338362
case .none:
339363
break
340364
}
341365

342366
switch Optional(main::p2) {
343-
// expected-error@-1 {{cannot find 'main::p2' in scope}}
367+
// expected-error@-1 {{'p2' is not imported through module 'main'}}
368+
// expected-note@-2 {{did you mean the local declaration?}} {{19-25=}}
344369
case let Optional.some(decl1j):
345370
break
346371
case .none:
347372
break
348373
}
349374

350375
switch Optional(main::p2) {
351-
// expected-error@-1 {{cannot find 'main::p2' in scope}}
376+
// expected-error@-1 {{'p2' is not imported through module 'main'}}
377+
// expected-note@-2 {{did you mean the local declaration?}} {{19-25=}}
352378
case let decl1k?:
353379
break
354380
case .none:
@@ -362,7 +388,8 @@ typealias decl5 = main::Bool
362388

363389
func badModuleNames() {
364390
NonexistentModule::print()
365-
// expected-error@-1 {{cannot find 'NonexistentModule::print' in scope}}
391+
// expected-error@-1 {{'print' is not imported through module 'NonexistentModule'}}
392+
// expected-note@-2 {{did you mean module 'Swift'?}} {{3-20=Swift}}
366393

367394
_ = "foo".NonexistentModule::count
368395
// FIXME improve: expected-error@-1 {{value of type 'String' has no member 'NonexistentModule::count'}}

0 commit comments

Comments
 (0)