Skip to content

Commit 6ca148d

Browse files
committed
AST: Optimize removeShadowedDecls()
Previously, whenever name lookup returned two declarations with the same name, we would compute the canonical type of each one as part of the shadowing check. The canonical type calculation is rather expensive for GenericFunctionTypes since it requires constructing a GenericSignatureBuilder to canonicalize type parameters that appear in the function's signature. Instead, let's first shard all declarations that have the same name by their generic signature. If two declarations have the same signature, only then do we proceed to compute their canonical type. Since computing a canonical GenericSignature is cheaper than computing a canonical GenericFunctionType, this should speed up name lookup of heavily-overloaded names, such as operators. Fixes <rdar://problem/56800097>.
1 parent a676a37 commit 6ca148d

File tree

2 files changed

+86
-37
lines changed

2 files changed

+86
-37
lines changed

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2810,7 +2810,7 @@ CanType ValueDecl::getOverloadSignatureType() const {
28102810
// implementation of the swift::conflicting overload that deals with
28112811
// overload types, in order to account for cases where the overload types
28122812
// don't match, but the decls differ and therefore always conflict.
2813-
2813+
assert(isa<TypeDecl>(this));
28142814
return CanType();
28152815
}
28162816

lib/AST/NameLookup.cpp

Lines changed: 85 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,13 @@ static ConstructorComparison compareConstructors(ConstructorDecl *ctor1,
244244
return ConstructorComparison::Same;
245245
}
246246

