Skip to content

Commit 60cc537

Browse files
committed
Improve module selector constraint solver diagnostics
1 parent d1e3910 commit 60cc537

File tree

7 files changed

+147
-19
lines changed

7 files changed

+147
-19
lines changed

include/swift/Sema/CSFix.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ enum class FixKind : uint8_t {
186186
/// no access control.
187187
AllowInaccessibleMember,
188188

189+
/// If a module selector prevented us from selecting a member, pretend that it
190+
/// was not specified.
191+
AllowMemberFromWrongModule,
192+
189193
/// Allow KeyPaths to use AnyObject as root type
190194
AllowAnyObjectKeyPathRoot,
191195

@@ -1941,6 +1945,25 @@ class AllowInaccessibleMember final : public AllowInvalidMemberRef {
19411945
}
19421946
};
19431947

1948+
class AllowMemberFromWrongModule final : public AllowInvalidMemberRef {
1949+
AllowMemberFromWrongModule(ConstraintSystem &cs, Type baseType,
1950+
ValueDecl *member, DeclNameRef name,
1951+
ConstraintLocator *locator)
1952+
: AllowInvalidMemberRef(cs, FixKind::AllowMemberFromWrongModule, baseType,
1953+
member, name, locator) {}
1954+
1955+
public:
1956+
std::string getName() const override {
1957+
return "allow reference to member from wrong module";
1958+
}
1959+
1960+
bool diagnose(const Solution &solution, bool asNote = false) const override;
1961+
1962+
static AllowMemberFromWrongModule *create(ConstraintSystem &cs, Type baseType,
1963+
ValueDecl *member, DeclNameRef name,
1964+
ConstraintLocator *locator);
1965+
};
1966+
19441967
class AllowAnyObjectKeyPathRoot final : public ConstraintFix {
19451968

19461969
AllowAnyObjectKeyPathRoot(ConstraintSystem &cs, ConstraintLocator *locator)

include/swift/Sema/ConstraintSystem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,9 @@ struct MemberLookupResult {
20592059
/// 'accesses' attributes of the init accessor and therefore canno
20602060
/// t be referenced in its body.
20612061
UR_UnavailableWithinInitAccessor,
2062+
2063+
/// The module selector in the `DeclNameRef` does not match this candidate.
2064+
UR_WrongModule
20622065
};
20632066

20642067
/// This is a list of considered (but rejected) candidates, along with a

lib/Sema/CSDiagnostics.cpp

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6321,10 +6321,7 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
63216321

63226322
if (baseExpr) {
63236323
auto *locator = getConstraintLocator(baseExpr, ConstraintLocator::Member);
6324-
const auto &solution = getSolution();
6325-
if (llvm::any_of(solution.Fixes, [&locator](const ConstraintFix *fix) {
6326-
return fix->getLocator() == locator;
6327-
}))
6324+
if (hasFixFor(getSolution(), locator))
63286325
return false;
63296326
}
63306327

@@ -6344,6 +6341,54 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
63446341
return true;
63456342
}
63466343

