Skip to content

Commit e3495f5

Browse files
committed
Forbid module selectors on dependent member types
In code like the following: ``` protocol P { associatedtype A: Hashable } protocol Q { associatedtype A: Comparable } func fn<T: P & Q>(_: T) where T.A == Int { … } ``` `T.A` is actually the union of `P.A` and `Q.A`—it satisfies both associated types and has both of their constraints. This means it doesn’t actually make sense to apply a module selector to `A`—even if `P` and `Q` are in different modules, `T.A` always represents both of the declarations, not one or the other. We therefore now ban module selectors in this position, since they don’t actually jibe with the nature of a generic signature. This justification technically doesn’t hold for *every* member type of a generic parameter—a member type can refer to a concrete typealias in a protocol extension, for instance—but in those situations, you can disambiguate (and add module selectors) by writing `P.A` or `Q.A` instead of `T.A`, so we’re not really worried about this limitation.
1 parent ec92be4 commit e3495f5

File tree

4 files changed

+33
-2
lines changed

4 files changed

+33
-2
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,10 @@ ERROR(no_module_type,none,
11461146
"no type named %0 in module %1", (DeclNameRef, Identifier))
11471147
ERROR(ambiguous_module_type,none,
11481148
"ambiguous type name %0 in module %1", (DeclNameRef, Identifier))
1149+
ERROR(module_selector_dependent_member_type_not_allowed,none,
1150+
"module selector is not allowed on generic member type; associated types "
1151+
"with the same name are merged instead of shadowing one another",
1152+
())
11491153
ERROR(use_nonmatching_operator,none,
11501154
"%0 is not a %select{binary|prefix unary|postfix unary}1 operator",
11511155
(DeclNameRef, unsigned))

lib/Sema/TypeCheckType.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,21 @@ static unsigned getGenericRequirementKind(TypeResolutionOptions options) {
193193
Type TypeResolution::resolveDependentMemberType(
194194
Type baseTy, DeclContext *DC, SourceRange baseRange,
195195
QualifiedIdentTypeRepr *repr) const {
196-
// FIXME(ModQual): If module selector is present, check that it matches the
197-
// protocol's module.
198196
Identifier refIdentifier = repr->getNameRef().getBaseIdentifier();
199197
ASTContext &ctx = DC->getASTContext();
200198

199+
if (repr->getNameRef().hasModuleSelector()) {
200+
if (!this->getOptions().contains(TypeResolutionFlags::SilenceErrors)) {
201+
ctx.Diags.diagnose(repr->getNameLoc().getModuleSelectorLoc(),
202+
diag::module_selector_dependent_member_type_not_allowed)
203+
.fixItRemoveChars(repr->getNameLoc().getModuleSelectorLoc(),
204+
repr->getNameLoc().getBaseNameLoc());
205+
// If we can check if `refIdentifier` is a protocol ext's concrete type:
206+
// FIXME: Conditionally emit fix-it replacing base type with protocol
207+
}
208+
return ErrorType::get(baseTy);
209+
}
210+
201211
switch (stage) {
202212
case TypeResolutionStage::Structural:
203213
return DependentMemberType::get(baseTy, refIdentifier);

test/NameLookup/Inputs/ModuleSelectorTestingKit.swiftinterface

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,10 @@ public struct MyBuilder {
4141
public static func buildBlock()
4242
}
4343

44+
public protocol ComparableIdentifiable {
45+
associatedtype ID: Comparable
46+
var id: ID { get }
47+
}
48+
4449
@freestanding(expression) public macro ExprMacro() -> String = #file
4550
@attached(peer) public macro PeerMacro() = #externalMacro(module: "Fnord", type: "PeerMacro")

test/NameLookup/module_selector.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,3 +428,15 @@ func concurrencyModuleLookups(
428428
// expected-error@-1 {{'withTaskCancellationHandler' is not imported through module 'ModuleSelectorTestingKit'}}
429429
// expected-note@-2 {{did you mean module 'Swift'?}} {{9-33=Swift}}
430430
}
431+
432+
func dependentTypeLookup<T, U, V, W, X>(_: T, _: U, _: V, _: W, _: X) where
433+
T: Identifiable, T: ComparableIdentifiable, T.ID == Int,
434+
U: Identifiable, U: ComparableIdentifiable, U.Swift::ID == Int,
435+
// expected-error@-1 {{module selector is not allowed on generic member type; associated types with the same name are merged instead of shadowing one another}} {{49-56=}}
436+
V: Identifiable, V: ComparableIdentifiable, V.ModuleSelectorTestingKit::ID == Int,
437+
// expected-error@-1 {{module selector is not allowed on generic member type; associated types with the same name are merged instead of shadowing one another}} {{49-75=}}
438+
W: Identifiable, W: ComparableIdentifiable, W.ctypes::ID == Int,
439+
// expected-error@-1 {{module selector is not allowed on generic member type; associated types with the same name are merged instead of shadowing one another}} {{49-57=}}
440+
X: Identifiable, X: ComparableIdentifiable, X.NonexistentModule::ID == Int
441+
// expected-error@-1 {{module selector is not allowed on generic member type; associated types with the same name are merged instead of shadowing one another}} {{49-68=}}
442+
{}

0 commit comments

Comments
 (0)