Skip to content

Commit 9fa2a8b

Browse files
committed
Don’t create a new generic signature builder for non-generic members.
When type-checking a function or subscript that itself does not have generic parameters (but is within a generic context), we were creating a generic signature builder which will always produce the same generic signature as the enclosing context. Stop creating that generic signature builder. Instead, teach the CompleteGenericTypeResolver to use the generic signature + the canonical generic signature builder for that signature to resolve types, which also eliminates some extraneous re-type-checking. Improves type-checking performance of the standard library by 36%.
1 parent 5e77efe commit 9fa2a8b

File tree

10 files changed

+178
-159
lines changed

10 files changed

+178
-159
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4591,7 +4591,7 @@ class ParamDecl : public VarDecl {
45914591
/// Clone constructor, allocates a new ParamDecl identical to the first.
45924592
/// Intentionally not defined as a typical copy constructor to avoid
45934593
/// accidental copies.
4594-
ParamDecl(ParamDecl *PD);
4594+
ParamDecl(ParamDecl *PD, bool withTypes);
45954595

45964596
/// Retrieve the argument (API) name for this function parameter.
45974597
Identifier getArgumentName() const { return ArgumentName; }

include/swift/AST/ParameterList.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,15 @@ class alignas(ParamDecl *) ParameterList final :
128128
Implicit = 0x01,
129129
/// The cloned pattern is for an inherited constructor; mark default
130130
/// arguments as inherited, and mark unnamed arguments as named.
131-
Inherited = 0x02
131+
Inherited = 0x02,
132+
/// The cloned pattern will strip type information.
133+
WithoutTypes = 0x04,
132134
};
133-
135+
136+
friend OptionSet<CloneFlags> operator|(CloneFlags flag1, CloneFlags flag2) {
137+
return OptionSet<CloneFlags>(flag1) | flag2;
138+
}
139+
134140
/// Make a duplicate copy of this parameter list. This allocates copies of
135141
/// the ParamDecls, so they can be reparented into a new DeclContext.
136142
ParameterList *clone(const ASTContext &C,

lib/AST/Decl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4217,18 +4217,22 @@ ParamDecl::ParamDecl(Specifier specifier,
42174217

42184218
/// Clone constructor, allocates a new ParamDecl identical to the first.
42194219
/// Intentionally not defined as a copy constructor to avoid accidental copies.
4220-
ParamDecl::ParamDecl(ParamDecl *PD)
4220+
ParamDecl::ParamDecl(ParamDecl *PD, bool withTypes)
42214221
: VarDecl(DeclKind::Param, /*IsStatic*/false, PD->getSpecifier(),
42224222
/*IsCaptureList*/false, PD->getNameLoc(), PD->getName(),
4223-
PD->hasType() ? PD->getType() : Type(), PD->getDeclContext()),
4223+
PD->hasType() && withTypes? PD->getType() : Type(),
4224+
PD->getDeclContext()),
42244225
ArgumentName(PD->getArgumentName()),
42254226
ArgumentNameLoc(PD->getArgumentNameLoc()),
42264227
SpecifierLoc(PD->getSpecifierLoc()),
42274228
DefaultValueAndIsVariadic(nullptr, PD->DefaultValueAndIsVariadic.getInt()),
42284229
IsTypeLocImplicit(PD->IsTypeLocImplicit),
42294230
defaultArgumentKind(PD->defaultArgumentKind) {
42304231
typeLoc = PD->getTypeLoc().clone(PD->getASTContext());
4231-
if (PD->hasInterfaceType())
4232+
if (!withTypes && typeLoc.getTypeRepr())
4233+
typeLoc.setType(Type());
4234+
4235+
if (withTypes && PD->hasInterfaceType())
42324236
setInterfaceType(PD->getInterfaceType());
42334237
}
42344238

lib/AST/Parameter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,12 @@ ParameterList *ParameterList::clone(const ASTContext &C,
8888
SmallVector<ParamDecl*, 8> params(begin(), end());
8989

9090
// Remap the ParamDecls inside of the ParameterList.
91+
bool withTypes = !options.contains(ParameterList::WithoutTypes);
9192
for (auto &decl : params) {
9293
bool hadDefaultArgument =
9394
decl->getDefaultArgumentKind() == DefaultArgumentKind::Normal;
9495

95-
decl = new (C) ParamDecl(decl);
96+
decl = new (C) ParamDecl(decl, withTypes);
9697
if (options & Implicit)
9798
decl->setImplicit();
9899

lib/Sema/CodeSynthesis.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ buildIndexForwardingParamList(AbstractStorageDecl *storage,
104104

105105
// Clone the parameter list over for a new decl, so we get new ParamDecls.
106106
auto indices = subscript->getIndices()->clone(context,
107-
ParameterList::Implicit);
107+
ParameterList::Implicit|
108+
ParameterList::WithoutTypes);
108109
if (prefix.empty())
109110
return indices;
110111

lib/Sema/GenericTypeResolver.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,14 @@ class ProtocolRequirementTypeResolver : public GenericTypeResolver {
130130
/// to check the signature of a generic declaration and resolve (for example)
131131
/// all dependent member refers to archetype members.
132132
class CompleteGenericTypeResolver : public GenericTypeResolver {
133-
TypeChecker &TC;
134-
GenericSignatureBuilder &Builder;
135-
ArrayRef<GenericTypeParamType *> GenericParams;
133+
TypeChecker &tc;
134+
GenericSignature *genericSig;
135+
ModuleDecl &module;
136+
GenericSignatureBuilder &builder;
136137

137138
public:
138-
CompleteGenericTypeResolver(TypeChecker &tc, GenericSignatureBuilder &builder,
139-
ArrayRef<GenericTypeParamType *> genericParams)
140-
: TC(tc), Builder(builder), GenericParams(genericParams) { }
139+
CompleteGenericTypeResolver(TypeChecker &tc, GenericSignature *genericSig,
140+
ModuleDecl &module);
141141

142142
virtual Type mapTypeIntoContext(Type type);
143143

lib/Sema/TypeCheckDecl.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5233,10 +5233,18 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
52335233
// Revert the types within the signature so it can be type-checked with
52345234
// archetypes below.
52355235
TC.revertGenericFuncSignature(FD);
5236-
} else if (FD->getDeclContext()->getGenericSignatureOfContext()) {
5237-
(void)TC.validateGenericFuncSignature(FD);
5238-
// Revert all of the types within the signature of the function.
5239-
TC.revertGenericFuncSignature(FD);
5236+
} else if (auto genericSig =
5237+
FD->getDeclContext()->getGenericSignatureOfContext()) {
5238+
if (!FD->getAccessorStorageDecl()) {
5239+
(void)TC.validateGenericFuncSignature(FD);
5240+
5241+
// Revert all of the types within the signature of the function.
5242+
TC.revertGenericFuncSignature(FD);
5243+
} else {
5244+
// We've inherited all of the type information already.
5245+
TC.configureInterfaceType(FD, genericSig);
5246+
}
5247+
52405248
FD->setGenericEnvironment(
52415249
FD->getDeclContext()->getGenericEnvironmentOfContext());
52425250
}

0 commit comments

Comments
 (0)