Skip to content

Commit 44dbebd

Browse files
authored
Merge pull request #76200 from slavapestov/type-subst-invariant
AST: Type substitution can skip subtrees that won't change
2 parents f34bcaa + 593358a commit 44dbebd

14 files changed

+112
-117
lines changed

include/swift/AST/InFlightSubstitution.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class InFlightSubstitution {
3131
SubstOptions Options;
3232
TypeSubstitutionFn BaselineSubstType;
3333
LookupConformanceFn BaselineLookupConformance;
34+
RecursiveTypeProperties Props;
3435

3536
struct ActivePackExpansion {
3637
bool isSubstExpansion = false;
@@ -41,10 +42,7 @@ class InFlightSubstitution {
4142
public:
4243
InFlightSubstitution(TypeSubstitutionFn substType,
4344
LookupConformanceFn lookupConformance,
44-
SubstOptions options)
45-
: Options(options),
46-
BaselineSubstType(substType),
47-
BaselineLookupConformance(lookupConformance) {}
45+
SubstOptions options);
4846

4947
InFlightSubstitution(const InFlightSubstitution &) = delete;
5048
InFlightSubstitution &operator=(const InFlightSubstitution &) = delete;

include/swift/AST/LocalArchetypeRequirementCollector.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ struct MapLocalArchetypesOutOfContext {
5454
Type operator()(SubstitutableType *type) const;
5555
};
5656

57+
Type mapLocalArchetypesOutOfContext(Type type,
58+
GenericSignature baseGenericSig,
59+
ArrayRef<GenericEnvironment *> capturedEnvs);
60+
5761
struct MapIntoLocalArchetypeContext {
5862
GenericEnvironment *baseGenericEnv;
5963
ArrayRef<GenericEnvironment *> capturedEnvs;

include/swift/AST/Types.h

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6577,10 +6577,6 @@ class ArchetypeType : public SubstitutableType,
65776577
/// which the archetype conforms.
65786578
Type getNestedTypeByName(Identifier name);
65796579

6580-
/// Return the archetype that represents the root generic parameter of its
6581-
/// interface type.
6582-
ArchetypeType *getRoot() const;
6583-
65846580
/// Determine whether this is a root archetype within the environment.
65856581
bool isRoot() const;
65866582

@@ -6761,19 +6757,12 @@ class LocalArchetypeType : public ArchetypeType {
67616757
using ArchetypeType::ArchetypeType;
67626758

67636759
public:
6764-
LocalArchetypeType *getRoot() const {
6765-
return cast<LocalArchetypeType>(ArchetypeType::getRoot());
6766-
}
6767-
67686760
static bool classof(const TypeBase *type) {
67696761
return type->getKind() == TypeKind::OpenedArchetype ||
67706762
type->getKind() == TypeKind::ElementArchetype;
67716763
}
67726764
};
67736765
BEGIN_CAN_TYPE_WRAPPER(LocalArchetypeType, ArchetypeType)
6774-
CanLocalArchetypeType getRoot() const {
6775-
return CanLocalArchetypeType(getPointer()->getRoot());
6776-
}
67776766
END_CAN_TYPE_WRAPPER(LocalArchetypeType, ArchetypeType)
67786767

67796768
/// An archetype that represents the dynamic type of an opened existential.
@@ -6828,12 +6817,6 @@ class OpenedArchetypeType final : public LocalArchetypeType,
68286817
/// Retrieve the ID number of this opened existential.
68296818
UUID getOpenedExistentialID() const;
68306819

6831-
/// Return the archetype that represents the root generic parameter of its
6832-
/// interface type.
6833-
OpenedArchetypeType *getRoot() const {
6834-
return cast<OpenedArchetypeType>(ArchetypeType::getRoot());
6835-
}
6836-
68376820
static bool classof(const TypeBase *T) {
68386821
return T->getKind() == TypeKind::OpenedArchetype;
68396822
}
@@ -6846,9 +6829,6 @@ class OpenedArchetypeType final : public LocalArchetypeType,
68466829
RecursiveTypeProperties properties);
68476830
};
68486831
BEGIN_CAN_TYPE_WRAPPER(OpenedArchetypeType, LocalArchetypeType)
6849-
CanOpenedArchetypeType getRoot() const {
6850-
return CanOpenedArchetypeType(getPointer()->getRoot());
6851-
}
68526832
END_CAN_TYPE_WRAPPER(OpenedArchetypeType, LocalArchetypeType)
68536833

68546834
/// A wrapper around a shape type to use in ArchetypeTrailingObjects
@@ -6916,12 +6896,6 @@ class ElementArchetypeType final : public LocalArchetypeType,
69166896
/// Retrieve the ID number of this opened element.
69176897
UUID getOpenedElementID() const;
69186898

6919-
/// Return the archetype that represents the root generic parameter of its
6920-
/// interface type.
6921-
ElementArchetypeType *getRoot() const {
6922-
return cast<ElementArchetypeType>(ArchetypeType::getRoot());
6923-
}
6924-
69256899
static bool classof(const TypeBase *T) {
69266900
return T->getKind() == TypeKind::ElementArchetype;
69276901
}
@@ -6933,9 +6907,6 @@ class ElementArchetypeType final : public LocalArchetypeType,
69336907
LayoutConstraint layout);
69346908
};
69356909
BEGIN_CAN_TYPE_WRAPPER(ElementArchetypeType, LocalArchetypeType)
6936-
CanElementArchetypeType getRoot() const {
6937-
return CanElementArchetypeType(getPointer()->getRoot());
6938-
}
69396910
END_CAN_TYPE_WRAPPER(ElementArchetypeType, LocalArchetypeType)
69406911

