Skip to content

Commit eca5a1c

Browse files
committed
AST: Optimize getContextSubstitutionMap()
1 parent 26fffae commit eca5a1c

File tree

3 files changed

+98
-5
lines changed

3 files changed

+98
-5
lines changed

include/swift/AST/Types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,9 @@ END_CAN_TYPE_WRAPPER(AnyGenericType, Type)
15261526
/// fields exist at the same offset in memory to improve code generation of the
15271527
/// compiler itself.
15281528
class NominalOrBoundGenericNominalType : public AnyGenericType {
1529+
friend class TypeBase;
1530+
SubstitutionMap ContextSubMap;
1531+
15291532
public:
15301533
template <typename... Args>
15311534
NominalOrBoundGenericNominalType(Args &&...args)

lib/AST/SubstitutionMap.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,9 @@ Type SubstitutionMap::lookupSubstitution(CanSubstitutableType type) const {
258258

259259
// Find the index of the replacement type based on the generic parameter we
260260
// have.
261+
GenericSignature genericSig = getGenericSignature();
261262
auto genericParam = cast<GenericTypeParamType>(type);
262-
auto genericParams = getGenericSignature().getGenericParams();
263+
auto genericParams = genericSig.getGenericParams();
263264
auto replacementIndex =
264265
GenericParamKey(genericParam).findIndexIn(genericParams);
265266

lib/AST/TypeSubstitution.cpp

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,96 @@ Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass,
677677
return ErrorType::get(this);
678678
}
679679

680+
SubstitutionMap TypeBase::getContextSubstitutionMap() {
681+
// Fast path.
682+
auto *nominalTy = castTo<NominalOrBoundGenericNominalType>();
683+
if (nominalTy->ContextSubMap)
684+
return nominalTy->ContextSubMap;
685+
686+
auto nominal = nominalTy->getDecl();
687+
auto genericSig = nominal->getGenericSignature();
688+
if (!genericSig)
689+
return SubstitutionMap();
690+
691+
Type baseTy(this);
692+
693+
assert(!baseTy->hasLValueType() &&
694+
!baseTy->is<AnyMetatypeType>() &&
695+
!baseTy->is<ErrorType>());
696+
697+
// The resulting set of substitutions. Always use this to ensure we
698+
// don't miss out on NRVO anywhere.
699+
SmallVector<Type, 4> replacementTypes;
700+
701+
// Gather all of the substitutions for all levels of generic arguments.
702+
auto params = genericSig.getGenericParams();
703+
bool first = true;
704+
705+
while (baseTy) {
706+
// For a bound generic type, gather the generic parameter -> generic
707+
// argument substitutions.
708+
if (auto boundGeneric = baseTy->getAs<BoundGenericType>()) {
709+
auto args = boundGeneric->getGenericArgs();
710+
for (auto arg : llvm::reverse(args)) {
711+
replacementTypes.push_back(arg);
712+
}
713+
714+
// Continue looking into the parent.
715+
baseTy = boundGeneric->getParent();
716+
first = false;
717+
continue;
718+
}
719+
720+
// For an unbound generic type, fill in error types.
721+
if (auto unboundGeneric = baseTy->getAs<UnboundGenericType>()) {
722+
auto &ctx = getASTContext();
723+
auto decl = unboundGeneric->getDecl();
724+
for (auto *paramDecl : decl->getGenericParams()->getParams()) {
725+
replacementTypes.push_back(ErrorType::get(ctx));
726+
(void) paramDecl;
727+
}
728+
baseTy = unboundGeneric->getParent();
729+
first = false;
730+
continue;
731+
}
732+
733+
// This case indicates we have invalid nesting of types.
734+
if (auto protocolTy = baseTy->getAs<ProtocolType>()) {
735+
if (!first)
736+
break;
737+
738+
replacementTypes.push_back(getASTContext().TheErrorType);
739+
break;
740+
}
741+
742+
// Continue looking into the parent.
743+
if (auto nominalTy = baseTy->getAs<NominalType>()) {
744+
baseTy = nominalTy->getParent();
745+
first = false;
746+
continue;
747+
}
748+
749+
abort();
750+
}
751+
752+
ASSERT(replacementTypes.size() <= params.size());
753+
754+
// Add any outer generic parameters from the local context.
755+
while (replacementTypes.size() < params.size()) {
756+
replacementTypes.push_back(getASTContext().TheErrorType);
757+
}
758+
759+
std::reverse(replacementTypes.begin(), replacementTypes.end());
760+
761+
auto subMap = SubstitutionMap::get(
762+
genericSig,
763+
QueryReplacementTypeArray{genericSig, replacementTypes},
764+
LookUpConformanceInModule());
765+
766+
nominalTy->ContextSubMap = subMap;
767+
return subMap;
768+
}
769+
680770
TypeSubstitutionMap
681771
TypeBase::getContextSubstitutions(const DeclContext *dc,
682772
GenericEnvironment *genericEnv) {
@@ -805,13 +895,12 @@ TypeBase::getContextSubstitutions(const DeclContext *dc,
805895
return substitutions;
806896
}
807897

808-
SubstitutionMap TypeBase::getContextSubstitutionMap() {
809-
return getContextSubstitutionMap(getAnyNominal(), nullptr);
810-
}
811-
812898
SubstitutionMap TypeBase::getContextSubstitutionMap(
813899
const DeclContext *dc,
814900
GenericEnvironment *genericEnv) {
901+
if (dc == getAnyNominal() && genericEnv == nullptr)
902+
return getContextSubstitutionMap();
903+
815904
auto genericSig = dc->getGenericSignatureOfContext();
816905
if (genericSig.isNull())
817906
return SubstitutionMap();

0 commit comments

Comments
 (0)