247-
/// Given a set of declarations whose names and signatures have matched,
247+
/// Given a set of declarations whose names and interface types have matched,
248248
/// figure out which of these declarations have been shadowed by others.
249249
template <typename T>
250-
static void
251-
recordShadowedDeclsAfterSignatureMatch(ArrayRef<T> decls, const DeclContext *dc,
252-
llvm::SmallPtrSetImpl<T> &shadowed) {
250+
static void recordShadowedDeclsAfterTypeMatch(
251+
ArrayRef<T> decls,
252+
const DeclContext *dc,
253+
llvm::SmallPtrSetImpl<T> &shadowed) {
253254
assert(decls.size() > 1 && "Nothing collided");
254255

255256
// Compare each declaration to every other declaration. This is
@@ -491,6 +492,48 @@ recordShadowedDeclsAfterSignatureMatch(ArrayRef<T> decls, const DeclContext *dc,
491492
}
492493
}
493494

495+
/// Given a set of declarations whose names and generic signatures have matched,
496+
/// figure out which of these declarations have been shadowed by others.
497+
static void recordShadowedDeclsAfterSignatureMatch(
498+
ArrayRef<ValueDecl *> decls,
499+
const DeclContext *dc,
500+
llvm::SmallPtrSetImpl<ValueDecl *> &shadowed) {
501+
assert(decls.size() > 1 && "Nothing collided");
502+
503+
// Categorize all of the declarations based on their overload types.
504+
llvm::SmallDenseMap<CanType, llvm::TinyPtrVector<ValueDecl *>> collisions;
505+
llvm::SmallVector<CanType, 2> collisionTypes;
506+
507+
for (auto decl : decls) {
508+
assert(!isa<TypeDecl>(decl));
509+
510+
CanType type;
511+
512+
// FIXME: The type of a variable or subscript doesn't include
513+
// enough context to distinguish entities from different
514+
// constrained extensions, so use the overload signature's
515+
// type. This is layering a partial fix upon a total hack.
516+
if (auto asd = dyn_cast<AbstractStorageDecl>(decl))
517+
type = asd->getOverloadSignatureType();
518+
else
519+
type = decl->getInterfaceType()->getCanonicalType();
520+
521+
// Record this declaration based on its signature.
522+
auto &known = collisions[type];
523+
if (known.size() == 1) {
524+
collisionTypes.push_back(type);
525+
}
526+
known.push_back(decl);
527+
}
528+
529+
// Check whether we have shadowing for signature collisions.
530+
for (auto type : collisionTypes) {
531+
ArrayRef<ValueDecl *> collidingDecls = collisions[type];
532+
recordShadowedDeclsAfterTypeMatch(collidingDecls, dc,
533+
shadowed);
534+
}
535+
}
536+
494537
/// Look through the given set of declarations (that all have the same name),
495538
/// recording those that are shadowed by another declaration in the
496539
/// \c shadowed set.
@@ -526,14 +569,23 @@ static void recordShadowedDecls(ArrayRef<ValueDecl *> decls,
526569
if (decls.size() < 2)
527570
return;
528571

572+
llvm::TinyPtrVector<ValueDecl *> typeDecls;
573+
529574
// Categorize all of the declarations based on their overload signatures.
530-
llvm::SmallDenseMap<CanType, llvm::TinyPtrVector<ValueDecl *>> collisions;
531-
llvm::SmallVector<CanType, 2> collisionTypes;
532-
llvm::SmallDenseMap<NominalTypeDecl *, llvm::TinyPtrVector<ConstructorDecl *>>
575+
llvm::SmallDenseMap<const GenericSignatureImpl *,
576+
llvm::TinyPtrVector<ValueDecl *>> collisions;
577+
llvm::SmallVector<const GenericSignatureImpl *, 2> collisionSignatures;
578+
llvm::SmallDenseMap<NominalTypeDecl *,
579+
llvm::TinyPtrVector<ConstructorDecl *>>
533580
importedInitializerCollisions;
534-
llvm::TinyPtrVector<NominalTypeDecl *> importedInitializerCollectionTypes;
581+
llvm::TinyPtrVector<NominalTypeDecl *> importedInitializerCollisionTypes;
535582

536583
for (auto decl : decls) {
584+
if (auto *typeDecl = dyn_cast<TypeDecl>(decl)) {
585+
typeDecls.push_back(typeDecl);
586+
continue;
587+
}
588+
537589
// Specifically keep track of imported initializers, which can come from
538590
// Objective-C init methods, Objective-C factory methods, renamed C
539591
// functions, or be synthesized by the importer.
@@ -544,50 +596,47 @@ static void recordShadowedDecls(ArrayRef<ValueDecl *> decls,
544596
auto nominal = ctor->getDeclContext()->getSelfNominalTypeDecl();
545597
auto &knownInits = importedInitializerCollisions[nominal];
546598
if (knownInits.size() == 1) {
547-
importedInitializerCollectionTypes.push_back(nominal);
599+
importedInitializerCollisionTypes.push_back(nominal);
548600
}
549601
knownInits.push_back(ctor);
550602
}
551603
}
552604

553-
CanType signature;
605+
// If the decl is currently being validated, this is likely a recursive
606+
// reference and we'll want to skip ahead so as to avoid having its type
607+
// attempt to desugar itself.
608+
if (decl->isRecursiveValidation())
609+
continue;
554610

555-
if (!isa<TypeDecl>(decl)) {
556-
// If the decl is currently being validated, this is likely a recursive
557-
// reference and we'll want to skip ahead so as to avoid having its type
558-
// attempt to desugar itself.
559-
if (decl->isRecursiveValidation())
560-
continue;
561-
auto ifaceType = decl->getInterfaceType();
562-
563-
// FIXME: the canonical type makes a poor signature, because we don't
564-
// canonicalize away default arguments.
565-
signature = ifaceType->getCanonicalType();
566-
567-
// FIXME: The type of a variable or subscript doesn't include
568-
// enough context to distinguish entities from different
569-
// constrained extensions, so use the overload signature's
570-
// type. This is layering a partial fix upon a total hack.
571-
if (auto asd = dyn_cast<AbstractStorageDecl>(decl))
572-
signature = asd->getOverloadSignatureType();
573-
}
611+
CanGenericSignature signature;
612+
613+
auto *dc = decl->getInnermostDeclContext();
614+
if (auto genericSig = dc->getGenericSignatureOfContext())
615+
signature = genericSig->getCanonicalSignature();
574616

575617
// Record this declaration based on its signature.
576-
auto &known = collisions[signature];
618+
auto &known = collisions[signature.getPointer()];
577619
if (known.size() == 1) {
578-
collisionTypes.push_back(signature);
620+
collisionSignatures.push_back(signature.getPointer());
579621
}
622+
580623
known.push_back(decl);
581624
}
582625

626+
// Check whether we have shadowing for type declarations.
627+
if (typeDecls.size() > 1) {
628+
ArrayRef<ValueDecl *> collidingDecls = typeDecls;
629+
recordShadowedDeclsAfterTypeMatch(collidingDecls, dc, shadowed);
630+
}
631+
583632
// Check whether we have shadowing for signature collisions.
584-
for (auto signature : collisionTypes) {
633+
for (auto signature : collisionSignatures) {
585634
ArrayRef<ValueDecl *> collidingDecls = collisions[signature];
586635
recordShadowedDeclsAfterSignatureMatch(collidingDecls, dc, shadowed);
587636
}
588637

589638
// Check whether we have shadowing for imported initializer collisions.
590-
for (auto nominal : importedInitializerCollectionTypes) {
639+
for (auto nominal : importedInitializerCollisionTypes) {
591640
recordShadowedDeclsForImportedInits(importedInitializerCollisions[nominal],
592641
shadowed);
593642
}
@@ -597,15 +646,15 @@ static void
597646
recordShadowedDecls(ArrayRef<OperatorDecl *> decls, const DeclContext *dc,
598647
llvm::SmallPtrSetImpl<OperatorDecl *> &shadowed) {
599648
// Always considered to have the same signature.
600-
recordShadowedDeclsAfterSignatureMatch(decls, dc, shadowed);
649+
recordShadowedDeclsAfterTypeMatch(decls, dc, shadowed);
601650
}
602651

603652
static void
604653
recordShadowedDecls(ArrayRef<PrecedenceGroupDecl *> decls,
605654
const DeclContext *dc,
606655
llvm::SmallPtrSetImpl<PrecedenceGroupDecl *> &shadowed) {
607-
// Always considered to have the same signature.
608-
recordShadowedDeclsAfterSignatureMatch(decls, dc, shadowed);
656+
// Always considered to have the same type.
657+
recordShadowedDeclsAfterTypeMatch(decls, dc, shadowed);
609658
}
610659

611660
template <typename T, typename Container>

0 commit comments

Comments
 (0)