69416912
template<typename Type>

include/swift/SIL/SILCloner.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,8 @@ struct SubstitutionMapWithLocalArchetypes {
6060

6161
// Map the local archetype to an interface type in the new generic
6262
// signature.
63-
MapLocalArchetypesOutOfContext mapOutOfContext(BaseGenericSig,
64-
CapturedEnvs);
65-
auto interfaceTy = mapOutOfContext(local);
63+
auto interfaceTy = mapLocalArchetypesOutOfContext(
64+
local, BaseGenericSig, CapturedEnvs);
6665

6766
// Map this interface type into the new generic environment to get
6867
// a primary archetype.

include/swift/SIL/SILModule.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,18 @@ class SILModule {
460460
SILValue getLocalGenericEnvironmentDef(GenericEnvironment *genericEnv,
461461
SILFunction *inFunction);
462462

463+
/// Returns the instruction which defines the given local generic environment,
464+
/// e.g. an open_existential_addr.
465+
///
466+
/// In contrast to getLocalGenericEnvironmentDef, it is required that all local
467+
/// generic environments are resolved.
468+
SingleValueInstruction *
469+
getLocalGenericEnvironmentDefInst(GenericEnvironment *genericEnv,
470+
SILFunction *inFunction) {
471+
return dyn_cast<SingleValueInstruction>(
472+
getLocalGenericEnvironmentDef(genericEnv, inFunction));
473+
}
474+
463475
/// Returns the instruction which defines the given root local archetype,
464476
/// e.g. an open_existential_addr.
465477
///

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3796,12 +3796,8 @@ void ASTMangler::appendClosureComponents(CanType Ty, unsigned discriminator,
37963796
appendContext(parentContext, base, StringRef());
37973797

37983798
auto Sig = parentContext->getGenericSignatureOfContext();
3799-
3800-
Ty = Ty.subst(MapLocalArchetypesOutOfContext(Sig, capturedEnvs),
3801-
MakeAbstractConformanceForGenericType(),
3802-
SubstFlags::PreservePackExpansionLevel |
3803-
SubstFlags::SubstitutePrimaryArchetypes |
3804-
SubstFlags::SubstituteLocalArchetypes)->getCanonicalType();
3799+
Ty = mapLocalArchetypesOutOfContext(Ty, Sig, capturedEnvs)
3800+
->getCanonicalType();
38053801

38063802
appendType(Ty, Sig);
38073803
appendOperator(isImplicit ? "fu" : "fU", Index(discriminator));

lib/AST/LocalArchetypeRequirementCollector.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,17 @@ Type MapLocalArchetypesOutOfContext::operator()(SubstitutableType *type) const {
203203
return getInterfaceType(archetypeTy->getInterfaceType(), genericEnv);
204204
}
205205

206+
Type swift::mapLocalArchetypesOutOfContext(
207+
Type type,
208+
GenericSignature baseGenericSig,
209+
ArrayRef<GenericEnvironment *> capturedEnvs) {
210+
return type.subst(MapLocalArchetypesOutOfContext(baseGenericSig, capturedEnvs),
211+
MakeAbstractConformanceForGenericType(),
212+
SubstFlags::PreservePackExpansionLevel |
213+
SubstFlags::SubstitutePrimaryArchetypes |
214+
SubstFlags::SubstituteLocalArchetypes);
215+
}
216+
206217
static Type mapIntoLocalContext(GenericTypeParamType *param, unsigned baseDepth,
207218
ArrayRef<GenericEnvironment *> capturedEnvs) {
208219
assert(!param->isParameterPack());

lib/AST/ParameterPack.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/Decl.h"
20+
#include "swift/AST/GenericEnvironment.h"
2021
#include "swift/AST/GenericParamList.h"
2122
#include "swift/AST/ParameterList.h"
2223
#include "swift/AST/Type.h"
@@ -161,7 +162,14 @@ void TypeBase::getTypeParameterPacks(
161162
if (paramTy->isParameterPack())
162163
rootParameterPacks.push_back(paramTy);
163164
} else if (auto *archetypeTy = t->getAs<PackArchetypeType>()) {
164-
rootParameterPacks.push_back(archetypeTy->getRoot());
165+
if (archetypeTy->isRoot()) {
166+
rootParameterPacks.push_back(archetypeTy);
167+
} else {
168+
auto *genericEnv = archetypeTy->getGenericEnvironment();
169+
auto paramTy = archetypeTy->getInterfaceType()->getRootGenericParam();
170+
rootParameterPacks.push_back(
171+
genericEnv->mapTypeIntoContext(paramTy));
172+
}
165173
}
166174

167175
return false;

lib/AST/Type.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3378,17 +3378,6 @@ ArchetypeType::ArchetypeType(TypeKind Kind,
33783378
getSubclassTrailingObjects<ProtocolDecl *>());
33793379
}
33803380

3381-
ArchetypeType *ArchetypeType::getRoot() const {
3382-
if (isRoot()) {
3383-
return const_cast<ArchetypeType *>(this);
3384-
}
3385-
3386-
auto gp = InterfaceType->getRootGenericParam();
3387-
assert(gp && "Missing root generic parameter?");
3388-
return getGenericEnvironment()->mapTypeIntoContext(
3389-
Type(gp))->castTo<ArchetypeType>();
3390-
}
3391-
33923381
bool ArchetypeType::isRoot() const {
33933382
return getInterfaceType()->is<GenericTypeParamType>();
33943383
}

lib/AST/TypeSubstitution.cpp

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,40 @@ static Type substGenericFunctionType(GenericFunctionType *genericFnType,
359359
fnType->getResult(), fnType->getExtInfo());
360360
}
361361

362+
InFlightSubstitution::InFlightSubstitution(TypeSubstitutionFn substType,
363+
LookupConformanceFn lookupConformance,
364+
SubstOptions options)
365+
: Options(options),
366+
BaselineSubstType(substType),
367+
BaselineLookupConformance(lookupConformance) {
368+
// FIXME: Don't substitute type parameters if one of the special flags is set.
369+
Props |= RecursiveTypeProperties::HasTypeParameter;
370+
371+
// If none of the special flags are set, we substitute type parameters and
372+
// primary archetypes only.
373+
if (!Options.contains(SubstFlags::SubstitutePrimaryArchetypes) &&
374+
!Options.contains(SubstFlags::SubstituteLocalArchetypes) &&
375+
!Options.contains(SubstFlags::SubstituteOpaqueArchetypes)) {
376+
Props |= RecursiveTypeProperties::HasPrimaryArchetype;
377+
}
378+
379+
if (Options.contains(SubstFlags::SubstitutePrimaryArchetypes))
380+
Props |= RecursiveTypeProperties::HasPrimaryArchetype;
381+
382+
if (Options.contains(SubstFlags::SubstituteLocalArchetypes)) {
383+
Props |= RecursiveTypeProperties::HasOpenedExistential;
384+
Props |= RecursiveTypeProperties::HasElementArchetype;
385+
}
386+
387+
if (Options.contains(SubstFlags::SubstituteOpaqueArchetypes))
388+
Props |= RecursiveTypeProperties::HasOpaqueArchetype;
389+
}
390+
391+
bool InFlightSubstitution::isInvariant(Type derivedType) const {
392+
// If none of the bits are set, the type won't be changed by substitution.
393+
return !(derivedType->getRecursiveProperties().getBits() & Props.getBits());
394+
}
395+
362396
void InFlightSubstitution::expandPackExpansionShape(Type origShape,
363397
llvm::function_ref<void(Type substComponentShape)> handleComponent) {
364398

@@ -470,16 +504,6 @@ InFlightSubstitution::lookupConformance(CanType dependentType,
470504
return substPackPatterns[index];
471505
}
472506

473-
bool InFlightSubstitution::isInvariant(Type derivedType) const {
474-
if (derivedType->hasPrimaryArchetype() || derivedType->hasTypeParameter())
475-
return false;
476-
if (shouldSubstituteLocalArchetypes() && derivedType->hasLocalArchetype())
477-
return false;
478-
if (shouldSubstituteOpaqueArchetypes() && derivedType->hasOpaqueArchetype())
479-
return false;
480-
return true;
481-
}
482-
483507
namespace {
484508

485509
class TypeSubstituter : public TypeTransform<TypeSubstituter> {
@@ -522,6 +546,9 @@ class TypeSubstituter : public TypeTransform<TypeSubstituter> {
522546

523547
std::optional<Type>
524548
TypeSubstituter::transform(TypeBase *type, TypePosition position) {
549+
if (IFS.isInvariant(type))
550+
return Type(type);
551+
525552
return std::nullopt;
526553
}
527554

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,14 +1967,11 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
19671967
auto mapTypeOutOfContext = [&](Type t) -> CanType {
19681968
LLVM_DEBUG(llvm::dbgs() << "-- capture with contextual type " << t << "\n");
19691969

1970-
t = t.subst(MapLocalArchetypesOutOfContext(origGenericSig, capturedEnvs),
1971-
MakeAbstractConformanceForGenericType(),
1972-
SubstFlags::PreservePackExpansionLevel |
1973-
SubstFlags::SubstitutePrimaryArchetypes |
1974-
SubstFlags::SubstituteLocalArchetypes);
1975-
1976-
LLVM_DEBUG(llvm::dbgs() << "-- maps to " << t->getCanonicalType() << "\n");
1977-
return t->getCanonicalType();
1970+
auto result = mapLocalArchetypesOutOfContext(t, origGenericSig, capturedEnvs)
1971+
->getCanonicalType();
1972+
1973+
LLVM_DEBUG(llvm::dbgs() << "-- maps to " << result << "\n");
1974+
return result;
19781975
};
19791976

19801977
for (auto capture : loweredCaptures.getCaptures()) {
@@ -3004,26 +3001,17 @@ CanSILFunctionType swift::buildSILFunctionThunkType(
30043001
interfaceSubs);
30053002
}
30063003

3007-
MapLocalArchetypesOutOfContext mapOutOfContext(baseGenericSig, capturedEnvs);
30083004
auto substFormalTypeIntoThunkContext =
30093005
[&](CanType t) -> CanType {
30103006
return genericEnv->mapTypeIntoContext(
3011-
t.subst(mapOutOfContext,
3012-
MakeAbstractConformanceForGenericType(),
3013-
SubstFlags::PreservePackExpansionLevel |
3014-
SubstFlags::SubstitutePrimaryArchetypes |
3015-
SubstFlags::SubstituteLocalArchetypes))
3007+
mapLocalArchetypesOutOfContext(t, baseGenericSig, capturedEnvs))
30163008
->getCanonicalType();
30173009
};
30183010
auto substLoweredTypeIntoThunkContext =
30193011
[&](CanSILFunctionType t) -> CanSILFunctionType {
30203012
return cast<SILFunctionType>(
30213013
genericEnv->mapTypeIntoContext(
3022-
Type(t).subst(mapOutOfContext,
3023-
MakeAbstractConformanceForGenericType(),
3024-
SubstFlags::PreservePackExpansionLevel |
3025-
SubstFlags::SubstitutePrimaryArchetypes |
3026-
SubstFlags::SubstituteLocalArchetypes))
3014+
mapLocalArchetypesOutOfContext(t, baseGenericSig, capturedEnvs))
30273015
->getCanonicalType());
30283016
};
30293017

lib/SIL/IR/TypeLowering.cpp

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3905,12 +3905,8 @@ getAnyFunctionRefInterfaceType(TypeConverter &TC,
39053905

39063906
if (funcType->hasArchetype()) {
39073907
assert(isa<FunctionType>(funcType));
3908-
auto substType = Type(funcType).subst(
3909-
MapLocalArchetypesOutOfContext(sig.baseGenericSig, sig.capturedEnvs),
3910-
MakeAbstractConformanceForGenericType(),
3911-
SubstFlags::PreservePackExpansionLevel |
3912-
SubstFlags::SubstitutePrimaryArchetypes |
3913-
SubstFlags::SubstituteLocalArchetypes);
3908+
auto substType = mapLocalArchetypesOutOfContext(
3909+
funcType, sig.baseGenericSig, sig.capturedEnvs);
39143910
funcType = cast<FunctionType>(substType->getCanonicalType());
39153911
}
39163912

@@ -4964,15 +4960,10 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
49644960
SmallSetVector<GenericEnvironment *, 2> boxCapturedEnvs;
49654961
findCapturedEnvironments(loweredContextType, boxCapturedEnvs);
49664962

4967-
MapLocalArchetypesOutOfContext mapOutOfContext(baseGenericSig,
4968-
boxCapturedEnvs.getArrayRef());
4969-
4970-
auto loweredInterfaceType = loweredContextType.subst(
4971-
mapOutOfContext,
4972-
MakeAbstractConformanceForGenericType(),
4973-
SubstFlags::PreservePackExpansionLevel |
4974-
SubstFlags::SubstitutePrimaryArchetypes |
4975-
SubstFlags::SubstituteLocalArchetypes)->getCanonicalType();
4963+
auto loweredInterfaceType =
4964+
mapLocalArchetypesOutOfContext(loweredContextType, baseGenericSig,
4965+
boxCapturedEnvs.getArrayRef())
4966+
->getCanonicalType();
49764967

49774968
// If the type is not dependent at all, we can form a concrete box layout.
49784969
// We don't need to capture the generic environment.

0 commit comments

Comments
 (0)