Skip to content

Commit 78e5607

Browse files
committed
AST: Introduce ExtensionDecl::createGenericParamsIfMissing()
For now Sema still calls it manually, but soon we could make getGenericParams() lazy, calling this automatically, since there's really no reason to create the generic parameters upfront when binding the extension.
1 parent adb82a5 commit 78e5607

File tree

3 files changed

+110
-102
lines changed

3 files changed

+110
-102
lines changed

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,6 +1761,8 @@ class ExtensionDecl final : public GenericContext, public Decl,
17611761
return getValidationState() > ValidationState::CheckingWithValidSignature;
17621762
}
17631763

1764+
void createGenericParamsIfMissing(NominalTypeDecl *nominal);
1765+
17641766
bool hasDefaultAccessLevel() const {
17651767
return Bits.ExtensionDecl.DefaultAndMaxAccessLevel != 0;
17661768
}

lib/AST/Decl.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,113 @@ AccessLevel ExtensionDecl::getMaxAccessLevel() const {
10561056
{AccessLevel::Private, AccessLevel::Private}).second;
10571057
}
10581058

1059+
/// Clone the given generic parameters in the given list. We don't need any
1060+
/// of the requirements, because they will be inferred.
1061+
static GenericParamList *cloneGenericParams(ASTContext &ctx,
1062+
DeclContext *dc,
1063+
GenericParamList *fromParams) {
1064+
// Clone generic parameters.
1065+
SmallVector<GenericTypeParamDecl *, 2> toGenericParams;
1066+
for (auto fromGP : *fromParams) {
1067+
// Create the new generic parameter.
1068+
auto toGP = new (ctx) GenericTypeParamDecl(dc, fromGP->getName(),
1069+
SourceLoc(),
1070+
fromGP->getDepth(),
1071+
fromGP->getIndex());
1072+
toGP->setImplicit(true);
1073+
1074+
// Record new generic parameter.
1075+
toGenericParams.push_back(toGP);
1076+
}
1077+
1078+
auto toParams = GenericParamList::create(ctx, SourceLoc(), toGenericParams,
1079+
SourceLoc());
1080+
1081+
auto outerParams = fromParams->getOuterParameters();
1082+
if (outerParams != nullptr)
1083+
outerParams = cloneGenericParams(ctx, dc, outerParams);
1084+
toParams->setOuterParameters(outerParams);
1085+
1086+
return toParams;
1087+
}
1088+
1089+
/// Ensure that the outer generic parameters of the given generic
1090+
/// context have been configured.
1091+
static void configureOuterGenericParams(const GenericContext *dc) {
1092+
auto genericParams = dc->getGenericParams();
1093+
1094+
// If we already configured the outer parameters, we're done.
1095+
if (genericParams && genericParams->getOuterParameters())
1096+
return;
1097+
1098+
DeclContext *outerDC = dc->getParent();
1099+
while (!outerDC->isModuleScopeContext()) {
1100+
if (auto outerDecl = outerDC->getAsDecl()) {
1101+
if (auto outerGenericDC = outerDecl->getAsGenericContext()) {
1102+
if (genericParams)
1103+
genericParams->setOuterParameters(outerGenericDC->getGenericParams());
1104+
1105+
configureOuterGenericParams(outerGenericDC);
1106+
return;
1107+
}
1108+
}
1109+
1110+
outerDC = outerDC->getParent();
1111+
}
1112+
}
1113+
1114+
void ExtensionDecl::createGenericParamsIfMissing(NominalTypeDecl *nominal) {
1115+
if (getGenericParams())
1116+
return;
1117+
1118+
// Hack to force generic parameter lists of protocols to be created if the
1119+
// nominal is an (invalid) nested type of a protocol.
1120+
DeclContext *outerDC = nominal;
1121+
while (!outerDC->isModuleScopeContext()) {
1122+
if (auto *proto = dyn_cast<ProtocolDecl>(outerDC))
1123+
proto->createGenericParamsIfMissing();
1124+
1125+
outerDC = outerDC->getParent();
1126+
}
1127+
1128+
configureOuterGenericParams(nominal);
1129+
1130+
if (auto proto = dyn_cast<ProtocolDecl>(nominal)) {
1131+
// For a protocol extension, build the generic parameter list directly
1132+
// since we want it to have an inheritance clause.
1133+
setGenericParams(proto->createGenericParams(this));
1134+
} else if (auto genericParams = nominal->getGenericParamsOfContext()) {
1135+
// Clone the generic parameter list of a generic type.
1136+
setGenericParams(
1137+
cloneGenericParams(getASTContext(), this, genericParams));
1138+
}
1139+
1140+
// Set the depth of every generic parameter.
1141+
auto *genericParams = getGenericParams();
1142+
for (auto *outerParams = genericParams;
1143+
outerParams != nullptr;
1144+
outerParams = outerParams->getOuterParameters())
1145+
outerParams->configureGenericParamDepth();
1146+
1147+
// If we have a trailing where clause, deal with it now.
1148+
// For now, trailing where clauses are only permitted on protocol extensions.
1149+
if (auto trailingWhereClause = getTrailingWhereClause()) {
1150+
if (genericParams) {
1151+
// Merge the trailing where clause into the generic parameter list.
1152+
// FIXME: Long-term, we'd like clients to deal with the trailing where
1153+
// clause explicitly, but for now it's far more direct to represent
1154+
// the trailing where clause as part of the requirements.
1155+
genericParams->addTrailingWhereClause(
1156+
getASTContext(),
1157+
trailingWhereClause->getWhereLoc(),
1158+
trailingWhereClause->getRequirements());
1159+
}
1160+
1161+
// If there's no generic parameter list, the where clause is diagnosed
1162+
// in typeCheckDecl().
1163+
}
1164+
}
1165+
10591166
PatternBindingDecl::PatternBindingDecl(SourceLoc StaticLoc,
10601167
StaticSpellingKind StaticSpelling,
10611168
SourceLoc VarLoc,

lib/Sema/TypeChecker.cpp

Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -255,114 +255,13 @@ Type TypeChecker::lookupBoolType(const DeclContext *dc) {
255255
return *boolType;
256256
}
257257

258-
/// Clone the given generic parameters in the given list. We don't need any
259-
/// of the requirements, because they will be inferred.
260-
static GenericParamList *cloneGenericParams(ASTContext &ctx,
261-
DeclContext *dc,
262-
GenericParamList *fromParams) {
263-
// Clone generic parameters.
264-
SmallVector<GenericTypeParamDecl *, 2> toGenericParams;
265-
for (auto fromGP : *fromParams) {
266-
// Create the new generic parameter.
267-
auto toGP = new (ctx) GenericTypeParamDecl(dc, fromGP->getName(),
268-
SourceLoc(),
269-
fromGP->getDepth(),
270-
fromGP->getIndex());
271-
toGP->setImplicit(true);
272-
273-
// Record new generic parameter.
274-
toGenericParams.push_back(toGP);
275-
}
276-
277-
auto toParams = GenericParamList::create(ctx, SourceLoc(), toGenericParams,
278-
SourceLoc());
279-
280-
auto outerParams = fromParams->getOuterParameters();
281-
if (outerParams != nullptr)
282-
outerParams = cloneGenericParams(ctx, dc, outerParams);
283-
toParams->setOuterParameters(outerParams);
284-
285-
return toParams;
286-
}
287-
288-
/// Ensure that the outer generic parameters of the given generic
289-
/// context have been configured.
290-
static void configureOuterGenericParams(const GenericContext *dc) {
291-
auto genericParams = dc->getGenericParams();
292-
293-
// If we already configured the outer parameters, we're done.
294-
if (genericParams && genericParams->getOuterParameters())
295-
return;
296-
297-
DeclContext *outerDC = dc->getParent();
298-
while (!outerDC->isModuleScopeContext()) {
299-
if (auto outerDecl = outerDC->getAsDecl()) {
300-
if (auto outerGenericDC = outerDecl->getAsGenericContext()) {
301-
if (genericParams)
302-
genericParams->setOuterParameters(outerGenericDC->getGenericParams());
303-
304-
configureOuterGenericParams(outerGenericDC);
305-
return;
306-
}
307-
}
308-
309-
outerDC = outerDC->getParent();
310-
}
311-
}
312-
313258
/// Bind the given extension to the given nominal type.
314259
static void bindExtensionToNominal(ExtensionDecl *ext,
315260
NominalTypeDecl *nominal) {
316261
if (ext->alreadyBoundToNominal())
317262
return;
318263

319-
// Hack to force generic parameter lists of protocols to be created if the
320-
// nominal is an (invalid) nested type of a protocol.
321-
DeclContext *outerDC = nominal;
322-
while (!outerDC->isModuleScopeContext()) {
323-
if (auto *proto = dyn_cast<ProtocolDecl>(outerDC))
324-
proto->createGenericParamsIfMissing();
325-
326-
outerDC = outerDC->getParent();
327-
}
328-
329-
configureOuterGenericParams(nominal);
330-
331-
if (auto proto = dyn_cast<ProtocolDecl>(nominal)) {
332-
// For a protocol extension, build the generic parameter list directly
333-
// since we want it to have an inheritance clause.
334-
ext->setGenericParams(proto->createGenericParams(ext));
335-
} else if (auto genericParams = nominal->getGenericParamsOfContext()) {
336-
// Clone the generic parameter list of a generic type.
337-
ext->setGenericParams(
338-
cloneGenericParams(ext->getASTContext(), ext, genericParams));
339-
}
340-
341-
// Set the depth of every generic parameter.
342-
auto *genericParams = ext->getGenericParams();
343-
for (auto *outerParams = genericParams;
344-
outerParams != nullptr;
345-
outerParams = outerParams->getOuterParameters())
346-
outerParams->configureGenericParamDepth();
347-
348-
// If we have a trailing where clause, deal with it now.
349-
// For now, trailing where clauses are only permitted on protocol extensions.
350-
if (auto trailingWhereClause = ext->getTrailingWhereClause()) {
351-
if (genericParams) {
352-
// Merge the trailing where clause into the generic parameter list.
353-
// FIXME: Long-term, we'd like clients to deal with the trailing where
354-
// clause explicitly, but for now it's far more direct to represent
355-
// the trailing where clause as part of the requirements.
356-
genericParams->addTrailingWhereClause(
357-
ext->getASTContext(),
358-
trailingWhereClause->getWhereLoc(),
359-
trailingWhereClause->getRequirements());
360-
}
361-
362-
// If there's no generic parameter list, the where clause is diagnosed
363-
// in typeCheckDecl().
364-
}
365-
264+
ext->createGenericParamsIfMissing(nominal);
366265
nominal->addExtension(ext);
367266
}
368267

0 commit comments

Comments
 (0)