Skip to content

Commit c040c71

Browse files
committed
AST: Remove some unnecessary SubstitutionList copies
ASTContext::getSpecializedConformance() already copies the substitutions, so remove some AllocateCopy() calls. Also, add a new overload taking a SubstitutionMap instead. This allows removing some gatherAllSubstitutions() calls, which have an allocation inside them. Finally, remove the now-unused ModuleDecl parameter from ProtocolConformance::subst() and make it public.
1 parent 69ae6cd commit c040c71

File tree

14 files changed

+103
-70
lines changed

14 files changed

+103
-70
lines changed

include/swift/AST/ASTContext.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -683,19 +683,38 @@ class ASTContext {
683683
takeDelayedConformanceDiags(NormalProtocolConformance *conformance);
684684

685685
/// \brief Produce a specialized conformance, which takes a generic
686-
/// conformance and substitutes
686+
/// conformance and substitutions written in terms of the generic
687+
/// conformance's signature.
687688
///
688689
/// \param type The type for which we are retrieving the conformance.
689690
///
690691
/// \param generic The generic conformance.
691692
///
692693
/// \param substitutions The set of substitutions required to produce the
693-
/// specialized conformance from the generic conformance.
694+
/// specialized conformance from the generic conformance. This list is
695+
/// copied so passing a temporary is permitted.
694696
SpecializedProtocolConformance *
695697
getSpecializedConformance(Type type,
696698
ProtocolConformance *generic,
697699
SubstitutionList substitutions);
698700

701+
/// \brief Produce a specialized conformance, which takes a generic
702+
/// conformance and substitutions written in terms of the generic
703+
/// conformance's signature.
704+
///
705+
/// \param type The type for which we are retrieving the conformance.
706+
///
707+
/// \param generic The generic conformance.
708+
///
709+
/// \param substitutions The set of substitutions required to produce the
710+
/// specialized conformance from the generic conformance. The keys must
711+
/// be generic parameters, not archetypes, so for example passing in
712+
/// TypeBase::getContextSubstitutionMap() is OK.
713+
SpecializedProtocolConformance *
714+
getSpecializedConformance(Type type,
715+
ProtocolConformance *generic,
716+
const SubstitutionMap &substitutions);
717+
699718
/// \brief Produce an inherited conformance, for subclasses of a type
700719
/// that already conforms to a protocol.
701720
///

include/swift/AST/ProtocolConformance.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -279,18 +279,15 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
279279

280280
/// Get the property declaration for a behavior conformance, if this is one.
281281
AbstractStorageDecl *getBehaviorDecl() const;
282-
283-
void dump() const;
284-
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;
285282

286-
private:
287-
friend class Substitution;
288283
/// Substitute the conforming type and produce a ProtocolConformance that
289284
/// applies to the substituted type.
290-
ProtocolConformance *subst(ModuleDecl *module,
291-
Type substType,
285+
ProtocolConformance *subst(Type substType,
292286
TypeSubstitutionFn subs,
293287
LookupConformanceFn conformances) const;
288+
289+
void dump() const;
290+
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;
294291
};
295292

296293
/// Normal protocol conformance, which involves mapping each of the protocol

include/swift/AST/Substitution.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,8 @@ class Substitution {
5757

5858
/// Apply a substitution to this substitution's replacement type and
5959
/// conformances.
60-
Substitution subst(ModuleDecl *module,
61-
const SubstitutionMap &subMap) const;
62-
Substitution subst(ModuleDecl *module,
63-
TypeSubstitutionFn subs,
60+
Substitution subst(const SubstitutionMap &subMap) const;
61+
Substitution subst(TypeSubstitutionFn subs,
6462
LookupConformanceFn conformances) const;
6563

6664
private:

include/swift/SIL/TypeSubstCloner.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
9393
}
9494

9595
CanType remapASTType(CanType ty) {
96-
return ty.subst(SubsMap, None)->getCanonicalType();
96+
return ty.subst(SubsMap)->getCanonicalType();
9797
}
9898

9999
Substitution remapSubstitution(Substitution sub) {
@@ -102,7 +102,7 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
102102
getASTTypeInClonedContext(sub.getReplacement()->getCanonicalType()),
103103
sub.getConformances());
104104
// Now remap the substitution.
105-
return sub.subst(SwiftMod, SubsMap);
105+
return sub.subst(SubsMap);
106106
}
107107

108108
ProtocolConformanceRef remapConformance(CanType type,
@@ -212,7 +212,7 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
212212
void visitWitnessMethodInst(WitnessMethodInst *Inst) {
213213
// Specialize the Self substitution of the witness_method.
214214
auto sub = Inst->getSelfSubstitution();
215-
sub = sub.subst(Inst->getModule().getSwiftModule(), SubsMap);
215+
sub = sub.subst(SubsMap);
216216

217217
assert(sub.getConformances().size() == 1 &&
218218
"didn't get conformance from substitution?!");

lib/AST/ASTContext.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,17 @@ ASTContext::getSpecializedConformance(Type type,
14571457
return result;
14581458
}
14591459

1460+
SpecializedProtocolConformance *
1461+
ASTContext::getSpecializedConformance(Type type,
1462+
ProtocolConformance *generic,
1463+
const SubstitutionMap &subMap) {
1464+
SmallVector<Substitution, 4> subs;
1465+
if (auto *genericSig = generic->getGenericSignature())
1466+
genericSig->getSubstitutions(subMap, subs);
1467+
1468+
return getSpecializedConformance(type, generic, subs);
1469+
}
1470+
14601471
InheritedProtocolConformance *
14611472
ASTContext::getInheritedConformance(Type type, ProtocolConformance *inherited) {
14621473
llvm::FoldingSetNodeID id;

lib/AST/Module.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -802,12 +802,10 @@ ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol,
802802
if (!explicitConformanceType->isEqual(type)) {
803803
// Gather the substitutions we need to map the generic conformance to
804804
// the specialized conformance.
805-
auto substitutions = type->gatherAllSubstitutions(this, resolver,
806-
explicitConformanceDC);
805+
auto subMap = type->getContextSubstitutionMap(this, explicitConformanceDC);
807806

808807
// Create the specialized conformance entry.
809-
auto result = ctx.getSpecializedConformance(type, conformance,
810-
substitutions);
808+
auto result = ctx.getSpecializedConformance(type, conformance, subMap);
811809
return ProtocolConformanceRef(result);
812810
}
813811
}

lib/AST/ProtocolConformance.cpp

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -546,10 +546,10 @@ bool ProtocolConformance::isVisibleFrom(const DeclContext *dc) const {
546546
return true;
547547
}
548548

549-
ProtocolConformance *ProtocolConformance::subst(ModuleDecl *module,
550-
Type substType,
551-
TypeSubstitutionFn subs,
552-
LookupConformanceFn conformances) const {
549+
ProtocolConformance *
550+
ProtocolConformance::subst(Type substType,
551+
TypeSubstitutionFn subs,
552+
LookupConformanceFn conformances) const {
553553
if (getType()->isEqual(substType))
554554
return const_cast<ProtocolConformance *>(this);
555555

@@ -561,10 +561,37 @@ ProtocolConformance *ProtocolConformance::subst(ModuleDecl *module,
561561
assert(getType()->getNominalOrBoundGenericNominal()
562562
== substType->getNominalOrBoundGenericNominal()
563563
&& "substitution mapped to different nominal?!");
564+
565+
// Since this is a normal conformance, the substitution maps archetypes
566+
// in the environment of the conformance to types containing archetypes
567+
// of some other generic environment.
568+
//
569+
// ASTContext::getSpecializedConformance() wants a substitution map
570+
// with interface types as keys, so do the mapping here.
571+
//
572+
// Once the type of a normal conformance becomes an interface type,
573+
// we can remove this.
574+
SubstitutionMap subMap;
575+
if (auto *genericSig = getGenericSignature()) {
576+
auto *genericEnv = getGenericEnvironment();
577+
subMap = genericSig->getSubstitutionMap(
578+
[&](SubstitutableType *t) -> Type {
579+
return genericEnv->mapTypeIntoContext(
580+
t).subst(subs, conformances);
581+
},
582+
[&](CanType origType, Type substType, ProtocolType *protoType)
583+
-> Optional<ProtocolConformanceRef> {
584+
origType = CanType(
585+
genericEnv->mapTypeIntoContext(
586+
origType)->castTo<ArchetypeType>());
587+
return conformances(origType, substType, protoType);
588+
});
589+
}
590+
564591
return substType->getASTContext()
565592
.getSpecializedConformance(substType,
566-
const_cast<ProtocolConformance *>(this),
567-
substType->gatherAllSubstitutions(module, nullptr));
593+
const_cast<ProtocolConformance *>(this),
594+
subMap);
568595
}
569596
assert(substType->isEqual(getType())
570597
&& "substitution changed non-specialized type?!");
@@ -576,8 +603,7 @@ ProtocolConformance *ProtocolConformance::subst(ModuleDecl *module,
576603
= cast<InheritedProtocolConformance>(this)->getInheritedConformance();
577604
ProtocolConformance *newBase;
578605
if (inheritedConformance->getType()->isSpecialized()) {
579-
newBase = inheritedConformance->subst(module, substType,
580-
subs, conformances);
606+
newBase = inheritedConformance->subst(substType, subs, conformances);
581607
} else {
582608
newBase = inheritedConformance;
583609
}
@@ -591,13 +617,11 @@ ProtocolConformance *ProtocolConformance::subst(ModuleDecl *module,
591617
SmallVector<Substitution, 8> newSubs;
592618
newSubs.reserve(spec->getGenericSubstitutions().size());
593619
for (auto &sub : spec->getGenericSubstitutions())
594-
newSubs.push_back(sub.subst(module, subs, conformances));
595-
596-
auto ctxNewSubs = substType->getASTContext().AllocateCopy(newSubs);
620+
newSubs.push_back(sub.subst(subs, conformances));
597621

598622
return substType->getASTContext()
599623
.getSpecializedConformance(substType, spec->getGenericConformance(),
600-
ctxNewSubs);
624+
newSubs);
601625
}
602626
}
603627
llvm_unreachable("bad ProtocolConformanceKind");
@@ -617,15 +641,11 @@ ProtocolConformance::getInheritedConformance(ProtocolDecl *protocol) const {
617641
&& "inherited conformance doesn't match type?!");
618642

619643
auto subs = spec->getGenericSubstitutions();
620-
621644
auto *conformingDC = spec->getDeclContext();
622-
auto *conformingModule = conformingDC->getParentModule();
623-
624645
auto *env = conformingDC->getGenericEnvironmentOfContext();
625-
626646
auto subMap = env->getSubstitutionMap(subs);
627647

628-
auto r = inherited->subst(conformingModule, getType(),
648+
auto r = inherited->subst(getType(),
629649
QuerySubstitutionMap{subMap},
630650
LookUpConformanceInSubstitutionMap(subMap));
631651
assert(getType()->isEqual(r->getType())

lib/AST/Substitution.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,12 @@ Substitution::Substitution(Type Replacement,
4343
&& "cannot substitute with a non-materializable type");
4444
}
4545

46-
Substitution Substitution::subst(ModuleDecl *module,
47-
const SubstitutionMap &subMap) const {
48-
return subst(module, QuerySubstitutionMap{subMap},
46+
Substitution Substitution::subst(const SubstitutionMap &subMap) const {
47+
return subst(QuerySubstitutionMap{subMap},
4948
LookUpConformanceInSubstitutionMap(subMap));
5049
}
5150

52-
Substitution Substitution::subst(ModuleDecl *module,
53-
TypeSubstitutionFn subs,
51+
Substitution Substitution::subst(TypeSubstitutionFn subs,
5452
LookupConformanceFn conformances) const {
5553
// Substitute the replacement.
5654
Type substReplacement = Replacement.subst(subs, conformances,
@@ -73,7 +71,7 @@ Substitution Substitution::subst(ModuleDecl *module,
7371
// If we have a concrete conformance, we need to substitute the
7472
// conformance to apply to the new type.
7573
if (c.isConcrete()) {
76-
auto substC = c.getConcrete()->subst(module, substReplacement,
74+
auto substC = c.getConcrete()->subst(substReplacement,
7775
subs, conformances);
7876
substConformances.push_back(ProtocolConformanceRef(substC));
7977
if (c != substConformances.back())

lib/AST/Type.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2907,8 +2907,7 @@ static Type substType(Type derivedType,
29072907

29082908
SmallVector<Substitution, 4> substArgs;
29092909
for (auto &arg : boxTy->getGenericArgs()) {
2910-
substArgs.push_back(arg.subst(nullptr, substitutions,
2911-
lookupConformances));
2910+
substArgs.push_back(arg.subst(substitutions, lookupConformances));
29122911
}
29132912
for (auto &arg : substArgs) {
29142913
arg = Substitution(arg.getReplacement()->getCanonicalType(),

lib/SILGen/SILGenBridging.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,10 @@ emitBridgeNativeToObjectiveC(SILGenFunction &gen,
7777
// FIXME: Substitute the type substitutions into the witness, because
7878
// SpecializedProtocolConformance::getWitness() doesn't do it for us.
7979
GenericEnvironment *witnessEnv = witness.getSyntheticEnvironment();
80-
8180
SubstitutionMap typeSubMap = witnessEnv
8281
->getSubstitutionMap(typeSubstitutions);
8382
for (auto sub : witnessSubstitutions) {
84-
substitutionsBuf.push_back(sub.subst(gen.SGM.SwiftModule, typeSubMap));
83+
substitutionsBuf.push_back(sub.subst(typeSubMap));
8584
}
8685
substitutions = substitutionsBuf;
8786
}

lib/SILGen/SILGenDecl.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,11 +1885,13 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
18851885
Type concreteTy = conformance->getInterfaceType();
18861886

18871887
// FIXME: conformance substitutions should be in terms of interface types
1888-
auto concreteSubs = concreteTy->gatherAllSubstitutions(M.getSwiftModule(),
1889-
nullptr, nullptr);
18901888
auto specialized = conformance;
18911889
if (conformance->getGenericSignature()) {
18921890
ASTContext &ctx = getASTContext();
1891+
1892+
auto concreteSubs = concreteTy->getContextSubstitutionMap(
1893+
M.getSwiftModule(),
1894+
conformance->getDeclContext());
18931895
specialized = ctx.getSpecializedConformance(concreteTy, conformance,
18941896
concreteSubs);
18951897
}

lib/SILOptimizer/Transforms/PerformanceInliner.cpp

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,7 @@ static bool calleeHasPartialApplyWithOpenedExistentials(FullApplySite AI) {
204204
for (auto PAISub : PAISubs) {
205205
if (!PAISub.getReplacement()->hasArchetype())
206206
continue;
207-
auto NewPAISub =
208-
PAISub.subst(AI.getModule().getSwiftModule(), SubsMap);
207+
auto NewPAISub = PAISub.subst(SubsMap);
209208
if (NewPAISub.getReplacement()->hasOpenedExistential())
210209
return true;
211210
}
@@ -351,6 +350,11 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
351350
int BaseBenefit = RemovedCallBenefit;
352351

353352
SubstitutionMap CalleeSubstMap;
353+
if (IsGeneric) {
354+
CalleeSubstMap = Callee->getGenericEnvironment()
355+
->getSubstitutionMap(AI.getSubstitutions());
356+
}
357+
354358
const SILOptions &Opts = Callee->getModule().getOptions();
355359

356360
// For some reason -Ounchecked can accept a higher base benefit without
@@ -395,28 +399,15 @@ bool SILPerformanceInliner::isProfitableToInline(FullApplySite AI,
395399
!isa<WitnessMethodInst>(def))
396400
continue;
397401

398-
SmallVector<Substitution, 32> NewSubs;
399-
SubstitutionMap SubstMap;
400-
401402
// It is a generic call inside the callee. Check if after inlining
402403
// it will be possible to perform a generic specialization or
403404
// devirtualization of this call.
404405

405406
// Create the list of substitutions as they will be after
406407
// inlining.
408+
SmallVector<Substitution, 4> NewSubs;
407409
for (auto Sub : Subs) {
408-
if (!Sub.getReplacement()->hasArchetype()) {
409-
// This substitution is a concrete type.
410-
NewSubs.push_back(Sub);
411-
continue;
412-
}
413-
// This substitution is not a concrete type.
414-
if (IsGeneric && CalleeSubstMap.empty()) {
415-
CalleeSubstMap =
416-
Callee->getGenericEnvironment()->getSubstitutionMap(
417-
AI.getSubstitutions());
418-
}
419-
auto NewSub = Sub.subst(AI.getModule().getSwiftModule(), CalleeSubstMap);
410+
auto NewSub = Sub.subst(CalleeSubstMap);
420411
NewSubs.push_back(NewSub);
421412
}
422413

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,10 +1043,11 @@ RequirementEnvironment::RequirementEnvironment(
10431043
ProtocolConformance *specialized = conformance;
10441044
if (conformance && conformance->getGenericSignature()) {
10451045
auto concreteSubs =
1046-
concreteType->gatherAllSubstitutions(conformanceDC->getParentModule(),
1047-
&tc, nullptr);
1046+
concreteType->getContextSubstitutionMap(
1047+
conformanceDC->getParentModule(), conformanceDC);
10481048
specialized =
1049-
ctx.getSpecializedConformance(concreteType, conformance, concreteSubs);
1049+
ctx.getSpecializedConformance(concreteType, conformance,
1050+
concreteSubs);
10501051
}
10511052

10521053
if (specialized)

lib/Serialization/Deserialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ ProtocolConformanceRef ModuleFile::readConformance(
590590
auto conformance =
591591
ctx.getSpecializedConformance(conformingType,
592592
genericConformance.getConcrete(),
593-
ctx.AllocateCopy(substitutions));
593+
substitutions);
594594
return ProtocolConformanceRef(conformance);
595595
}
596596

0 commit comments

Comments
 (0)