Skip to content

Miscellaneous solver cleanups #77178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions include/swift/AST/ExistentialLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines the ExistentialLayout struct.
// The ExistentialLayout struct describes the in-memory layout of an existential
// type.
//
// It flattens and canonicalizes protocol compositions, and also expands defaults
// for invertible protocols.
//
//===----------------------------------------------------------------------===//

Expand All @@ -33,7 +37,6 @@ struct ExistentialLayout {
hasExplicitAnyObject = false;
containsObjCProtocol = false;
containsSwiftProtocol = false;
containsParameterized = false;
representsAnyObject = false;
}

Expand All @@ -53,9 +56,6 @@ struct ExistentialLayout {
/// Whether any protocol members require a witness table.
bool containsSwiftProtocol : 1;

/// Whether any protocol members are parameterized.s
bool containsParameterized : 1;

/// Whether this layout is the canonical layout for plain-old 'AnyObject'.
bool representsAnyObject : 1;

Expand Down Expand Up @@ -105,14 +105,18 @@ struct ExistentialLayout {
/// calling this on a temporary is likely to be incorrect.
ArrayRef<ProtocolDecl*> getProtocols() const && = delete;

ArrayRef<ParameterizedProtocolType *> getParameterizedProtocols() const & {
return parameterized;
}
/// The returned ArrayRef points to internal storage, so
/// calling this on a temporary is likely to be incorrect.
ArrayRef<ProtocolDecl*> getParameterizedProtocols() const && = delete;

LayoutConstraint getLayoutConstraint() const;

private:
SmallVector<ProtocolDecl *, 4> protocols;

/// Zero or more primary associated type requirements from a
/// ParameterizedProtocolType
ArrayRef<Type> sameTypeRequirements;
SmallVector<ParameterizedProtocolType *, 4> parameterized;
};

}
Expand Down
55 changes: 26 additions & 29 deletions include/swift/Sema/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,6 @@ enum class ConstraintKind : char {
LiteralConformsTo,
/// A checked cast from the first type to the second.
CheckedCast,
/// The first type can act as the Self type of the second type (which
/// is a protocol).
///
/// This constraint is slightly looser than a conforms-to constraint, because
/// an existential can be used as the Self of any protocol within the
/// existential, even if it doesn't conform to that protocol (e.g., due to
/// the use of associated types).
SelfObjectOfProtocol,
/// Both types are function types. The first function type's
/// input is the value being passed to the function and its output
/// is a type variable that describes the output. The second
Expand Down Expand Up @@ -344,7 +336,10 @@ enum RememberChoice_t : bool {

/// A constraint between two type variables.
class Constraint final : public llvm::ilist_node<Constraint>,
private llvm::TrailingObjects<Constraint, TypeVariableType *> {
private llvm::TrailingObjects<Constraint,
TypeVariableType *,
ConstraintFix *,
OverloadChoice> {
friend TrailingObjects;

/// The kind of constraint.
Expand All @@ -353,8 +348,8 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// The kind of restriction placed on this constraint.
ConversionRestrictionKind Restriction : 8;

/// The fix to be applied to the constraint before visiting it.
ConstraintFix *TheFix = nullptr;
/// Whether we have a fix.
unsigned HasFix : 1;

/// Whether the \c Restriction field is valid.
unsigned HasRestriction : 1;
Expand Down Expand Up @@ -438,9 +433,6 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// The first type
Type First;

/// The overload choice
OverloadChoice Choice;

/// The DC in which the use appears.
DeclContext *UseDC;
} Overload;
Expand Down Expand Up @@ -514,6 +506,18 @@ class Constraint final : public llvm::ilist_node<Constraint>,
return { getTrailingObjects<TypeVariableType *>(), NumTypeVariables };
}

size_t numTrailingObjects(OverloadToken<TypeVariableType *>) const {
return NumTypeVariables;
}

size_t numTrailingObjects(OverloadToken<ConstraintFix *>) const {
return HasFix ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<OverloadChoice>) const {
return Kind == ConstraintKind::BindOverload ? 1 : 0;
}

public:
/// Create a new constraint.
static Constraint *create(ConstraintSystem &cs, ConstraintKind Kind,
Expand Down Expand Up @@ -546,10 +550,10 @@ class Constraint final : public llvm::ilist_node<Constraint>,
ValueDecl *requirement, DeclContext *useDC,
FunctionRefKind functionRefKind, ConstraintLocator *locator);

/// Create an overload-binding constraint.
/// Create an overload-binding constraint, possibly with a fix.
static Constraint *createBindOverload(ConstraintSystem &cs, Type type,
OverloadChoice choice,
DeclContext *useDC,
DeclContext *useDC, ConstraintFix *fix,
ConstraintLocator *locator);

/// Create a restricted relational constraint.
Expand All @@ -563,13 +567,6 @@ class Constraint final : public llvm::ilist_node<Constraint>,
ConstraintFix *fix, Type first, Type second,
ConstraintLocator *locator);

/// Create a bind overload choice with a fix.
/// Note: This constraint is going to be disabled by default.
static Constraint *createFixedChoice(ConstraintSystem &cs, Type type,
OverloadChoice choice,
DeclContext *useDC, ConstraintFix *fix,
ConstraintLocator *locator);

/// Create a new disjunction constraint.
static Constraint *createDisjunction(ConstraintSystem &cs,
ArrayRef<Constraint *> constraints,
Expand Down Expand Up @@ -616,7 +613,11 @@ class Constraint final : public llvm::ilist_node<Constraint>,
}

/// Retrieve the fix associated with this constraint.
ConstraintFix *getFix() const { return TheFix; }
ConstraintFix *getFix() const {
if (HasFix)
return *getTrailingObjects<ConstraintFix *>();
return nullptr;
}

/// Whether this constraint is active, i.e., in the worklist.
bool isActive() const { return IsActive; }
Expand Down Expand Up @@ -681,7 +682,6 @@ class Constraint final : public llvm::ilist_node<Constraint>,
case ConstraintKind::LiteralConformsTo:
case ConstraintKind::TransitivelyConformsTo:
case ConstraintKind::CheckedCast:
case ConstraintKind::SelfObjectOfProtocol:
case ConstraintKind::ApplicableFunction:
case ConstraintKind::DynamicCallableApplicableFunction:
case ConstraintKind::BindOverload:
Expand Down Expand Up @@ -849,7 +849,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// Retrieve the overload choice for an overload-binding constraint.
OverloadChoice getOverloadChoice() const {
assert(Kind == ConstraintKind::BindOverload);
return Overload.Choice;
return *getTrailingObjects<OverloadChoice>();
}

/// Retrieve the DC in which the overload was used.
Expand Down Expand Up @@ -888,9 +888,6 @@ class Constraint final : public llvm::ilist_node<Constraint>,
/// Retrieve the locator for this constraint.
ConstraintLocator *getLocator() const { return Locator; }

/// Clone the given constraint.
Constraint *clone(ConstraintSystem &cs) const;

/// Print constraint placed on type and constraint properties.
///
/// \c skipLocator skips printing of locators.
Expand Down
53 changes: 6 additions & 47 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -2075,14 +2075,6 @@ struct ClosureIsolatedByPreconcurrency {
bool operator()(const ClosureExpr *expr) const;
};

/// Determine whether the given expression is part of the left-hand side
/// of an assignment expression.
struct IsInLeftHandSideOfAssignment {
ConstraintSystem &cs;

bool operator()(Expr *expr) const;
};

/// Describes the type produced when referencing a declaration.
struct DeclReferenceType {
/// The "opened" type, which is the type of the declaration where any
Expand Down Expand Up @@ -4374,39 +4366,6 @@ class ConstraintSystem {
bool wantInterfaceType = false,
bool adjustForPreconcurrency = true);

/// Return the type-of-reference of the given value.
///
/// \param baseType if non-null, return the type of a member reference to
/// this value when the base has the given type
///
/// \param UseDC The context of the access. Some variables have different
/// types depending on where they are used.
///
/// \param locator The locator anchored at this value reference, when
/// it is a member reference.
///
/// \param wantInterfaceType Whether we want the interface type, if available.
///
/// \param getType Optional callback to extract a type for given declaration.
static Type
getUnopenedTypeOfReference(
VarDecl *value, Type baseType, DeclContext *UseDC,
llvm::function_ref<Type(VarDecl *)> getType,
ConstraintLocator *locator,
bool wantInterfaceType = false,
bool adjustForPreconcurrency = true,
llvm::function_ref<Type(const AbstractClosureExpr *)> getClosureType =
[](const AbstractClosureExpr *) {
return Type();
},
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency =
[](const ClosureExpr *closure) {
return closure->isIsolatedByPreconcurrency();
},
llvm::function_ref<bool(Expr *)> isAssignTarget = [](Expr *) {
return false;
});

/// Given the opened type and a pile of information about a member reference,
/// determine the reference type of the member reference.
Type getMemberReferenceTypeFromOpenedType(
Expand Down Expand Up @@ -4642,7 +4601,7 @@ class ConstraintSystem {
/// \param getFix Optional callback to determine a fix for a given
/// choice (first argument is a position of current choice,
/// second - the choice in question).
void generateConstraints(
void generateOverloadConstraints(
SmallVectorImpl<Constraint *> &constraints, Type type,
ArrayRef<OverloadChoice> choices, DeclContext *useDC,
ConstraintLocator *locator,
Expand Down Expand Up @@ -4761,10 +4720,10 @@ class ConstraintSystem {
/// Subroutine of \c matchTypes(), which matches up a value to an
/// existential type.
///
/// \param kind Either ConstraintKind::SelfObjectOfProtocol or
/// ConstraintKind::ConformsTo. Usually this uses SelfObjectOfProtocol,
/// but when matching the instance type of a metatype with the instance type
/// of an existential metatype, since we want an actual conformance check.
/// \param kind Either ConstraintKind::Subtype or ConstraintKind::ConformsTo.
/// Usually this uses Subtype, but when matching the instance type of a
/// metatype with the instance type of an existential metatype, since we
/// want an actual conformance check.
TypeMatchResult matchExistentialTypes(Type type1, Type type2,
ConstraintKind kind,
TypeMatchOptions flags,
Expand Down Expand Up @@ -4971,7 +4930,7 @@ class ConstraintSystem {
///
/// \param type The type being tested.
/// \param protocol The protocol to which the type should conform.
/// \param kind Either ConstraintKind::SelfObjectOfProtocol or
/// \param kind Either ConstraintKind::Subtype or
/// ConstraintKind::ConformsTo.
/// \param locator Locator describing where this constraint occurred.
SolutionKind simplifyConformsToConstraint(Type type, ProtocolDecl *protocol,
Expand Down
11 changes: 4 additions & 7 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@ ExistentialLayout::ExistentialLayout(CanProtocolType type) {
containsObjCProtocol = protoDecl->isObjC();
containsSwiftProtocol = (!protoDecl->isObjC() &&
!protoDecl->isMarkerProtocol());
containsParameterized = false;
representsAnyObject = false;

protocols.push_back(protoDecl);
Expand All @@ -316,7 +315,6 @@ ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) {
hasExplicitAnyObject = type->hasExplicitAnyObject();
containsObjCProtocol = false;
containsSwiftProtocol = false;
containsParameterized = false;

auto members = type.getMembers();
if (!members.empty() &&
Expand All @@ -331,9 +329,9 @@ ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) {
if (auto protocolType = dyn_cast<ProtocolType>(member)) {
protoDecl = protocolType->getDecl();
} else {
auto parameterized = cast<ParameterizedProtocolType>(member);
protoDecl = parameterized->getProtocol();
containsParameterized = true;
auto *parameterizedType = member->castTo<ParameterizedProtocolType>();
protoDecl = parameterizedType->getProtocol();
parameterized.push_back(parameterizedType);
}
if (protoDecl->isObjC())
containsObjCProtocol = true;
Expand Down Expand Up @@ -366,8 +364,7 @@ ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) {

ExistentialLayout::ExistentialLayout(CanParameterizedProtocolType type)
: ExistentialLayout(type.getBaseType()) {
sameTypeRequirements = type->getArgs();
containsParameterized = true;
parameterized.push_back(type);
}

ExistentialLayout TypeBase::getExistentialLayout() {
Expand Down
4 changes: 2 additions & 2 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ static bool usesExtendedExistentialMetadata(CanType type) {
// should turn them into unparameterized protocol types. If the
// structure makes it to IRGen, we have to honor that decision that
// they represent different types.
return layout.containsParameterized;
return !layout.getParameterizedProtocols().empty();
}

static std::optional<std::pair<CanExistentialType, /*depth*/ unsigned>>
Expand Down Expand Up @@ -2026,7 +2026,7 @@ namespace {
llvm::Value *emitExistentialTypeMetadata(CanExistentialType type) {
auto layout = type.getExistentialLayout();

if (layout.containsParameterized) {
if (!layout.getParameterizedProtocols().empty()) {
return emitExtendedExistentialTypeMetadata(type);
}

Expand Down
4 changes: 1 addition & 3 deletions lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1873,8 +1873,7 @@ void PotentialBindings::infer(Constraint *constraint) {
DelayedBy.push_back(constraint);
break;

case ConstraintKind::ConformsTo:
case ConstraintKind::SelfObjectOfProtocol: {
case ConstraintKind::ConformsTo: {
auto protocolTy = constraint->getSecondType();
if (protocolTy->is<ProtocolType>())
Protocols.push_back(constraint);
Expand Down Expand Up @@ -1985,7 +1984,6 @@ void PotentialBindings::retract(Constraint *constraint) {

switch (constraint->getKind()) {
case ConstraintKind::ConformsTo:
case ConstraintKind::SelfObjectOfProtocol:
Protocols.erase(llvm::remove_if(Protocols, isMatchingConstraint),
Protocols.end());
break;
Expand Down
Loading