Skip to content

Commit 6f08216

Browse files
committed
Sema: Support where clauses on contextually generic decls
1 parent eb539e6 commit 6f08216

12 files changed

+259
-101
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1218,7 +1218,9 @@ class RequirementRepr {
12181218
void print(raw_ostream &OS) const;
12191219
void print(ASTPrinter &Printer) const;
12201220
};
1221-
1221+
1222+
using GenericParamSource = PointerUnion<GenericContext *, GenericParamList *>;
1223+
12221224
/// GenericParamList - A list of generic parameters that is part of a generic
12231225
/// function or type, along with extra requirements placed on those generic
12241226
/// parameters and types derived from them.

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2751,6 +2751,10 @@ ERROR(dynamic_self_stored_property_init,none,
27512751
ERROR(dynamic_self_default_arg,none,
27522752
"covariant 'Self' type cannot be referenced from a default argument expression", ())
27532753

2754+
ERROR(where_nongeneric_ctx,none,
2755+
"'where' clause on non-generic member declaration requires a "
2756+
"generic context", ())
2757+
27542758
//------------------------------------------------------------------------------
27552759
// MARK: Type Check Attributes
27562760
//------------------------------------------------------------------------------

include/swift/AST/TypeCheckRequests.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,7 @@ class InferredGenericSignatureRequest :
11081108
public SimpleRequest<InferredGenericSignatureRequest,
11091109
GenericSignature (ModuleDecl *,
11101110
GenericSignatureImpl *,
1111-
GenericParamList *,
1111+
GenericParamSource,
11121112
SmallVector<Requirement, 2>,
11131113
SmallVector<TypeLoc, 2>,
11141114
bool),
@@ -1124,7 +1124,7 @@ class InferredGenericSignatureRequest :
11241124
evaluate(Evaluator &evaluator,
11251125
ModuleDecl *module,
11261126
GenericSignatureImpl *baseSignature,
1127-
GenericParamList *gpl,
1127+
GenericParamSource paramSource,
11281128
SmallVector<Requirement, 2> addedRequirements,
11291129
SmallVector<TypeLoc, 2> inferenceSources,
11301130
bool allowConcreteGenericParams) const;

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ SWIFT_REQUEST(TypeChecker, HasDynamicMemberLookupAttributeRequest,
8383
bool(CanType), Cached, NoLocationInfo)
8484
SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest,
8585
GenericSignature (ModuleDecl *, GenericSignatureImpl *,
86-
GenericParamList *,
86+
GenericParamSource,
8787
SmallVector<Requirement, 2>,
8888
SmallVector<TypeLoc, 2>, bool),
8989
Cached, NoLocationInfo)

include/swift/Basic/SimpleDisplay.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,15 @@ namespace swift {
135135
}
136136
out << "}";
137137
}
138+
139+
template<typename T, typename U>
140+
void simple_display(llvm::raw_ostream &out,
141+
const llvm::PointerUnion<T, U> &ptrUnion) {
142+
if (const auto t = ptrUnion.template dyn_cast<T>())
143+
simple_display(out, t);
144+
else
145+
simple_display(out, ptrUnion.template get<U>());
146+
}
138147
}
139148

140149
#endif // SWIFT_BASIC_SIMPLE_DISPLAY_H

