Skip to content

Commit fc7068e

Browse files
authored
Merge pull request #76910 from slavapestov/open-type-perf-fix
Fix performance regression in ConstraintSystem::openType()
2 parents 5fa12d3 + b0303bb commit fc7068e

File tree

8 files changed

+109
-61
lines changed

8 files changed

+109
-61
lines changed

include/swift/AST/TypeTransform.h

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ namespace swift {
2525

2626
template<typename Derived>
2727
class TypeTransform {
28+
public:
29+
ASTContext &ctx;
30+
31+
TypeTransform(ASTContext &ctx) : ctx(ctx) {}
32+
33+
private:
2834
Derived &asDerived() { return *static_cast<Derived *>(this); }
2935

3036
/// \param pos The variance position of the result type.
@@ -98,7 +104,6 @@ class TypeTransform {
98104

99105
// Recur into children of this type.
100106
TypeBase *base = t.getPointer();
101-
auto &ctx = base->getASTContext();
102107

103108
switch (base->getKind()) {
104109
#define BUILTIN_TYPE(Id, Parent) \
@@ -467,9 +472,27 @@ case TypeKind::Id:
467472
return newUnderlyingTy;
468473

469474
auto oldSubMap = alias->getSubstitutionMap();
470-
auto newSubMap = asDerived().transformSubMap(oldSubMap);
471-
if (oldSubMap && !newSubMap)
472-
return Type();
475+
SubstitutionMap newSubMap;
476+
477+
// We leave the old behavior behind for ConstraintSystem::openType(), where
478+
// preserving sugar introduces a performance penalty.
479+
if (asDerived().shouldDesugarTypeAliases()) {
480+
for (auto oldReplacementType : oldSubMap.getReplacementTypes()) {
481+
Type newReplacementType = doIt(oldReplacementType, TypePosition::Invariant);
482+
if (!newReplacementType)
483+
return Type();
484+
485+
// If anything changed with the replacement type, we lose the sugar.
486+
if (newReplacementType.getPointer() != oldReplacementType.getPointer())
487+
return newUnderlyingTy;
488+
}
489+
490+
newSubMap = oldSubMap;
491+
} else {
492+
newSubMap = asDerived().transformSubMap(oldSubMap);
493+
if (oldSubMap && !newSubMap)
494+
return Type();
495+
}
473496

474497
if (oldParentType.getPointer() == newParentType.getPointer() &&
475498
oldUnderlyingTy.getPointer() == newUnderlyingTy.getPointer() &&
@@ -684,14 +707,16 @@ case TypeKind::Id:
684707
if (!anyChanged)
685708
return t;
686709

687-
// Handle vanishing tuples -- If the transform would yield a singleton
688-
// tuple, and we didn't start with one, flatten to produce the
689-
// element type.
690-
if (elements.size() == 1 &&
691-
!elements[0].getType()->is<PackExpansionType>() &&
692-
!(tuple->getNumElements() == 1 &&
693-
!tuple->getElementType(0)->is<PackExpansionType>())) {
694-
return elements[0].getType();
710+
if (asDerived().shouldUnwrapVanishingTuples()) {
711+
// Handle vanishing tuples -- If the transform would yield a singleton
712+
// tuple, and we didn't start with one, flatten to produce the
713+
// element type.
714+
if (elements.size() == 1 &&
715+
!elements[0].getType()->is<PackExpansionType>() &&
716+
!(tuple->getNumElements() == 1 &&
717+
!tuple->getElementType(0)->is<PackExpansionType>())) {
718+
return elements[0].getType();
719+
}
695720
}
696721

697722
return TupleType::get(elements, ctx);
@@ -1002,6 +1027,10 @@ case TypeKind::Id:
10021027
return SubstitutionMap::get(sig, newSubs, LookUpConformanceInModule());
10031028
}
10041029

1030+
bool shouldUnwrapVanishingTuples() const { return true; }
1031+
1032+
bool shouldDesugarTypeAliases() const { return false; }
1033+
10051034
CanType transformSILField(CanType fieldTy, TypePosition pos) {
10061035
return doIt(fieldTy, pos)->getCanonicalType();
10071036
}

include/swift/Sema/ConstraintSystem.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4318,7 +4318,6 @@ class ConstraintSystem {
43184318
Type openType(Type type, OpenedTypeMap &replacements,
43194319
ConstraintLocatorBuilder locator);
43204320

4321-
private:
43224321
/// "Open" an opaque archetype type, similar to \c openType.
43234322
Type openOpaqueType(OpaqueTypeArchetypeType *type,
43244323
ConstraintLocatorBuilder locator);
@@ -4340,7 +4339,6 @@ class ConstraintSystem {
43404339
ASSERT(erased);
43414340
}
43424341

4343-
public:
43444342
/// Recurse over the given type and open any opaque archetype types.
43454343
Type openOpaqueType(Type type, ContextualTypePurpose context,
43464344
ConstraintLocatorBuilder locator);

lib/AST/GenericEnvironment.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,8 @@ namespace {
524524
struct MapTypeIntoContext: TypeTransform<MapTypeIntoContext> {
525525
GenericEnvironment *env;
526526

527-
explicit MapTypeIntoContext(GenericEnvironment *env) : env(env) {}
527+
explicit MapTypeIntoContext(GenericEnvironment *env, ASTContext &ctx)
528+
: TypeTransform(ctx), env(env) {}
528529

529530
std::optional<Type> transform(TypeBase *type, TypePosition pos) {
530531
if (!type->hasTypeParameter())
@@ -552,7 +553,10 @@ struct MapTypeIntoContext: TypeTransform<MapTypeIntoContext> {
552553

553554
Type GenericEnvironment::mapTypeIntoContext(Type type) const {
554555
assert(!type->hasPrimaryArchetype() && "already have a contextual type");
555-
return MapTypeIntoContext(const_cast<GenericEnvironment *>(this))
556+
if (!type->hasTypeParameter())
557+
return type;
558+
return MapTypeIntoContext(const_cast<GenericEnvironment *>(this),
559+
type->getASTContext())
556560
.doIt(type, TypePosition::Invariant);
557561
}
558562

lib/AST/Type.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4092,14 +4092,15 @@ Type Type::transformRec(
40924092
class Transform : public TypeTransform<Transform> {
40934093
llvm::function_ref<std::optional<Type>(TypeBase *)> fn;
40944094
public:
4095-
explicit Transform(llvm::function_ref<std::optional<Type>(TypeBase *)> fn) : fn(fn) {}
4095+
explicit Transform(llvm::function_ref<std::optional<Type>(TypeBase *)> fn,
4096+
ASTContext &ctx) : TypeTransform(ctx), fn(fn) {}
40964097

40974098
std::optional<Type> transform(TypeBase *type, TypePosition position) {
40984099
return fn(type);
40994100
}
41004101
};
41014102

4102-
return Transform(fn).doIt(*this, TypePosition::Invariant);
4103+
return Transform(fn, (*this)->getASTContext()).doIt(*this, TypePosition::Invariant);
41034104
}
41044105

41054106
Type Type::transformWithPosition(
@@ -4109,14 +4110,15 @@ Type Type::transformWithPosition(
41094110
class Transform : public TypeTransform<Transform> {
41104111
llvm::function_ref<std::optional<Type>(TypeBase *, TypePosition)> fn;
41114112
public:
4112-
explicit Transform(llvm::function_ref<std::optional<Type>(TypeBase *, TypePosition)> fn) : fn(fn) {}
4113+
explicit Transform(llvm::function_ref<std::optional<Type>(TypeBase *, TypePosition)> fn,
4114+
ASTContext &ctx) : TypeTransform(ctx), fn(fn) {}
41134115

41144116
std::optional<Type> transform(TypeBase *type, TypePosition position) {
41154117
return fn(type, position);
41164118
}
41174119
};
41184120

4119-
return Transform(fn).doIt(*this, pos);
4121+
return Transform(fn, (*this)->getASTContext()).doIt(*this, pos);
41204122
}
41214123

41224124
bool Type::findIf(llvm::function_ref<bool(Type)> pred) const {

lib/AST/TypeSubstitution.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,8 @@ class TypeSubstituter : public TypeTransform<TypeSubstituter> {
388388
InFlightSubstitution &IFS;
389389

390390
public:
391-
TypeSubstituter(unsigned level, InFlightSubstitution &IFS)
392-
: level(level), IFS(IFS) {}
391+
TypeSubstituter(ASTContext &ctx, unsigned level, InFlightSubstitution &IFS)
392+
: TypeTransform(ctx), level(level), IFS(IFS) {}
393393

394394
std::optional<Type> transform(TypeBase *type, TypePosition pos);
395395

@@ -566,7 +566,7 @@ Type Type::subst(InFlightSubstitution &IFS) const {
566566
if (IFS.isInvariant(*this))
567567
return *this;
568568

569-
TypeSubstituter transform(/*level=*/0, IFS);
569+
TypeSubstituter transform((*this)->getASTContext(), /*level=*/0, IFS);
570570
return transform.doIt(*this, TypePosition::Invariant);
571571
}
572572

lib/Sema/ConstraintSystem.cpp

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/AST/ParameterList.h"
3232
#include "swift/AST/ProtocolConformance.h"
3333
#include "swift/AST/TypeCheckRequests.h"
34+
#include "swift/AST/TypeTransform.h"
3435
#include "swift/Basic/Assertions.h"
3536
#include "swift/Basic/Defer.h"
3637
#include "swift/Basic/Statistic.h"
@@ -1199,49 +1200,63 @@ Type ConstraintSystem::replaceInferableTypesWithTypeVars(
11991200
return type;
12001201
}
12011202

1203+
namespace {
1204+
1205+
struct TypeOpener : public TypeTransform<TypeOpener> {
1206+
OpenedTypeMap &replacements;
1207+
ConstraintLocatorBuilder locator;
1208+
ConstraintSystem &cs;
1209+
1210+
TypeOpener(OpenedTypeMap &replacements,
1211+
ConstraintLocatorBuilder locator,
1212+
ConstraintSystem &cs)
1213+
: TypeTransform<TypeOpener>(cs.getASTContext()),
1214+
replacements(replacements), locator(locator), cs(cs) {}
1215+
1216+
std::optional<Type> transform(TypeBase *type, TypePosition pos) {
1217+
if (!type->hasTypeParameter())
1218+
return Type(type);
1219+
1220+
return std::nullopt;
1221+
}
1222+
1223+
Type transformGenericTypeParamType(GenericTypeParamType *genericParam,
1224+
TypePosition pos) {
1225+
auto known = replacements.find(
1226+
cast<GenericTypeParamType>(genericParam->getCanonicalType()));
1227+
// FIXME: This should be an assert, however protocol generic signatures
1228+
// drop outer generic parameters.
1229+
// assert(known != replacements.end());
1230+
if (known == replacements.end())
1231+
return ErrorType::get(ctx);
1232+
return known->second;
1233+
}
1234+
1235+
Type transformPackExpansionType(PackExpansionType *expansion,
1236+
TypePosition pos) {
1237+
return cs.openPackExpansionType(expansion, replacements, locator);
1238+
}
1239+
1240+
bool shouldUnwrapVanishingTuples() const {
1241+
return false;
1242+
}
1243+
1244+
bool shouldDesugarTypeAliases() const {
1245+
return true;
1246+
}
1247+
};
1248+
1249+
}
1250+
12021251
Type ConstraintSystem::openType(Type type, OpenedTypeMap &replacements,
12031252
ConstraintLocatorBuilder locator) {
12041253
assert(!type->hasUnboundGenericType());
12051254

12061255
if (!type->hasTypeParameter())
12071256
return type;
12081257

1209-
return type.transformRec([&](Type type) -> std::optional<Type> {
1210-
assert(!type->is<GenericFunctionType>());
1211-
1212-
// Preserve single element tuples if their element is
1213-
// pack expansion, otherwise it wouldn't be expanded.
1214-
if (auto *tuple = type->getAs<TupleType>()) {
1215-
if (tuple->getNumElements() == 1) {
1216-
const auto &elt = tuple->getElement(0);
1217-
if (!elt.hasName() && elt.getType()->is<PackExpansionType>()) {
1218-
return TupleType::get(
1219-
{openPackExpansionType(
1220-
elt.getType()->castTo<PackExpansionType>(), replacements,
1221-
locator)},
1222-
tuple->getASTContext());
1223-
}
1224-
}
1225-
}
1226-
1227-
if (auto *expansion = type->getAs<PackExpansionType>()) {
1228-
return openPackExpansionType(expansion, replacements, locator);
1229-
}
1230-
1231-
// Replace a generic type parameter with its corresponding type variable.
1232-
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
1233-
auto known = replacements.find(
1234-
cast<GenericTypeParamType>(genericParam->getCanonicalType()));
1235-
// FIXME: This should be an assert, however protocol generic signatures
1236-
// drop outer generic parameters.
1237-
// assert(known != replacements.end());
1238-
if (known == replacements.end())
1239-
return ErrorType::get(getASTContext());
1240-
return known->second;
1241-
}
1242-
1243-
return std::nullopt;
1244-
});
1258+
return TypeOpener(replacements, locator, *this)
1259+
.doIt(type, TypePosition::Invariant);
12451260
}
12461261

12471262
Type ConstraintSystem::openPackExpansionType(PackExpansionType *expansion,

test/IDE/complete_call_arg.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1119,7 +1119,7 @@ func testLValueBaseTyOfSubscript() {
11191119
var cache: [String: Codable] = [:]
11201120
if let cached = cache[#^LVALUEBASETY^#
11211121

1122-
// LVALUEBASETY-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(position): Dictionary<String, any Codable>.Index#}[']'][#Dictionary<String, any Codable>.Element#];
1122+
// LVALUEBASETY-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(position): Dictionary<String, any Codable>.Index#}[']'][#(key: String, value: any Codable)#];
11231123
// LVALUEBASETY-DAG: Decl[Subscript]/CurrNominal/Flair[ArgLabels]/IsSystem: ['[']{#(key): String#}[']'][#@lvalue (any Codable)?#];
11241124
}
11251125

test/Macros/macro_default_argument_diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,5 @@ func testIdentifier(notOkay: Stringified<String> = #stringify(myString)) {}
5555
// expected-error@+1{{only literals are permitted}}
5656
func testString(interpolated: Stringified<String> = #stringify("Hello \(0b10001)")) {}
5757

58-
// expected-error@+1{{default argument value of type 'Stringified<Int>' (aka '(Int, String)') cannot be converted to type 'Int'}}
58+
// expected-error@+1{{default argument value of type '(Int, String)' cannot be converted to type 'Int'}}
5959
func testReturn(wrongType: Int = #stringify(0)) {}

0 commit comments

Comments
 (0)