Merge pull request #79882 from slavapestov/sizeof-constraint

Sema: Optimize Constraint layout to save 24 bytes
This commit is contained in:
Slava Pestov
2025-03-11 14:30:44 -04:00
committed by GitHub
7 changed files with 176 additions and 152 deletions

View File

@@ -336,6 +336,8 @@ class Constraint final : public llvm::ilist_node<Constraint>,
private llvm::TrailingObjects<Constraint, private llvm::TrailingObjects<Constraint,
TypeVariableType *, TypeVariableType *,
ConstraintFix *, ConstraintFix *,
DeclContext *,
ContextualTypeInfo,
OverloadChoice> { OverloadChoice> {
friend TrailingObjects; friend TrailingObjects;
@@ -345,9 +347,17 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// The kind of restriction placed on this constraint. /// The kind of restriction placed on this constraint.
ConversionRestrictionKind Restriction : 8; ConversionRestrictionKind Restriction : 8;
/// Whether we have a fix. /// The number of type variables referenced by this constraint.
///
/// The type variables themselves are tail-allocated.
unsigned NumTypeVariables : 11;
/// Whether we have a tail-allocated fix.
unsigned HasFix : 1; unsigned HasFix : 1;
/// Whether we have a tail-allocated DeclContext.
unsigned HasDeclContext : 1;
/// Whether the \c Restriction field is valid. /// Whether the \c Restriction field is valid.
unsigned HasRestriction : 1; unsigned HasRestriction : 1;
@@ -375,14 +385,19 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// the rest of the constraint system. Currently only applies to conjunctions. /// the rest of the constraint system. Currently only applies to conjunctions.
unsigned IsIsolated : 1; unsigned IsIsolated : 1;
/// The number of type variables referenced by this constraint.
///
/// The type variables themselves are tail-allocated.
unsigned NumTypeVariables : 11;
/// The kind of function reference, for member references. /// The kind of function reference, for member references.
unsigned TheFunctionRefInfo : 3; unsigned TheFunctionRefInfo : 3;
/// The trailing closure matching for an applicable function constraint,
/// if any. 0 = None, 1 = Forward, 2 = Backward.
unsigned trailingClosureMatching : 2;
/// For a SyntacticElement constraint, identify whether the result of this
/// node is unused.
unsigned isDiscarded : 1;
// 22 bits remaining
union { union {
struct { struct {
/// The first type. /// The first type.
@@ -414,29 +429,19 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// Used for ValueWitness constraints. /// Used for ValueWitness constraints.
ValueDecl *Ref; ValueDecl *Ref;
} Member; } Member;
/// The DC in which the use appears.
DeclContext *UseDC;
} Member; } Member;
/// The set of constraints for a disjunction. /// The set of constraints for a disjunction.
ArrayRef<Constraint *> Nested; ArrayRef<Constraint *> Nested;
struct { struct {
/// The first type /// The first type.
Type First; Type First;
/// The DC in which the use appears.
DeclContext *UseDC;
} Overload; } Overload;
struct { struct {
/// The node itself. /// The node itself.
ASTNode Element; ASTNode Element;
/// Contextual information associated with the element (if any).
ContextualTypeInfo Context;
/// Identifies whether result of this node is unused.
bool IsDiscarded;
} SyntacticElement; } SyntacticElement;
struct { struct {
@@ -447,11 +452,6 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// The type being called, primarily a function type, but could /// The type being called, primarily a function type, but could
/// be a metatype, a tuple or a nominal type. /// be a metatype, a tuple or a nominal type.
Type Callee; Type Callee;
/// The trailing closure matching for an applicable function constraint,
/// if any. 0 = None, 1 = Forward, 2 = Backward.
unsigned TrailingClosureMatching : 2;
/// The declaration context in which the application appears.
DeclContext *UseDC;
} Apply; } Apply;
}; };
@@ -527,6 +527,14 @@ class Constraint final : public llvm::ilist_node<Constraint>,
return HasFix ? 1 : 0; return HasFix ? 1 : 0;
} }
size_t numTrailingObjects(OverloadToken<DeclContext *>) const {
return HasDeclContext ? 1 : 0;
}
size_t numTrailingObjects(OverloadToken<ContextualTypeInfo>) const {
return Kind == ConstraintKind::SyntacticElement ? 1 : 0;
}
size_t numTrailingObjects(OverloadToken<OverloadChoice>) const { size_t numTrailingObjects(OverloadToken<OverloadChoice>) const {
return Kind == ConstraintKind::BindOverload ? 1 : 0; return Kind == ConstraintKind::BindOverload ? 1 : 0;
} }
@@ -604,15 +612,15 @@ public:
DeclContext *useDC, ConstraintLocator *locator); DeclContext *useDC, ConstraintLocator *locator);
static Constraint *createSyntacticElement(ConstraintSystem &cs, static Constraint *createSyntacticElement(ConstraintSystem &cs,
ASTNode node, ASTNode node,
ConstraintLocator *locator, ConstraintLocator *locator,
bool isDiscarded = false); bool isDiscarded = false);
static Constraint *createSyntacticElement(ConstraintSystem &cs, static Constraint *createSyntacticElement(ConstraintSystem &cs,
ASTNode node, ASTNode node,
ContextualTypeInfo context, ContextualTypeInfo context,
ConstraintLocator *locator, ConstraintLocator *locator,
bool isDiscarded = false); bool isDiscarded = false);
/// Determine the kind of constraint. /// Determine the kind of constraint.
ConstraintKind getKind() const { return Kind; } ConstraintKind getKind() const { return Kind; }
@@ -864,24 +872,10 @@ public:
/// Retrieve the overload choice for an overload-binding constraint. /// Retrieve the overload choice for an overload-binding constraint.
OverloadChoice getOverloadChoice() const { OverloadChoice getOverloadChoice() const {
assert(Kind == ConstraintKind::BindOverload); ASSERT(Kind == ConstraintKind::BindOverload);
return *getTrailingObjects<OverloadChoice>(); return *getTrailingObjects<OverloadChoice>();
} }
/// Retrieve the DC in which the overload was used.
DeclContext *getOverloadUseDC() const {
assert(Kind == ConstraintKind::BindOverload);
return Overload.UseDC;
}
/// Retrieve the DC in which the member was used.
DeclContext *getMemberUseDC() const {
assert(Kind == ConstraintKind::ValueMember ||
Kind == ConstraintKind::UnresolvedValueMember ||
Kind == ConstraintKind::ValueWitness);
return Member.UseDC;
}
FunctionType *getAppliedFunctionType() const { FunctionType *getAppliedFunctionType() const {
assert(Kind == ConstraintKind::ApplicableFunction); assert(Kind == ConstraintKind::ApplicableFunction);
return Apply.AppliedFn; return Apply.AppliedFn;
@@ -892,24 +886,25 @@ public:
return Apply.Callee; return Apply.Callee;
} }
DeclContext *getApplicationDC() const {
assert(Kind == ConstraintKind::ApplicableFunction);
return Apply.UseDC;
}
ASTNode getSyntacticElement() const { ASTNode getSyntacticElement() const {
assert(Kind == ConstraintKind::SyntacticElement); assert(Kind == ConstraintKind::SyntacticElement);
return SyntacticElement.Element; return SyntacticElement.Element;
} }
ContextualTypeInfo getElementContext() const { ContextualTypeInfo getElementContext() const {
assert(Kind == ConstraintKind::SyntacticElement); ASSERT(Kind == ConstraintKind::SyntacticElement);
return SyntacticElement.Context; return *getTrailingObjects<ContextualTypeInfo>();
} }
bool isDiscardedElement() const { bool isDiscardedElement() const {
assert(Kind == ConstraintKind::SyntacticElement); assert(Kind == ConstraintKind::SyntacticElement);
return SyntacticElement.IsDiscarded; return isDiscarded;
}
/// Retrieve the DC in which the overload was used.
DeclContext *getDeclContext() const {
ASSERT(HasDeclContext);
return *getTrailingObjects<DeclContext *>();
} }
/// For an applicable function constraint, retrieve the trailing closure /// For an applicable function constraint, retrieve the trailing closure