lib/AST/ASTScopeLookup.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ bool ASTScopeImpl::doesContextMatchStartingContext(
194194
// For a SubscriptDecl with generic parameters, the call tries to do lookups
195195
// with startingContext equal to either the get or set subscript
196196
// AbstractFunctionDecls. Since the generic parameters are in the
197-
// SubScriptDeclScope, and not the AbstractFunctionDecl scopes (after all how
198-
// could one parameter be in two scopes?), GenericParamScoped intercepts the
197+
// SubscriptDeclScope, and not the AbstractFunctionDecl scopes (after all how
198+
// could one parameter be in two scopes?), GenericParamScope intercepts the
199199
// match query here and tests against the accessor DeclContexts.
200200
bool GenericParamScope::doesContextMatchStartingContext(
201201
const DeclContext *context) const {

lib/AST/Decl.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,9 +1077,12 @@ void GenericContext::setGenericSignature(GenericSignature genericSig) {
10771077
}
10781078

10791079
SourceRange GenericContext::getGenericTrailingWhereClauseSourceRange() const {
1080-
if (!isGeneric())
1081-
return SourceRange();
1082-
return getGenericParams()->getTrailingWhereClauseSourceRange();
1080+
if (isGeneric())
1081+
return getGenericParams()->getTrailingWhereClauseSourceRange();
1082+
else if (const auto *where = getTrailingWhereClause())
1083+
return where->getSourceRange();
1084+
1085+
return SourceRange();
10831086
}
10841087

10851088
ImportDecl *ImportDecl::create(ASTContext &Ctx, DeclContext *DC,

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 84 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7459,7 +7459,7 @@ llvm::Expected<GenericSignature>
74597459
InferredGenericSignatureRequest::evaluate(
74607460
Evaluator &evaluator, ModuleDecl *parentModule,
74617461
GenericSignatureImpl *parentSig,
7462-
GenericParamList *gpl,
7462+
GenericParamSource paramSource,
74637463
SmallVector<Requirement, 2> addedRequirements,
74647464
SmallVector<TypeLoc, 2> inferenceSources,
74657465
bool allowConcreteGenericParams) const {
@@ -7470,78 +7470,99 @@ InferredGenericSignatureRequest::evaluate(
74707470
// from that context.
74717471
builder.addGenericSignature(parentSig);
74727472

7473-
// Type check the generic parameters, treating all generic type
7474-
// parameters as dependent, unresolved.
7475-
SmallVector<GenericParamList *, 2> gpLists;
7476-
if (gpl->getOuterParameters() && !parentSig) {
7477-
for (auto *outerParams = gpl;
7473+
DeclContext *lookupDC = nullptr;
7474+
7475+
const auto visitRequirement = [&](const Requirement &req,
7476+
RequirementRepr *reqRepr) {
7477+
const auto source = FloatingRequirementSource::forExplicit(reqRepr);
7478+
7479+
// If we're extending a protocol and adding a redundant requirement,
7480+
// for example, `extension Foo where Self: Foo`, then emit a
7481+
// diagnostic.
7482+
7483+
if (auto decl = lookupDC->getAsDecl()) {
7484+
if (auto extDecl = dyn_cast<ExtensionDecl>(decl)) {
7485+
auto extType = extDecl->getDeclaredInterfaceType();
7486+
auto extSelfType = extDecl->getSelfInterfaceType();
7487+
auto reqLHSType = req.getFirstType();
7488+
auto reqRHSType = req.getSecondType();
7489+
7490+
if (extType->isExistentialType() &&
7491+
reqLHSType->isEqual(extSelfType) &&
7492+
reqRHSType->isEqual(extType)) {
7493+
7494+
auto &ctx = extDecl->getASTContext();
7495+
ctx.Diags.diagnose(extDecl->getLoc(),
7496+
diag::protocol_extension_redundant_requirement,
7497+
extType->getString(),
7498+
extSelfType->getString(),
7499+
reqRHSType->getString());
7500+
}
7501+
}
7502+
}
7503+
7504+
builder.addRequirement(req, reqRepr, source, nullptr,
7505+
lookupDC->getParentModule());
7506+
return false;
7507+
};
7508+
7509+
GenericParamList *genericParams = nullptr;
7510+
if (auto params = paramSource.dyn_cast<GenericParamList *>())
7511+
genericParams = params;
7512+
else
7513+
genericParams = paramSource.get<GenericContext *>()->getGenericParams();
7514+
7515+
if (genericParams) {
7516+
// Extensions never have a parent signature.
7517+
if (genericParams->getOuterParameters())
7518+
assert(parentSig == nullptr);
7519+
7520+
// Type check the generic parameters, treating all generic type
7521+
// parameters as dependent, unresolved.
7522+
SmallVector<GenericParamList *, 2> gpLists;
7523+
for (auto *outerParams = genericParams;
74787524
outerParams != nullptr;
74797525
outerParams = outerParams->getOuterParameters()) {
74807526
gpLists.push_back(outerParams);
74817527
}
7482-
} else {
7483-
gpLists.push_back(gpl);
7484-
}
74857528

7486-
// The generic parameter lists MUST appear from innermost to outermost.
7487-
// We walk them backwards to order outer requirements before
7488-
// inner requirements.
7489-
for (auto &genericParams : llvm::reverse(gpLists)) {
7490-
assert(genericParams->size() > 0 &&
7491-
"Parsed an empty generic parameter list?");
7529+
// The generic parameter lists MUST appear from innermost to outermost.
7530+
// We walk them backwards to order outer requirements before
7531+
// inner requirements.
7532+
for (auto &genericParams : llvm::reverse(gpLists)) {
7533+
assert(genericParams->size() > 0 &&
7534+
"Parsed an empty generic parameter list?");
74927535

7493-
// Determine where and how to perform name lookup.
7494-
DeclContext *lookupDC = genericParams->begin()[0]->getDeclContext();
7536+
// First, add the generic parameters to the generic signature builder.
7537+
// Do this before checking the inheritance clause, since it may
7538+
// itself be dependent on one of these parameters.
7539+
for (const auto param : *genericParams)
7540+
builder.addGenericParameter(param);
74957541

7496-
// First, add the generic parameters to the generic signature builder.
7497-
// Do this before checking the inheritance clause, since it may
7498-
// itself be dependent on one of these parameters.
7499-
for (auto param : *genericParams)
7500-
builder.addGenericParameter(param);
7542+
// Add the requirements for each of the generic parameters to the builder.
7543+
// Now, check the inheritance clauses of each parameter.
7544+
for (const auto param : *genericParams)
7545+
builder.addGenericParameterRequirements(param);
75017546

7502-
// Add the requirements for each of the generic parameters to the builder.
7503-
// Now, check the inheritance clauses of each parameter.
7504-
for (auto param : *genericParams)
7505-
builder.addGenericParameterRequirements(param);
7547+
// Determine where and how to perform name lookup.
7548+
lookupDC = genericParams->begin()[0]->getDeclContext();
75067549

7507-
// Add the requirements clause to the builder.
7550+
// Add the requirements clause to the builder.
7551+
WhereClauseOwner(lookupDC, genericParams)
7552+
.visitRequirements(TypeResolutionStage::Structural,
7553+
visitRequirement);
7554+
}
7555+
} else {
7556+
// The declaration has a where clause, but no generic parameters of its own.
7557+
const auto ctx = paramSource.get<GenericContext *>();
75087558

7509-
using FloatingRequirementSource =
7510-
GenericSignatureBuilder::FloatingRequirementSource;
7511-
WhereClauseOwner(lookupDC, genericParams).visitRequirements(
7512-
TypeResolutionStage::Structural,
7513-
[&](const Requirement &req, RequirementRepr *reqRepr) {
7514-
auto source = FloatingRequirementSource::forExplicit(reqRepr);
7515-
7516-
// If we're extending a protocol and adding a redundant requirement,
7517-
// for example, `extension Foo where Self: Foo`, then emit a
7518-
// diagnostic.
7519-
7520-
if (auto decl = lookupDC->getAsDecl()) {
7521-
if (auto extDecl = dyn_cast<ExtensionDecl>(decl)) {
7522-
auto extType = extDecl->getDeclaredInterfaceType();
7523-
auto extSelfType = extDecl->getSelfInterfaceType();
7524-
auto reqLHSType = req.getFirstType();
7525-
auto reqRHSType = req.getSecondType();
7526-
7527-
if (extType->isExistentialType() &&
7528-
reqLHSType->isEqual(extSelfType) &&
7529-
reqRHSType->isEqual(extType)) {
7530-
7531-
auto &ctx = extDecl->getASTContext();
7532-
ctx.Diags.diagnose(extDecl->getLoc(),
7533-
diag::protocol_extension_redundant_requirement,
7534-
extType->getString(),
7535-
extSelfType->getString(),
7536-
reqRHSType->getString());
7537-
}
7538-
}
7539-
}
7540-
7541-
builder.addRequirement(req, reqRepr, source, nullptr,
7542-
lookupDC->getParentModule());
7543-
return false;
7544-
});
7559+
assert(ctx->getTrailingWhereClause() && "No params or where clause");
7560+
7561+
// Determine where and how to perform name lookup.
7562+
lookupDC = ctx;
7563+
7564+
WhereClauseOwner(ctx).visitRequirements(
7565+
TypeResolutionStage::Structural, visitRequirement);
75457566
}
75467567

75477568
/// Perform any remaining requirement inference.

lib/Parse/ParseGeneric.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,9 @@ ParserStatus Parser::parseGenericWhereClause(
392392
}
393393

394394

395-
/// Parse a free-standing where clause attached to a declaration, adding it to
396-
/// a generic parameter list that may (or may not) already exist.
395+
/// Parse a free-standing where clause attached to a declaration,
396+
/// adding it to a generic parameter list, if any, or to the given
397+
/// generic context representing the declaration.
397398
ParserStatus Parser::
398399
parseFreestandingGenericWhereClause(GenericContext *genCtx,
399400
GenericParamList *&genericParams,

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -450,16 +450,17 @@ void TypeChecker::checkReferencedGenericParams(GenericContext *dc) {
450450
///
451451

452452
GenericSignature TypeChecker::checkGenericSignature(
453-
GenericParamList *genericParamList,
453+
GenericParamSource paramSource,
454454
DeclContext *dc,
455455
GenericSignature parentSig,
456456
bool allowConcreteGenericParams,
457457
SmallVector<Requirement, 2> additionalRequirements,
458458
SmallVector<TypeLoc, 2> inferenceSources) {
459-
assert(genericParamList && "Missing generic parameters?");
459+
if (auto genericParamList = paramSource.dyn_cast<GenericParamList *>())
460+
assert(genericParamList && "Missing generic parameters?");
460461

461462
auto request = InferredGenericSignatureRequest{
462-
dc->getParentModule(), parentSig.getPointer(), genericParamList,
463+
dc->getParentModule(), parentSig.getPointer(), paramSource,
463464
additionalRequirements, inferenceSources,
464465
allowConcreteGenericParams};
465466
auto sig = evaluateOrDefault(dc->getASTContext().evaluator,
@@ -489,7 +490,7 @@ GenericSignature TypeChecker::checkGenericSignature(
489490
/// extension's list of generic parameters.
490491
static Type formExtensionInterfaceType(
491492
ExtensionDecl *ext, Type type,
492-
GenericParamList *genericParams,
493+
const GenericParamList *genericParams,
493494
SmallVectorImpl<Requirement> &sameTypeReqs,
494495
bool &mustInferRequirements) {
495496
if (type->is<ErrorType>())
@@ -602,28 +603,45 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
602603
return sig;
603604
}
604605

605-
// We can fast-path computing the generic signature of non-generic
606-
// declarations by re-using the parent context's signature.
607-
auto *gp = GC->getGenericParams();
608-
if (!gp) {
609-
return GC->getParent()->getGenericSignatureOfContext();
610-
}
606+
bool allowConcreteGenericParams = false;
607+
const auto *genericParams = GC->getGenericParams();
608+
if (genericParams) {
609+
// Setup the depth of the generic parameters.
610+
const_cast<GenericParamList *>(genericParams)
611+
->setDepth(GC->getGenericContextDepth());
612+
613+
// Accessors can always use the generic context of their storage
614+
// declarations. This is a compile-time optimization since it lets us
615+
// avoid the requirements-gathering phase, but it also simplifies that
616+
// work for accessors which don't mention the value type in their formal
617+
// signatures (like the read and modify coroutines, since yield types
618+
// aren't tracked in the AST type yet).
619+
if (auto accessor = dyn_cast<AccessorDecl>(GC->getAsDecl())) {
620+
return cast<SubscriptDecl>(accessor->getStorage())->getGenericSignature();
621+
}
622+
623+
// ...or we may have a where clause dependent on outer generic parameters.
624+
} else if (const auto *where = GC->getTrailingWhereClause()) {
625+
// If there is no generic context for the where clause to
626+
// rely on, diagnose that now and bail out.
627+
if (!GC->isGenericContext()) {
628+
GC->getASTContext().Diags.diagnose(where->getWhereLoc(),
629+
diag::where_nongeneric_ctx);
630+
return nullptr;
631+
}
611632

612-
// Setup the depth of the generic parameters.
613-
gp->setDepth(GC->getGenericContextDepth());
614-
615-
// Accessors can always use the generic context of their storage
616-
// declarations. This is a compile-time optimization since it lets us
617-
// avoid the requirements-gathering phase, but it also simplifies that
618-
// work for accessors which don't mention the value type in their formal
619-
// signatures (like the read and modify coroutines, since yield types
620-
// aren't tracked in the AST type yet).
621-
if (auto accessor = dyn_cast<AccessorDecl>(GC->getAsDecl())) {
622-
return cast<SubscriptDecl>(accessor->getStorage())->getGenericSignature();
633+
allowConcreteGenericParams = true;
634+
} else {
635+
// We can fast-path computing the generic signature of non-generic
636+
// declarations by re-using the parent context's signature.
637+
if (auto accessor = dyn_cast<AccessorDecl>(GC->getAsDecl()))
638+
if (auto subscript = dyn_cast<SubscriptDecl>(accessor->getStorage()))
639+
return subscript->getGenericSignature();
640+
641+
return GC->getParent()->getGenericSignatureOfContext();
623642
}
624643

625644
auto parentSig = GC->getParent()->getGenericSignatureOfContext();
626-
bool allowConcreteGenericParams = false;
627645
SmallVector<TypeLoc, 2> inferenceSources;
628646
SmallVector<Requirement, 2> sameTypeReqs;
629647
if (auto VD = dyn_cast_or_null<ValueDecl>(GC->getAsDecl())) {
@@ -685,11 +703,11 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
685703
bool mustInferRequirements = false;
686704
Type extInterfaceType =
687705
formExtensionInterfaceType(ext, ext->getExtendedType(),
688-
gp, sameTypeReqs,
706+
genericParams, sameTypeReqs,
689707
mustInferRequirements);
690708

691709
auto cannotReuseNominalSignature = [&]() -> bool {
692-
const auto finalDepth = gp->getParams().back()->getDepth();
710+
const auto finalDepth = genericParams->getParams().back()->getDepth();
693711
return mustInferRequirements
694712
|| !sameTypeReqs.empty()
695713
|| ext->getTrailingWhereClause()
@@ -717,7 +735,7 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
717735
}
718736

719737
return TypeChecker::checkGenericSignature(
720-
gp, GC, parentSig,
738+
GC, GC, parentSig,
721739
allowConcreteGenericParams,
722740
sameTypeReqs, inferenceSources);
723741
}

0 commit comments

Comments
 (0)