6344+
bool MemberFromWrongModuleFailure::diagnoseAsError() {
6345+
auto anchor = getRawAnchor();
6346+
// Let's try to avoid over-diagnosing chains of wrong-module
6347+
// members e.g.:
6348+
//
6349+
// struct A {
6350+
// struct B {
6351+
// struct C {}
6352+
// }
6353+
// }
6354+
//
6355+
// _ = A.Other::B.Other::C()
6356+
Expr *baseExpr = nullptr;
6357+
DeclNameLoc nameLoc;
6358+
if (auto *UDE = getAsExpr<UnresolvedDotExpr>(anchor)) {
6359+
baseExpr = UDE->getBase();
6360+
nameLoc = UDE->getNameLoc();
6361+
} else if (auto *UME = getAsExpr<UnresolvedMemberExpr>(anchor)) {
6362+
nameLoc = UME->getNameLoc();
6363+
} else if (auto *SE = getAsExpr<SubscriptExpr>(anchor)) {
6364+
baseExpr = SE->getBase();
6365+
} else if (auto *call = getAsExpr<CallExpr>(anchor)) {
6366+
baseExpr = call->getFn();
6367+
}
6368+
6369+
if (baseExpr) {
6370+
auto *locator = getConstraintLocator(baseExpr, ConstraintLocator::Member);
6371+
if (hasFixFor(getSolution(), locator))
6372+
return false;
6373+
}
6374+
6375+
auto modSelLoc = nameLoc.getModuleSelectorLoc();
6376+
auto loc = nameLoc.isValid() ? nameLoc.getStartLoc() : ::getLoc(anchor);
6377+
6378+
emitDiagnosticAt(loc, diag::wrong_module_selector, Member->getName(),
6379+
Name.getModuleSelector());
6380+
6381+
Identifier actualModuleName = Member->getModuleContext()->getName();
6382+
ASSERT(actualModuleName != Name.getModuleSelector() &&
6383+
"Module selector failure on member in same module?");
6384+
emitDiagnosticAt(loc, diag::note_change_module_selector, actualModuleName)
6385+
.fixItReplace(modSelLoc, actualModuleName.str());
6386+
6387+
emitDiagnosticAt(Member, diag::decl_declared_here, Member);
6388+
6389+
return true;
6390+
}
6391+
63476392
SourceLoc AnyObjectKeyPathRootFailure::getLoc() const {
63486393
auto anchor = getAnchor();
63496394

lib/Sema/CSDiagnostics.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,6 +1653,27 @@ class InaccessibleMemberFailure final : public FailureDiagnostic {
16531653
bool diagnoseAsError() override;
16541654
};
16551655

1656+
/// Diagnose an attempt to reference member from the wrong module with a module
1657+
/// selector, e.g.
1658+
///
1659+
/// ```swift
1660+
/// import Foo
1661+
/// import Bar
1662+
///
1663+
/// SomeType.Bar::methodDefinedInFoo()
1664+
/// ```
1665+
class MemberFromWrongModuleFailure final : public FailureDiagnostic {
1666+
ValueDecl *Member;
1667+
DeclNameRef Name;
1668+
1669+
public:
1670+
MemberFromWrongModuleFailure(const Solution &solution, DeclNameRef name,
1671+
ValueDecl *member, ConstraintLocator *locator)
1672+
: FailureDiagnostic(solution, locator), Member(member), Name(name) {}
1673+
1674+
bool diagnoseAsError() override;
1675+
};
1676+
16561677
/// Diagnose an attempt to reference member marked as `mutating`
16571678
/// on immutable base e.g. `let` variable:
16581679
///

lib/Sema/CSFix.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,21 @@ AllowInaccessibleMember::create(ConstraintSystem &cs, Type baseType,
12101210
AllowInaccessibleMember(cs, baseType, member, name, locator);
12111211
}
12121212

1213+
bool AllowMemberFromWrongModule::diagnose(const Solution &solution,
1214+
bool asNote) const {
1215+
MemberFromWrongModuleFailure failure(solution, getMemberName(), getMember(),
1216+
getLocator());
1217+
return failure.diagnose(asNote);
1218+
}
1219+
1220+
AllowMemberFromWrongModule *
1221+
AllowMemberFromWrongModule::create(ConstraintSystem &cs, Type baseType,
1222+
ValueDecl *member, DeclNameRef name,
1223+
ConstraintLocator *locator) {
1224+
return new (cs.getAllocator())
1225+
AllowMemberFromWrongModule(cs, baseType, member, name, locator);
1226+
}
1227+
12131228
bool AllowAnyObjectKeyPathRoot::diagnose(const Solution &solution,
12141229
bool asNote) const {
12151230
AnyObjectKeyPathRootFailure failure(solution, getLocator());

lib/Sema/CSSimplify.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10946,8 +10946,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
1094610946
}
1094710947

1094810948
// If we have no viable or unviable candidates, and we're generating,
10949-
// diagnostics, rerun the query with inaccessible members included, so we can
10950-
// include them in the unviable candidates list.
10949+
// diagnostics, rerun the query with various excluded members included, so we
10950+
// can include them in the unviable candidates list.
1095110951
if (result.ViableCandidates.empty() && result.UnviableCandidates.empty() &&
1095210952
includeInaccessibleMembers) {
1095310953
NameLookupOptions lookupOptions =
@@ -10956,7 +10956,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
1095610956
// Local function that looks up additional candidates using the given lookup
1095710957
// options, recording the results as unviable candidates.
1095810958
auto lookupUnviable =
10959-
[&](NameLookupOptions lookupOptions,
10959+
[&](DeclNameRef memberName,
10960+
NameLookupOptions lookupOptions,
1096010961
MemberLookupResult::UnviableReason reason) -> bool {
1096110962
auto lookup = TypeChecker::lookupMember(DC, instanceTy, memberName,
1096210963
memberLoc, lookupOptions);
@@ -10980,9 +10981,20 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
1098010981
return !lookup.empty();
1098110982
};
1098210983

10984+
// Look for members that were excluded because of a module selector.
10985+
if (memberName.hasModuleSelector()) {
10986+
DeclNameRef unqualifiedMemberName{memberName.getFullName()};
10987+
10988+
if (lookupUnviable(unqualifiedMemberName,
10989+
lookupOptions,
10990+
MemberLookupResult::UR_WrongModule))
10991+
return result;
10992+
}
10993+
1098310994
// Ignore access control so we get candidates that might have been missed
1098410995
// before.
10985-
if (lookupUnviable(lookupOptions | NameLookupFlags::IgnoreAccessControl,
10996+
if (lookupUnviable(memberName,
10997+
lookupOptions | NameLookupFlags::IgnoreAccessControl,
1098610998
MemberLookupResult::UR_Inaccessible))
1098710999
return result;
1098811000
}
@@ -11183,6 +11195,11 @@ static ConstraintFix *fixMemberRef(
1118311195
: nullptr;
1118411196
}
1118511197

11198+
case MemberLookupResult::UR_WrongModule:
11199+
ASSERT(choice.isDecl());
11200+
return AllowMemberFromWrongModule::create(cs, baseTy, choice.getDecl(),
11201+
memberName, locator);
11202+
1118611203
case MemberLookupResult::UR_Inaccessible:
1118711204
assert(choice.isDecl());
1118811205
return AllowInaccessibleMember::create(cs, baseTy, choice.getDecl(),
@@ -16167,6 +16184,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1616716184
case FixKind::AllowInvalidInitRef:
1616816185
case FixKind::AllowClosureParameterDestructuring:
1616916186
case FixKind::AllowInaccessibleMember:
16187+
case FixKind::AllowMemberFromWrongModule:
1617016188
case FixKind::AllowAnyObjectKeyPathRoot:
1617116189
case FixKind::AllowMultiArgFuncKeyPathMismatch:
1617216190
case FixKind::TreatKeyPathSubscriptIndexAsHashable:

test/NameLookup/module_selector.swift

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ extension B: @retroactive main::Equatable {
129129
// expected-error@-3 {{cannot infer contextual base in reference to member 'main::min'}}
130130

131131
self = B.main::init(value: .min)
132-
// FIXME improve: expected-error@-1 {{'B' cannot be constructed because it has no accessible initializers}}
133-
// expected-error@-2 {{cannot infer contextual base in reference to member 'min'}}
132+
// expected-error@-1 {{'init(value:)' is not imported through module 'main'}}
133+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{16-20=ModuleSelectorTestingKit}}
134134
}
135135

136136
self.main::myNegate()
@@ -183,7 +183,7 @@ extension C: @retroactive ModuleSelectorTestingKit::Equatable {
183183
@_dynamicReplacement(for: ModuleSelectorTestingKit::negate())
184184

185185
mutating func myNegate() {
186-
// expected-note@-1 {{did you mean 'myNegate'?}}
186+
// expected-note@-1 {{'myNegate()' declared here}}
187187

188188
let fn: (ModuleSelectorTestingKit::Int, ModuleSelectorTestingKit::Int) -> ModuleSelectorTestingKit::Int =
189189
// expected-error@-1 3{{'Int' is not imported through module 'ModuleSelectorTestingKit'}}
@@ -213,13 +213,15 @@ extension C: @retroactive ModuleSelectorTestingKit::Equatable {
213213
}
214214
else {
215215
self = ModuleSelectorTestingKit::C(value: .ModuleSelectorTestingKit::min)
216-
// FIXME improve: expected-error@-1 {{type 'Int' has no member 'ModuleSelectorTestingKit::min'}}
216+
// expected-error@-1 {{'min' is not imported through module 'ModuleSelectorTestingKit'}}
217+
// expected-note@-2 {{did you mean module 'Swift'?}} {{50-74=Swift}}
217218

218219
self = C.ModuleSelectorTestingKit::init(value: .min)
219220
}
220221

221222
self.ModuleSelectorTestingKit::myNegate()
222-
// FIXME improve: expected-error@-1 {{value of type 'C' has no member 'ModuleSelectorTestingKit::myNegate'}}
223+
// expected-error@-1 {{'myNegate()' is not imported through module 'ModuleSelectorTestingKit'}}
224+
// expected-note@-2 {{did you mean module 'main'?}} {{10-34=main}}
223225

224226
ModuleSelectorTestingKit::fatalError()
225227
// expected-error@-1 {{'fatalError' is not imported through module 'ModuleSelectorTestingKit'}}
@@ -261,7 +263,7 @@ extension D: @retroactive Swift::Equatable {
261263
// FIXME improve: expected-error@-1 {{replaced function 'Swift::negate()' could not be found}}
262264

263265
mutating func myNegate() {
264-
// expected-note@-1 {{did you mean 'myNegate'?}}
266+
// expected-note@-1 {{'myNegate()' declared here}}
265267

266268
let fn: (Swift::Int, Swift::Int) -> Swift::Int =
267269
(Swift::+)
@@ -285,12 +287,13 @@ extension D: @retroactive Swift::Equatable {
285287
// expected-error@-3 {{cannot infer contextual base in reference to member 'Swift::min'}}
286288

287289
self = D.Swift::init(value: .min)
288-
// FIXME improve: expected-error@-1 {{'D' cannot be constructed because it has no accessible initializers}}
289-
// expected-error@-2 {{cannot infer contextual base in reference to member 'min'}}
290+
// expected-error@-1 {{'init(value:)' is not imported through module 'Swift'}}
291+
// expected-note@-2 {{did you mean module 'ModuleSelectorTestingKit'?}} {{16-21=ModuleSelectorTestingKit}}
290292
}
291293

292294
self.Swift::myNegate()
293-
// FIXME improve: expected-error@-1 {{value of type 'D' has no member 'Swift::myNegate'}}
295+
// expected-error@-1 {{'myNegate()' is not imported through module 'Swift'}}
296+
// expected-note@-2 {{did you mean module 'main'?}} {{10-15=main}}
294297

295298
Swift::fatalError()
296299

@@ -392,8 +395,8 @@ func badModuleNames() {
392395
// expected-note@-2 {{did you mean module 'Swift'?}} {{3-20=Swift}}
393396

394397
_ = "foo".NonexistentModule::count
395-
// FIXME improve: expected-error@-1 {{value of type 'String' has no member 'NonexistentModule::count'}}
396-
// FIXME: expected-EVENTUALLY-note@-2 {{did you mean module 'Swift'?}} {{13-30=Swift}}
398+
// expected-error@-1 {{'count' is not imported through module 'NonexistentModule'}}
399+
// expected-note@-2 {{did you mean module 'Swift'?}} {{13-30=Swift}}
397400

398401
let x: NonexistentModule::MyType = NonexistentModule::MyType()
399402
// expected-error@-1 {{cannot find type 'NonexistentModule::MyType' in scope}}

0 commit comments

Comments
 (0)