mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
This commit is contained in:
@@ -1146,6 +1146,10 @@ ERROR(no_module_type,none,
|
||||
"no type named %0 in module %1", (DeclNameRef, Identifier))
|
||||
ERROR(ambiguous_module_type,none,
|
||||
"ambiguous type name %0 in module %1", (DeclNameRef, Identifier))
|
||||
ERROR(module_selector_dependent_member_type_not_allowed,none,
|
||||
"module selector is not allowed on generic member type; associated types "
|
||||
"with the same name are merged instead of shadowing one another",
|
||||
())
|
||||
ERROR(use_nonmatching_operator,none,
|
||||
"%0 is not a %select{binary|prefix unary|postfix unary}1 operator",
|
||||
(DeclNameRef, unsigned))
|
||||
|
||||
@@ -193,11 +193,21 @@ static unsigned getGenericRequirementKind(TypeResolutionOptions options) {
|
||||
Type TypeResolution::resolveDependentMemberType(
|
||||
Type baseTy, DeclContext *DC, SourceRange baseRange,
|
||||
QualifiedIdentTypeRepr *repr) const {
|
||||
// FIXME(ModQual): If module selector is present, check that it matches the
|
||||
// protocol's module.
|
||||
Identifier refIdentifier = repr->getNameRef().getBaseIdentifier();
|
||||
ASTContext &ctx = DC->getASTContext();
|
||||
|
||||
if (repr->getNameRef().hasModuleSelector()) {
|
||||
if (!this->getOptions().contains(TypeResolutionFlags::SilenceErrors)) {
|
||||
ctx.Diags.diagnose(repr->getNameLoc().getModuleSelectorLoc(),
|
||||
diag::module_selector_dependent_member_type_not_allowed)
|
||||
.fixItRemoveChars(repr->getNameLoc().getModuleSelectorLoc(),
|
||||
repr->getNameLoc().getBaseNameLoc());
|
||||
// If we can check if `refIdentifier` is a protocol ext's concrete type:
|
||||
// FIXME: Conditionally emit fix-it replacing base type with protocol
|
||||
}
|
||||
return ErrorType::get(baseTy);
|
||||
}
|
||||
|
||||
switch (stage) {
|
||||
case TypeResolutionStage::Structural:
|
||||
return DependentMemberType::get(baseTy, refIdentifier);
|
||||
|
||||
@@ -41,5 +41,10 @@ public struct MyBuilder {
|
||||
public static func buildBlock()
|
||||
}
|
||||
|
||||
public protocol ComparableIdentifiable {
|
||||
associatedtype ID: Comparable
|
||||
var id: ID { get }
|
||||
}
|
||||
|
||||
@freestanding(expression) public macro ExprMacro() -> String = #file
|
||||
@attached(peer) public macro PeerMacro() = #externalMacro(module: "Fnord", type: "PeerMacro")
|
||||
|
||||
@@ -428,3 +428,15 @@ func concurrencyModuleLookups(
|
||||
// expected-error@-1 {{'withTaskCancellationHandler' is not imported through module 'ModuleSelectorTestingKit'}}
|
||||
// expected-note@-2 {{did you mean module 'Swift'?}} {{9-33=Swift}}
|
||||
}
|
||||
|
||||
func dependentTypeLookup<T, U, V, W, X>(_: T, _: U, _: V, _: W, _: X) where
|
||||
T: Identifiable, T: ComparableIdentifiable, T.ID == Int,
|
||||
U: Identifiable, U: ComparableIdentifiable, U.Swift::ID == Int,
|
||||
// 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=}}
|
||||
V: Identifiable, V: ComparableIdentifiable, V.ModuleSelectorTestingKit::ID == Int,
|
||||
// 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=}}
|
||||
W: Identifiable, W: ComparableIdentifiable, W.ctypes::ID == Int,
|
||||
// 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=}}
|
||||
X: Identifiable, X: ComparableIdentifiable, X.NonexistentModule::ID == Int
|
||||
// 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=}}
|
||||
{}
|
||||
|
||||
Reference in New Issue
Block a user