Skip to content

Commit 0ecf885

Browse files
authored
Merge pull request #60984 from slavapestov/protocol-extension-where-clause
Sema: Diagnose references to protocol extension type aliases from generic requirements
2 parents d2f6107 + 67d182e commit 0ecf885

File tree

4 files changed

+140
-3
lines changed

4 files changed

+140
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,15 @@ NOTE(invalid_redecl_implicit_wrapper,none,
865865
"%select{projected value|backing storage}1",
866866
(DeclName, bool))
867867

868+
ERROR(protocol_extension_in_where_clause,none,
869+
"%0 was defined in extension of protocol %1 and cannot be referenced "
870+
"from a %select{'where' clause|generic parameter inheritance clause|"
871+
"associated type inheritance clause}2",
872+
(Identifier, Identifier, unsigned))
873+
NOTE(protocol_extension_in_where_clause_note,none,
874+
"consider moving %0 into the definition of protocol %1",
875+
(Identifier, Identifier))
876+
868877
ERROR(ambiguous_type_base,none,
869878
"%0 is ambiguous for type lookup in this context", (DeclNameRef))
870879
ERROR(invalid_member_type,none,

lib/Sema/TypeCheckRequestFunctions.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,38 @@ Type InheritedTypeRequest::evaluate(
3131
unsigned index, TypeResolutionStage stage) const {
3232
// Figure out how to resolve types.
3333
DeclContext *dc;
34+
TypeResolverContext context;
35+
3436
if (auto typeDecl = decl.dyn_cast<const TypeDecl *>()) {
3537
if (auto nominal = dyn_cast<NominalTypeDecl>(typeDecl)) {
3638
dc = (DeclContext *)nominal;
39+
context = TypeResolverContext::Inherited;
3740
} else {
3841
dc = typeDecl->getDeclContext();
42+
if (isa<GenericTypeParamDecl>(typeDecl))
43+
context = TypeResolverContext::GenericParameterInherited;
44+
else {
45+
assert(isa<AssociatedTypeDecl>(typeDecl));
46+
context = TypeResolverContext::AssociatedTypeInherited;
47+
}
3948
}
4049
} else {
4150
dc = (DeclContext *)decl.get<const ExtensionDecl *>();
51+
context = TypeResolverContext::Inherited;
4252
}
4353

4454
Optional<TypeResolution> resolution;
4555
switch (stage) {
4656
case TypeResolutionStage::Structural:
4757
resolution =
48-
TypeResolution::forStructural(dc, TypeResolverContext::Inherited,
58+
TypeResolution::forStructural(dc, context,
4959
/*unboundTyOpener*/ nullptr,
5060
/*placeholderHandler*/ nullptr);
5161
break;
5262

5363
case TypeResolutionStage::Interface:
5464
resolution =
55-
TypeResolution::forInterface(dc, TypeResolverContext::Inherited,
65+
TypeResolution::forInterface(dc, context,
5666
/*unboundTyOpener*/ nullptr,
5767
/*placeholderHandler*/ nullptr);
5868
break;

lib/Sema/TypeCheckType.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,51 @@ static DescriptiveDeclKind describeDeclOfType(Type t) {
119119
return DescriptiveDeclKind::Type;
120120
}
121121

122+
static unsigned getGenericRequirementKind(TypeResolutionOptions options) {
123+
switch (options.getBaseContext()) {
124+
case TypeResolverContext::GenericRequirement:
125+
case TypeResolverContext::SameTypeRequirement:
126+
return 0;
127+
128+
case TypeResolverContext::GenericParameterInherited:
129+
return 1;
130+
131+
case TypeResolverContext::AssociatedTypeInherited:
132+
return 2;
133+
134+
case TypeResolverContext::None:
135+
case TypeResolverContext::Inherited:
136+
case TypeResolverContext::FunctionInput:
137+
case TypeResolverContext::TupleElement:
138+
case TypeResolverContext::GenericArgument:
139+
case TypeResolverContext::ProtocolGenericArgument:
140+
case TypeResolverContext::ExtensionBinding:
141+
case TypeResolverContext::TypeAliasDecl:
142+
case TypeResolverContext::GenericTypeAliasDecl:
143+
case TypeResolverContext::ExistentialConstraint:
144+
case TypeResolverContext::MetatypeBase:
145+
case TypeResolverContext::InExpression:
146+
case TypeResolverContext::ExplicitCastExpr:
147+
case TypeResolverContext::ForEachStmt:
148+
case TypeResolverContext::PatternBindingDecl:
149+
case TypeResolverContext::EditorPlaceholderExpr:
150+
case TypeResolverContext::ClosureExpr:
151+
case TypeResolverContext::VariadicFunctionInput:
152+
case TypeResolverContext::InoutFunctionInput:
153+
case TypeResolverContext::FunctionResult:
154+
case TypeResolverContext::SubscriptDecl:
155+
case TypeResolverContext::EnumElementDecl:
156+
case TypeResolverContext::EnumPatternPayload:
157+
case TypeResolverContext::ProtocolMetatypeBase:
158+
case TypeResolverContext::ImmediateOptionalTypeArgument:
159+
case TypeResolverContext::AbstractFunctionDecl:
160+
case TypeResolverContext::CustomAttr:
161+
break;
162+
}
163+
164+
llvm_unreachable("Invalid type resolution context");
165+
}
166+
122167
Type TypeResolution::resolveDependentMemberType(
123168
Type baseTy, DeclContext *DC,
124169
SourceRange baseRange,
@@ -144,6 +189,24 @@ Type TypeResolution::resolveDependentMemberType(
144189

145190
// Look for a nested type with the given name.
146191
if (auto nestedType = genericSig->lookupNestedType(baseTy, refIdentifier)) {
192+
if (options.isGenericRequirement()) {
193+
if (auto *protoDecl = nestedType->getDeclContext()->getExtendedProtocolDecl()) {
194+
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
195+
unsigned kind = getGenericRequirementKind(options);
196+
ctx.Diags.diagnose(ref->getNameLoc(),
197+
diag::protocol_extension_in_where_clause,
198+
nestedType->getName(), protoDecl->getName(), kind);
199+
if (protoDecl->getLoc() && nestedType->getLoc()) {
200+
ctx.Diags.diagnose(nestedType->getLoc(),
201+
diag::protocol_extension_in_where_clause_note,
202+
nestedType->getName(), protoDecl->getName());
203+
}
204+
}
205+
206+
return ErrorType::get(ctx);
207+
}
208+
}
209+
147210
// Record the type we found.
148211
ref->setValue(nestedType, nullptr);
149212
} else {
@@ -3991,6 +4054,8 @@ NeverNullType TypeResolver::resolveImplicitlyUnwrappedOptionalType(
39914054
case TypeResolverContext::AbstractFunctionDecl:
39924055
case TypeResolverContext::ClosureExpr:
39934056
case TypeResolverContext::Inherited:
4057+
case TypeResolverContext::GenericParameterInherited:
4058+
case TypeResolverContext::AssociatedTypeInherited:
39944059
case TypeResolverContext::CustomAttr:
39954060
doDiag = true;
39964061
break;

lib/Sema/TypeCheckType.h

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,15 @@ enum class TypeResolverContext : uint8_t {
162162
/// Whether this is the type of an editor placeholder.
163163
EditorPlaceholderExpr,
164164

165-
/// Whether this is an "inherited" type.
165+
/// Whether this is an inheritance clause of a concrete type.
166166
Inherited,
167167

168+
/// Whether this is an inheritance clause of a generic parameter.
169+
GenericParameterInherited,
170+
171+
/// Whether this is an inheritance clause of an associated type.
172+
AssociatedTypeInherited,
173+
168174
/// Whether this is a custom attribute.
169175
CustomAttr
170176
};
@@ -256,6 +262,8 @@ class TypeResolutionOptions {
256262
case Context::ImmediateOptionalTypeArgument:
257263
case Context::AbstractFunctionDecl:
258264
case Context::Inherited:
265+
case Context::GenericParameterInherited:
266+
case Context::AssociatedTypeInherited:
259267
case Context::CustomAttr:
260268
return false;
261269
}
@@ -267,6 +275,8 @@ class TypeResolutionOptions {
267275
bool isConstraintImplicitExistential() const {
268276
switch (context) {
269277
case Context::Inherited:
278+
case Context::GenericParameterInherited:
279+
case Context::AssociatedTypeInherited:
270280
case Context::ExtensionBinding:
271281
case Context::TypeAliasDecl:
272282
case Context::GenericTypeAliasDecl:
@@ -311,6 +321,8 @@ class TypeResolutionOptions {
311321
case Context::None:
312322
case Context::ProtocolGenericArgument:
313323
case Context::Inherited:
324+
case Context::GenericParameterInherited:
325+
case Context::AssociatedTypeInherited:
314326
case Context::ExtensionBinding:
315327
case Context::TypeAliasDecl:
316328
case Context::GenericTypeAliasDecl:
@@ -338,6 +350,47 @@ class TypeResolutionOptions {
338350
}
339351
}
340352

353+
/// Whether we are resolving a type in a `where` clause, generic parameter
354+
/// declaration inheritance clause, or associated type inheritance clause.
355+
bool isGenericRequirement() const {
356+
switch (base) {
357+
case Context::GenericRequirement:
358+
case Context::SameTypeRequirement:
359+
case Context::GenericParameterInherited:
360+
case Context::AssociatedTypeInherited:
361+
return true;
362+
363+
case Context::None:
364+
case Context::Inherited:
365+
case Context::FunctionInput:
366+
case Context::TupleElement:
367+
case Context::GenericArgument:
368+
case Context::ProtocolGenericArgument:
369+
case Context::ExtensionBinding:
370+
case Context::TypeAliasDecl:
371+
case Context::GenericTypeAliasDecl:
372+
case Context::ExistentialConstraint:
373+
case Context::MetatypeBase:
374+
case Context::InExpression:
375+
case Context::ExplicitCastExpr:
376+
case Context::ForEachStmt:
377+
case Context::PatternBindingDecl:
378+
case Context::EditorPlaceholderExpr:
379+
case Context::ClosureExpr:
380+
case Context::VariadicFunctionInput:
381+
case Context::InoutFunctionInput:
382+
case Context::FunctionResult:
383+
case Context::SubscriptDecl:
384+
case Context::EnumElementDecl:
385+
case Context::EnumPatternPayload:
386+
case Context::ProtocolMetatypeBase:
387+
case Context::ImmediateOptionalTypeArgument:
388+
case Context::AbstractFunctionDecl:
389+
case Context::CustomAttr:
390+
return false;
391+
}
392+
}
393+
341394
/// Determine whether all of the given options are set.
342395
bool contains(TypeResolutionFlags set) const {
343396
return !static_cast<bool>(unsigned(set) & ~unsigned(flags));

0 commit comments

Comments
 (0)