View File

@@ -18,6 +18,7 @@
# error #define CS_STATISTIC(Name, Description) before including # error #define CS_STATISTIC(Name, Description) before including
#endif #endif
CS_STATISTIC(ASTBytesAllocated, "bytes allocated in solver arena")
CS_STATISTIC(NumTypeVariablesBound, "# of type variables bound") CS_STATISTIC(NumTypeVariablesBound, "# of type variables bound")
CS_STATISTIC(NumTypeVariableBindings, "# of type variable bindings attempted") CS_STATISTIC(NumTypeVariableBindings, "# of type variable bindings attempted")
CS_STATISTIC(NumDisjunctions, "# of disjunctions explored") CS_STATISTIC(NumDisjunctions, "# of disjunctions explored")

View File

@@ -575,12 +575,6 @@ struct ASTContext::Implementation {
/// The set of function types. /// The set of function types.
llvm::FoldingSet<FunctionType> FunctionTypes; llvm::FoldingSet<FunctionType> FunctionTypes;
/// The set of normal protocol conformances.
llvm::FoldingSet<NormalProtocolConformance> NormalConformances;
// The set of self protocol conformances.
llvm::DenseMap<ProtocolDecl*, SelfProtocolConformance*> SelfConformances;
/// The set of specialized protocol conformances. /// The set of specialized protocol conformances.
llvm::FoldingSet<SpecializedProtocolConformance> SpecializedConformances; llvm::FoldingSet<SpecializedProtocolConformance> SpecializedConformances;
@@ -597,9 +591,6 @@ struct ASTContext::Implementation {
/// The set of substitution maps (uniqued by their storage). /// The set of substitution maps (uniqued by their storage).
llvm::FoldingSet<SubstitutionMap::Storage> SubstitutionMaps; llvm::FoldingSet<SubstitutionMap::Storage> SubstitutionMaps;
/// The set of unique AvailabilityContexts (uniqued by their storage).
llvm::FoldingSet<AvailabilityContext::Storage> AvailabilityContexts;
~Arena() { ~Arena() {
for (auto &conformance : SpecializedConformances) for (auto &conformance : SpecializedConformances)
conformance.~SpecializedProtocolConformance(); conformance.~SpecializedProtocolConformance();
@@ -613,11 +604,6 @@ struct ASTContext::Implementation {
#if SWIFT_COMPILER_IS_MSVC #if SWIFT_COMPILER_IS_MSVC
#pragma warning (default: 4189) #pragma warning (default: 4189)
#endif #endif
// Call the normal conformance destructors last since they could be
// referenced by the other conformance types.
for (auto &conformance : NormalConformances)
conformance.~NormalProtocolConformance();
} }
size_t getTotalMemory() const; size_t getTotalMemory() const;
@@ -645,6 +631,11 @@ struct ASTContext::Implementation {
AutoDiffDerivativeFunctionIdentifiers; AutoDiffDerivativeFunctionIdentifiers;
llvm::FoldingSet<GenericSignatureImpl> GenericSignatures; llvm::FoldingSet<GenericSignatureImpl> GenericSignatures;
llvm::FoldingSet<NormalProtocolConformance> NormalConformances;
llvm::DenseMap<ProtocolDecl*, SelfProtocolConformance*> SelfConformances;
/// The set of unique AvailabilityContexts (uniqued by their storage).
llvm::FoldingSet<AvailabilityContext::Storage> AvailabilityContexts;
/// A cache of information about whether particular nominal types /// A cache of information about whether particular nominal types
/// are representable in a foreign language. /// are representable in a foreign language.
@@ -720,6 +711,9 @@ ASTContext::Implementation::Implementation()
: IdentifierTable(Allocator), : IdentifierTable(Allocator),
IntrinsicScratchContext(new llvm::LLVMContext()) {} IntrinsicScratchContext(new llvm::LLVMContext()) {}
ASTContext::Implementation::~Implementation() { ASTContext::Implementation::~Implementation() {
for (auto &conformance : NormalConformances)
conformance.~NormalProtocolConformance();
for (auto &cleanup : Cleanups) for (auto &cleanup : Cleanups)
cleanup(); cleanup();
} }
@@ -889,6 +883,9 @@ void ASTContext::Implementation::dump(llvm::raw_ostream &os) const {
SIZE_AND_BYTES(SILMoveOnlyWrappedTypes); SIZE_AND_BYTES(SILMoveOnlyWrappedTypes);
SIZE_AND_BYTES(BuiltinIntegerTypes); SIZE_AND_BYTES(BuiltinIntegerTypes);
SIZE_AND_BYTES(OpenedElementEnvironments); SIZE_AND_BYTES(OpenedElementEnvironments);
SIZE(NormalConformances);
SIZE(SelfConformances);
SIZE(AvailabilityContexts);
SIZE_AND_BYTES(ForeignRepresentableCache); SIZE_AND_BYTES(ForeignRepresentableCache);
SIZE(SearchPathsSet); SIZE(SearchPathsSet);
@@ -2912,15 +2909,14 @@ ASTContext::getNormalConformance(Type conformingType,
// Did we already record the normal conformance? // Did we already record the normal conformance?
void *insertPos; void *insertPos;
auto &normalConformances = auto &normalConformances = getImpl().NormalConformances;
getImpl().getArena(AllocationArena::Permanent).NormalConformances;
if (auto result = normalConformances.FindNodeOrInsertPos(id, insertPos)) if (auto result = normalConformances.FindNodeOrInsertPos(id, insertPos))
return result; return result;
// Build a new normal protocol conformance. // Build a new normal protocol conformance.
auto result = new (*this, AllocationArena::Permanent) auto result = new (*this) NormalProtocolConformance(
NormalProtocolConformance(conformingType, protocol, loc, dc, state, conformingType, protocol, loc, dc, state,
options, preconcurrencyLoc); options, preconcurrencyLoc);
normalConformances.InsertNode(result, insertPos); normalConformances.InsertNode(result, insertPos);
return result; return result;
@@ -2929,12 +2925,11 @@ ASTContext::getNormalConformance(Type conformingType,
/// Produce a self-conformance for the given protocol. /// Produce a self-conformance for the given protocol.
SelfProtocolConformance * SelfProtocolConformance *
ASTContext::getSelfConformance(ProtocolDecl *protocol) { ASTContext::getSelfConformance(ProtocolDecl *protocol) {
auto &selfConformances = auto &selfConformances = getImpl().SelfConformances;
getImpl().getArena(AllocationArena::Permanent).SelfConformances;
auto &entry = selfConformances[protocol]; auto &entry = selfConformances[protocol];
if (!entry) { if (!entry) {
entry = new (*this, AllocationArena::Permanent) entry = new (*this) SelfProtocolConformance(
SelfProtocolConformance(protocol->getDeclaredExistentialType()); protocol->getDeclaredExistentialType());
} }
return entry; return entry;
} }
@@ -3274,6 +3269,9 @@ size_t ASTContext::getTotalMemory() const {
// getImpl().GenericSignatures ? // getImpl().GenericSignatures ?
// getImpl().CompoundNames ? // getImpl().CompoundNames ?
// getImpl().IntegerTypes ? // getImpl().IntegerTypes ?
// getImpl().NormalConformances ?
// getImpl().SelfConformances ?
// getImpl().AvailabilityContexts
getImpl().Permanent.getTotalMemory(); getImpl().Permanent.getTotalMemory();
Size += getSolverMemory(); Size += getSolverMemory();
@@ -3315,7 +3313,6 @@ size_t ASTContext::Implementation::Arena::getTotalMemory() const {
// FunctionTypes ? // FunctionTypes ?
// UnboundGenericTypes ? // UnboundGenericTypes ?
// BoundGenericTypes ? // BoundGenericTypes ?
// NormalConformances ?
// SpecializedConformances ? // SpecializedConformances ?
// InheritedConformances ? // InheritedConformances ?
// BuiltinConformances ? // BuiltinConformances ?
@@ -3360,14 +3357,11 @@ void ASTContext::Implementation::Arena::dump(llvm::raw_ostream &os) const {
SIZE_AND_BYTES(OpaqueArchetypeEnvironments); SIZE_AND_BYTES(OpaqueArchetypeEnvironments);
SIZE_AND_BYTES(OpenedExistentialEnvironments); SIZE_AND_BYTES(OpenedExistentialEnvironments);
SIZE(FunctionTypes); SIZE(FunctionTypes);
SIZE(NormalConformances);
SIZE(SelfConformances);
SIZE(SpecializedConformances); SIZE(SpecializedConformances);
SIZE(InheritedConformances); SIZE(InheritedConformances);
SIZE_AND_BYTES(BuiltinConformances); SIZE_AND_BYTES(BuiltinConformances);
SIZE(PackConformances); SIZE(PackConformances);
SIZE(SubstitutionMaps); SIZE(SubstitutionMaps);
SIZE(AvailabilityContexts);
#undef SIZE #undef SIZE
#undef SIZE_AND_BYTES #undef SIZE_AND_BYTES
@@ -5720,8 +5714,7 @@ const AvailabilityContext::Storage *AvailabilityContext::Storage::get(
AvailabilityContext::Storage::Profile(id, platformRange, isDeprecated, AvailabilityContext::Storage::Profile(id, platformRange, isDeprecated,
domainInfos); domainInfos);
auto &foldingSet = auto &foldingSet = ctx.getImpl().AvailabilityContexts;
ctx.getImpl().getArena(AllocationArena::Permanent).AvailabilityContexts;
void *insertPos; void *insertPos;
auto *existing = foldingSet.FindNodeOrInsertPos(id, insertPos); auto *existing = foldingSet.FindNodeOrInsertPos(id, insertPos);
if (existing) if (existing)

View File

@@ -13118,7 +13118,7 @@ retry_after_fail:
// Determine the type that this choice will have. // Determine the type that this choice will have.
Type choiceType = getEffectiveOverloadType( Type choiceType = getEffectiveOverloadType(
constraint->getLocator(), choice, /*allowMembers=*/true, constraint->getLocator(), choice, /*allowMembers=*/true,
constraint->getOverloadUseDC()); constraint->getDeclContext());
if (!choiceType) { if (!choiceType) {
hasUnhandledConstraints = true; hasUnhandledConstraints = true;
return true; return true;
@@ -16364,7 +16364,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
return simplifyApplicableFnConstraint( return simplifyApplicableFnConstraint(
constraint.getAppliedFunctionType(), constraint.getCalleeType(), constraint.getAppliedFunctionType(), constraint.getCalleeType(),
constraint.getTrailingClosureMatching(), constraint.getTrailingClosureMatching(),
constraint.getApplicationDC(), /*flags=*/std::nullopt, constraint.getDeclContext(), /*flags=*/std::nullopt,
constraint.getLocator()); constraint.getLocator());
case ConstraintKind::DynamicCallableApplicableFunction: case ConstraintKind::DynamicCallableApplicableFunction:
@@ -16411,7 +16411,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
resolveOverload(constraint.getLocator(), constraint.getFirstType(), resolveOverload(constraint.getLocator(), constraint.getFirstType(),
constraint.getOverloadChoice(), constraint.getOverloadChoice(),
constraint.getOverloadUseDC()); constraint.getDeclContext());
return SolutionKind::Solved; return SolutionKind::Solved;
case ConstraintKind::SubclassOf: case ConstraintKind::SubclassOf:
@@ -16458,7 +16458,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
case ConstraintKind::UnresolvedValueMember: case ConstraintKind::UnresolvedValueMember:
return simplifyMemberConstraint( return simplifyMemberConstraint(
constraint.getKind(), constraint.getFirstType(), constraint.getMember(), constraint.getKind(), constraint.getFirstType(), constraint.getMember(),
constraint.getSecondType(), constraint.getMemberUseDC(), constraint.getSecondType(), constraint.getDeclContext(),
constraint.getFunctionRefInfo(), constraint.getFunctionRefInfo(),
/*outerAlternatives=*/{}, /*outerAlternatives=*/{},
/*flags*/ std::nullopt, constraint.getLocator()); /*flags*/ std::nullopt, constraint.getLocator());
@@ -16467,7 +16467,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
return simplifyValueWitnessConstraint( return simplifyValueWitnessConstraint(
constraint.getKind(), constraint.getFirstType(), constraint.getKind(), constraint.getFirstType(),
constraint.getRequirement(), constraint.getSecondType(), constraint.getRequirement(), constraint.getSecondType(),
constraint.getMemberUseDC(), constraint.getFunctionRefInfo(), constraint.getDeclContext(), constraint.getFunctionRefInfo(),
/*flags*/ std::nullopt, constraint.getLocator()); /*flags*/ std::nullopt, constraint.getLocator());
case ConstraintKind::Defaultable: case ConstraintKind::Defaultable:

View File

@@ -669,6 +669,10 @@ ConstraintSystem::SolverState::~SolverState() {
CS.Options -= ConstraintSystemFlags::DebugConstraints; CS.Options -= ConstraintSystemFlags::DebugConstraints;
} }
// This statistic is special because it's not a counter; we just update
// it in one shot at the end.
ASTBytesAllocated = CS.getASTContext().getSolverMemory();
// Write our local statistics back to the overall statistics. // Write our local statistics back to the overall statistics.
#define CS_STATISTIC(Name, Description) JOIN2(Overall,Name) += Name; #define CS_STATISTIC(Name, Description) JOIN2(Overall,Name) += Name;
#include "swift/Sema/ConstraintSolverStats.def" #include "swift/Sema/ConstraintSolverStats.def"

View File

@@ -30,9 +30,10 @@ using namespace constraints;
Constraint::Constraint(ConstraintKind kind, ArrayRef<Constraint *> constraints, Constraint::Constraint(ConstraintKind kind, ArrayRef<Constraint *> constraints,
bool isIsolated, ConstraintLocator *locator, bool isIsolated, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(kind), HasFix(false), HasRestriction(false), IsActive(false), : Kind(kind), NumTypeVariables(typeVars.size()),
IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), HasFix(false), HasDeclContext(false), HasRestriction(false),
IsFavored(false), IsIsolated(isIsolated), NumTypeVariables(typeVars.size()), IsActive(false), IsDisabled(false), IsDisabledForPerformance(false),
RememberChoice(false), IsFavored(false), IsIsolated(isIsolated),
Nested(constraints), Locator(locator) { Nested(constraints), Locator(locator) {
assert(kind == ConstraintKind::Disjunction || assert(kind == ConstraintKind::Disjunction ||
kind == ConstraintKind::Conjunction); kind == ConstraintKind::Conjunction);
@@ -54,10 +55,11 @@ static bool isAdmissibleType(Type type) {
Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
ConstraintLocator *locator, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(Kind), HasFix(false), HasRestriction(false), IsActive(false), : Kind(Kind), NumTypeVariables(typeVars.size()),
IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), HasFix(false), HasDeclContext(false), HasRestriction(false),
IsFavored(false), IsIsolated(false), IsActive(false), IsDisabled(false), IsDisabledForPerformance(false),
NumTypeVariables(typeVars.size()), Types{First, Second, Type()}, RememberChoice(false), IsFavored(false), IsIsolated(false),
Types{First, Second, Type()},
Locator(locator) { Locator(locator) {
ASSERT(isAdmissibleType(First)); ASSERT(isAdmissibleType(First));
ASSERT(isAdmissibleType(Second)); ASSERT(isAdmissibleType(Second));
@@ -135,10 +137,11 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third, Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
ConstraintLocator *locator, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(Kind), HasFix(false), HasRestriction(false), IsActive(false), : Kind(Kind), NumTypeVariables(typeVars.size()),
IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), HasFix(false), HasDeclContext(false), HasRestriction(false),
IsFavored(false), IsIsolated(false), IsActive(false), IsDisabled(false), IsDisabledForPerformance(false),
NumTypeVariables(typeVars.size()), Types{First, Second, Third}, RememberChoice(false), IsFavored(false), IsIsolated(false),
Types{First, Second, Third},
Locator(locator) { Locator(locator) {
ASSERT(isAdmissibleType(First)); ASSERT(isAdmissibleType(First));
ASSERT(isAdmissibleType(Second)); ASSERT(isAdmissibleType(Second));
@@ -201,10 +204,11 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second,
FunctionRefInfo functionRefInfo, FunctionRefInfo functionRefInfo,
ConstraintLocator *locator, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(kind), HasFix(false), HasRestriction(false), IsActive(false), : Kind(kind), NumTypeVariables(typeVars.size()),
IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), HasFix(false), HasDeclContext(true), HasRestriction(false),
IsFavored(false), IsIsolated(false), IsActive(false), IsDisabled(false), IsDisabledForPerformance(false),
NumTypeVariables(typeVars.size()), Member{first, second, {member}, useDC}, RememberChoice(false), IsFavored(false), IsIsolated(false),
Member{first, second, {member}},
Locator(locator) { Locator(locator) {
assert(kind == ConstraintKind::ValueMember || assert(kind == ConstraintKind::ValueMember ||
kind == ConstraintKind::UnresolvedValueMember); kind == ConstraintKind::UnresolvedValueMember);
@@ -214,6 +218,7 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second,
assert(useDC && "Member constraint has no use DC"); assert(useDC && "Member constraint has no use DC");
std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
*getTrailingObjects<DeclContext *>() = useDC;
} }
Constraint::Constraint(ConstraintKind kind, Type first, Type second, Constraint::Constraint(ConstraintKind kind, Type first, Type second,
@@ -221,14 +226,14 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second,
FunctionRefInfo functionRefInfo, FunctionRefInfo functionRefInfo,
ConstraintLocator *locator, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(kind), HasFix(false), HasRestriction(false), IsActive(false), : Kind(kind), NumTypeVariables(typeVars.size()),
IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), HasFix(false), HasDeclContext(true), HasRestriction(false),
IsFavored(false), IsIsolated(false), NumTypeVariables(typeVars.size()), IsActive(false), IsDisabled(false), IsDisabledForPerformance(false),
RememberChoice(false), IsFavored(false), IsIsolated(false),
Locator(locator) { Locator(locator) {
Member.First = first; Member.First = first;
Member.Second = second; Member.Second = second;
Member.Member.Ref = requirement; Member.Member.Ref = requirement;
Member.UseDC = useDC;
TheFunctionRefInfo = functionRefInfo.getOpaqueValue(); TheFunctionRefInfo = functionRefInfo.getOpaqueValue();
assert(kind == ConstraintKind::ValueWitness); assert(kind == ConstraintKind::ValueWitness);
@@ -237,19 +242,21 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second,
assert(useDC && "Member constraint has no use DC"); assert(useDC && "Member constraint has no use DC");
std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
*getTrailingObjects<DeclContext *>() = useDC;
} }
Constraint::Constraint(Type type, OverloadChoice choice, DeclContext *useDC, Constraint::Constraint(Type type, OverloadChoice choice, DeclContext *useDC,
ConstraintFix *fix, ConstraintLocator *locator, ConstraintFix *fix, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(ConstraintKind::BindOverload), HasFix(fix != nullptr), HasRestriction(false), : Kind(ConstraintKind::BindOverload), NumTypeVariables(typeVars.size()),
HasFix(fix != nullptr), HasDeclContext(true), HasRestriction(false),
IsActive(false), IsDisabled(bool(fix)), IsDisabledForPerformance(false), IsActive(false), IsDisabled(bool(fix)), IsDisabledForPerformance(false),
RememberChoice(false), IsFavored(false), IsIsolated(false), RememberChoice(false), IsFavored(false), IsIsolated(false),
NumTypeVariables(typeVars.size()), Overload{type, useDC}, Overload{type}, Locator(locator) {
Locator(locator) {
std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
if (fix) if (fix)
*getTrailingObjects<ConstraintFix *>() = fix; *getTrailingObjects<ConstraintFix *>() = fix;
*getTrailingObjects<DeclContext *>() = useDC;
*getTrailingObjects<OverloadChoice>() = choice; *getTrailingObjects<OverloadChoice>() = choice;
} }
@@ -257,10 +264,10 @@ Constraint::Constraint(ConstraintKind kind,
ConversionRestrictionKind restriction, Type first, ConversionRestrictionKind restriction, Type first,
Type second, ConstraintLocator *locator, Type second, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(kind), Restriction(restriction), HasFix(false), HasRestriction(true), : Kind(kind), Restriction(restriction), NumTypeVariables(typeVars.size()),
IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), HasFix(false), HasDeclContext(false), HasRestriction(true), IsActive(false),
RememberChoice(false), IsFavored(false), IsIsolated(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false),
NumTypeVariables(typeVars.size()), Types{first, second, Type()}, IsFavored(false), IsIsolated(false), Types{first, second, Type()},
Locator(locator) { Locator(locator) {
ASSERT(isAdmissibleType(first)); ASSERT(isAdmissibleType(first));
ASSERT(isAdmissibleType(second)); ASSERT(isAdmissibleType(second));
@@ -270,10 +277,11 @@ Constraint::Constraint(ConstraintKind kind,
Constraint::Constraint(ConstraintKind kind, ConstraintFix *fix, Type first, Constraint::Constraint(ConstraintKind kind, ConstraintFix *fix, Type first,
Type second, ConstraintLocator *locator, Type second, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(kind), HasFix(fix != nullptr), HasRestriction(false), IsActive(false), : Kind(kind), NumTypeVariables(typeVars.size()),
IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), HasFix(fix != nullptr), HasDeclContext(false), HasRestriction(false),
IsFavored(false), IsIsolated(false), IsActive(false), IsDisabled(false), IsDisabledForPerformance(false),
NumTypeVariables(typeVars.size()), Types{first, second, Type()}, RememberChoice(false), IsFavored(false), IsIsolated(false),
Types{first, second, Type()},
Locator(locator) { Locator(locator) {
ASSERT(isAdmissibleType(first)); ASSERT(isAdmissibleType(first));
ASSERT(isAdmissibleType(second)); ASSERT(isAdmissibleType(second));
@@ -285,24 +293,26 @@ Constraint::Constraint(ConstraintKind kind, ConstraintFix *fix, Type first,
Constraint::Constraint(ASTNode node, ContextualTypeInfo context, Constraint::Constraint(ASTNode node, ContextualTypeInfo context,
bool isDiscarded, ConstraintLocator *locator, bool isDiscarded, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(ConstraintKind::SyntacticElement), HasFix(false), : Kind(ConstraintKind::SyntacticElement), NumTypeVariables(typeVars.size()),
HasRestriction(false), IsActive(false), IsDisabled(false), HasFix(false), HasDeclContext(false), HasRestriction(false), IsActive(false),
IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false),
IsIsolated(false), IsFavored(false), IsIsolated(false), isDiscarded(isDiscarded),
NumTypeVariables(typeVars.size()), SyntacticElement{node, context, SyntacticElement{node},
isDiscarded},
Locator(locator) { Locator(locator) {
std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
*getTrailingObjects<ContextualTypeInfo>() = context;
} }
Constraint::Constraint(FunctionType *appliedFn, Type calleeType, Constraint::Constraint(FunctionType *appliedFn, Type calleeType,
unsigned trailingClosureMatching, DeclContext *useDC, unsigned trailingClosureMatching, DeclContext *useDC,
ConstraintLocator *locator, ConstraintLocator *locator,
SmallPtrSetImpl<TypeVariableType *> &typeVars) SmallPtrSetImpl<TypeVariableType *> &typeVars)
: Kind(ConstraintKind::ApplicableFunction), HasFix(false), : Kind(ConstraintKind::ApplicableFunction), NumTypeVariables(typeVars.size()),
HasRestriction(false), IsActive(false), IsDisabled(false), HasFix(false), HasDeclContext(true), HasRestriction(false), IsActive(false),
IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false),
IsIsolated(false), NumTypeVariables(typeVars.size()), Locator(locator) { IsFavored(false), IsIsolated(false),
trailingClosureMatching(trailingClosureMatching),
Locator(locator) {
ASSERT(isAdmissibleType(appliedFn)); ASSERT(isAdmissibleType(appliedFn));
ASSERT(isAdmissibleType(calleeType)); ASSERT(isAdmissibleType(calleeType));
assert(trailingClosureMatching >= 0 && trailingClosureMatching <= 2); assert(trailingClosureMatching >= 0 && trailingClosureMatching <= 2);
@@ -310,10 +320,9 @@ Constraint::Constraint(FunctionType *appliedFn, Type calleeType,
Apply.AppliedFn = appliedFn; Apply.AppliedFn = appliedFn;
Apply.Callee = calleeType; Apply.Callee = calleeType;
Apply.TrailingClosureMatching = trailingClosureMatching;
Apply.UseDC = useDC;
std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
*getTrailingObjects<DeclContext *>() = useDC;
} }
ProtocolDecl *Constraint::getProtocol() const { ProtocolDecl *Constraint::getProtocol() const {
@@ -782,8 +791,10 @@ Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind,
// Create the constraint. // Create the constraint.
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
return ::new (mem) Constraint(kind, first, second, locator, typeVars); return ::new (mem) Constraint(kind, first, second, locator, typeVars);
} }
@@ -803,8 +814,10 @@ Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind,
third->getTypeVariables(typeVars); third->getTypeVariables(typeVars);
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
return ::new (mem) Constraint(kind, return ::new (mem) Constraint(kind,
first, second, third, first, second, third,
@@ -846,8 +859,10 @@ Constraint *Constraint::createMember(ConstraintSystem &cs, ConstraintKind kind,
// Create the constraint. // Create the constraint.
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/1,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
return new (mem) Constraint(kind, first, second, member, useDC, return new (mem) Constraint(kind, first, second, member, useDC,
functionRefInfo, locator, typeVars); functionRefInfo, locator, typeVars);
@@ -868,8 +883,10 @@ Constraint *Constraint::createValueWitness(
// Create the constraint. // Create the constraint.
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/1,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
return new (mem) Constraint(kind, first, second, requirement, useDC, return new (mem) Constraint(kind, first, second, requirement, useDC,
functionRefInfo, locator, typeVars); functionRefInfo, locator, typeVars);
@@ -890,8 +907,10 @@ Constraint *Constraint::createBindOverload(ConstraintSystem &cs, Type type,
// Create the constraint. // Create the constraint.
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), fix ? 1 : 0, /*hasOverloadChoice=*/1); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), fix ? 1 : 0, /*hasDeclContext=*/1,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/1);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
return new (mem) Constraint(type, choice, useDC, fix, locator, typeVars); return new (mem) Constraint(type, choice, useDC, fix, locator, typeVars);
} }
@@ -910,8 +929,10 @@ Constraint *Constraint::createRestricted(ConstraintSystem &cs,
// Create the constraint. // Create the constraint.
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
return new (mem) Constraint(kind, restriction, first, second, locator, return new (mem) Constraint(kind, restriction, first, second, locator,
typeVars); typeVars);
@@ -929,8 +950,10 @@ Constraint *Constraint::createFixed(ConstraintSystem &cs, ConstraintKind kind,
// Create the constraint. // Create the constraint.
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), fix ? 1 : 0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), fix ? 1 : 0, /*hasDeclContext=*/0,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
return new (mem) Constraint(kind, fix, first, second, locator, typeVars); return new (mem) Constraint(kind, fix, first, second, locator, typeVars);
} }
@@ -1001,8 +1024,10 @@ Constraint *Constraint::createDisjunction(ConstraintSystem &cs,
// Create the disjunction constraint. // Create the disjunction constraint.
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
auto disjunction = new (mem) auto disjunction = new (mem)
Constraint(ConstraintKind::Disjunction, cs.allocateCopy(constraints), Constraint(ConstraintKind::Disjunction, cs.allocateCopy(constraints),
@@ -1022,8 +1047,10 @@ Constraint *Constraint::createConjunction(
assert(!constraints.empty() && "Empty conjunction constraint"); assert(!constraints.empty() && "Empty conjunction constraint");
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
auto conjunction = new (mem) auto conjunction = new (mem)
Constraint(ConstraintKind::Conjunction, cs.allocateCopy(constraints), Constraint(ConstraintKind::Conjunction, cs.allocateCopy(constraints),
@@ -1058,8 +1085,10 @@ Constraint *Constraint::createApplicableFunction(
// Create the constraint. // Create the constraint.
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/1,
/*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
auto constraint = new (mem) auto constraint = new (mem)
Constraint(argumentFnType, calleeType, rawTrailingClosureMatching, useDC, Constraint(argumentFnType, calleeType, rawTrailingClosureMatching, useDC,
@@ -1087,8 +1116,10 @@ Constraint *Constraint::createSyntacticElement(ConstraintSystem &cs,
contextTy->getTypeVariables(typeVars); contextTy->getTypeVariables(typeVars);
auto size = auto size =
totalSizeToAlloc<TypeVariableType *, ConstraintFix *, OverloadChoice>( totalSizeToAlloc<TypeVariableType *, ConstraintFix *, DeclContext *,
typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); ContextualTypeInfo, OverloadChoice>(
typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0,
/*hasContextualTypeInfo=*/1, /*hasOverloadChoice=*/0);
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
return new (mem) Constraint(node, context, isDiscarded, locator, typeVars); return new (mem) Constraint(node, context, isDiscarded, locator, typeVars);
} }
@@ -1096,7 +1127,7 @@ Constraint *Constraint::createSyntacticElement(ConstraintSystem &cs,
std::optional<TrailingClosureMatching> std::optional<TrailingClosureMatching>
Constraint::getTrailingClosureMatching() const { Constraint::getTrailingClosureMatching() const {
assert(Kind == ConstraintKind::ApplicableFunction); assert(Kind == ConstraintKind::ApplicableFunction);
switch (Apply.TrailingClosureMatching) { switch (trailingClosureMatching) {
case 0: case 0:
return std::nullopt; return std::nullopt;
case 1: return TrailingClosureMatching::Forward; case 1: return TrailingClosureMatching::Forward;

View File

@@ -218,7 +218,7 @@ TEST_F(SemaTest, TestInitializerUseDCIsSetCorrectlyInClosure) {
->isLastElement<LocatorPathElt::ConstructorMember>()); ->isLastElement<LocatorPathElt::ConstructorMember>());
for (auto *choice : constraint->getNestedConstraints()) for (auto *choice : constraint->getNestedConstraints())
ASSERT_EQ(choice->getOverloadUseDC(), closure); ASSERT_EQ(choice->getDeclContext(), closure);
} }
} }
} }