Skip to content

Commit aba30e7

Browse files
authored
Merge pull request swiftlang#39543 from hamishknight/constructing-a-tier-list
2 parents a94e961 + ac50dfd commit aba30e7

File tree

11 files changed

+131
-157
lines changed

11 files changed

+131
-157
lines changed

include/swift/Sema/Constraint.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,6 @@ enum class ConstraintKind : char {
171171
/// The key path type is chosen based on the selection of overloads for the
172172
/// member references along the path.
173173
KeyPath,
174-
/// The first type is a function type, the second is the function's
175-
/// input type.
176-
FunctionInput,
177-
/// The first type is a function type, the second is the function's
178-
/// result type.
179-
FunctionResult,
180174
/// The first type will be equal to the second type, but only when the
181175
/// second type has been fully determined (and mapped down to a concrete
182176
/// type). At that point, this constraint will be treated like an `Equal`
@@ -691,8 +685,6 @@ class Constraint final : public llvm::ilist_node<Constraint>,
691685
case ConstraintKind::KeyPath:
692686
case ConstraintKind::KeyPathApplication:
693687
case ConstraintKind::Defaultable:
694-
case ConstraintKind::FunctionInput:
695-
case ConstraintKind::FunctionResult:
696688
return ConstraintClassification::TypeProperty;
697689

698690
case ConstraintKind::Disjunction:

include/swift/Sema/ConstraintLocator.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,25 @@ class LocatorPathElt::KeyPathType final
960960
}
961961
};
962962

963+
class LocatorPathElt::ConstructorMemberType final
964+
: public StoredIntegerElement<1> {
965+
public:
966+
ConstructorMemberType(bool isShortFormOrSelfDelegating = false)
967+
: StoredIntegerElement(ConstraintLocator::ConstructorMemberType,
968+
isShortFormOrSelfDelegating) {}
969+
970+
/// Whether this constructor overload is for a short-form init call such as
971+
/// 'X(...)', or a 'self.init(...)' call. Such calls have additional ranking
972+
/// rules.
973+
bool isShortFormOrSelfDelegatingConstructor() const {
974+
return bool(getValue());
975+
}
976+
977+
static bool classof(const LocatorPathElt *elt) {
978+
return elt->getKind() == ConstraintLocator::ConstructorMemberType;
979+
}
980+
};
981+
963982
class LocatorPathElt::ClosureBodyElement final
964983
: public StoredPointerElement<void> {
965984
public:

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ CUSTOM_LOCATOR_PATH_ELT(ClosureBody)
6060
/// The lookup for a constructor member.
6161
SIMPLE_LOCATOR_PATH_ELT(ConstructorMember)
6262

63+
/// The constructor member type in the lookup of a constructor.
64+
CUSTOM_LOCATOR_PATH_ELT(ConstructorMemberType)
65+
6366
/// The desired contextual type passed in to the constraint system.
6467
CUSTOM_LOCATOR_PATH_ELT(ContextualType)
6568

include/swift/Sema/ConstraintSystem.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4751,13 +4751,6 @@ class ConstraintSystem {
47514751
TypeMatchOptions flags,
47524752
ConstraintLocatorBuilder locator);
47534753

4754-
/// Attempt to simplify a function input or result constraint.
4755-
SolutionKind simplifyFunctionComponentConstraint(
4756-
ConstraintKind kind,
4757-
Type first, Type second,
4758-
TypeMatchOptions flags,
4759-
ConstraintLocatorBuilder locator);
4760-
47614754
/// Attempt to simplify the BridgingConversion constraint.
47624755
SolutionKind simplifyBridgingConstraint(Type type1,
47634756
Type type2,

lib/Sema/CSBindings.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,8 +1336,6 @@ void PotentialBindings::infer(Constraint *constraint) {
13361336
case ConstraintKind::EscapableFunctionOf:
13371337
case ConstraintKind::OpenedExistentialOf:
13381338
case ConstraintKind::KeyPath:
1339-
case ConstraintKind::FunctionInput:
1340-
case ConstraintKind::FunctionResult:
13411339
case ConstraintKind::ClosureBodyElement:
13421340
case ConstraintKind::Conjunction:
13431341
// Constraints from which we can't do anything.

lib/Sema/CSGen.cpp

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,8 +1214,14 @@ namespace {
12141214
auto *memberLoc =
12151215
CS.getConstraintLocator(expr, ConstraintLocator::ConstructorMember);
12161216

1217+
auto *fnLoc =
1218+
CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction);
1219+
1220+
auto *memberTypeLoc = CS.getConstraintLocator(
1221+
fnLoc, LocatorPathElt::ConstructorMemberType());
1222+
12171223
auto *memberType =
1218-
CS.createTypeVariable(memberLoc, TVO_CanBindToNoEscape);
1224+
CS.createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape);
12191225

12201226
CS.addValueMemberConstraint(MetatypeType::get(witnessType, ctx),
12211227
DeclNameRef(constrName), memberType, CurDC,
@@ -1228,10 +1234,9 @@ namespace {
12281234
CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult),
12291235
TVO_CanBindToNoEscape);
12301236

1231-
CS.addConstraint(
1232-
ConstraintKind::ApplicableFunction,
1233-
FunctionType::get(params, resultType), memberType,
1234-
CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction));
1237+
CS.addConstraint(ConstraintKind::ApplicableFunction,
1238+
FunctionType::get(params, resultType), memberType,
1239+
fnLoc);
12351240

12361241
if (constr->isFailable())
12371242
return OptionalType::get(witnessType);
@@ -1500,25 +1505,12 @@ namespace {
15001505
// self.super = Super.init()
15011506
baseTy = MetatypeType::get(baseTy, ctx);
15021507

1503-
auto methodTy = CS.createTypeVariable(
1504-
CS.getConstraintLocator(expr,
1505-
ConstraintLocator::ApplyFunction),
1506-
TVO_CanBindToNoEscape);
1507-
1508-
// FIXME: Once TVO_PrefersSubtypeBinding is replaced with something
1509-
// better, we won't need the second type variable at all.
1510-
{
1511-
auto argTy = CS.createTypeVariable(
1512-
CS.getConstraintLocator(expr,
1513-
ConstraintLocator::ApplyArgument),
1514-
(TVO_CanBindToLValue |
1515-
TVO_CanBindToInOut |
1516-
TVO_CanBindToNoEscape |
1517-
TVO_PrefersSubtypeBinding));
1518-
CS.addConstraint(
1519-
ConstraintKind::FunctionInput, methodTy, argTy,
1520-
CS.getConstraintLocator(expr));
1521-
}
1508+
auto memberTypeLoc = CS.getConstraintLocator(
1509+
expr, LocatorPathElt::ConstructorMemberType(
1510+
/*shortFormOrSelfDelegating*/ true));
1511+
1512+
auto methodTy =
1513+
CS.createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape);
15221514

15231515
CS.addValueMemberConstraint(
15241516
baseTy, expr->getName(), methodTy, CurDC,

lib/Sema/CSRanking.cpp

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,40 @@ static void addKeyPathDynamicMemberOverloads(
766766
}
767767
}
768768

769+
/// Given the bound types of two constructor overloads, returns their parameter
770+
/// list types as tuples to compare for solution ranking, or \c None if they
771+
/// shouldn't be compared.
772+
static Optional<std::pair<Type, Type>>
773+
getConstructorParamsAsTuples(ASTContext &ctx, Type boundTy1, Type boundTy2) {
774+
auto choiceTy1 =
775+
boundTy1->lookThroughAllOptionalTypes()->getAs<FunctionType>();
776+
auto choiceTy2 =
777+
boundTy2->lookThroughAllOptionalTypes()->getAs<FunctionType>();
778+
779+
// If the type variables haven't been bound to functions yet, let's not try
780+
// and rank them.
781+
if (!choiceTy1 || !choiceTy2)
782+
return None;
783+
784+
auto initParams1 = choiceTy1->getParams();
785+
auto initParams2 = choiceTy2->getParams();
786+
if (initParams1.size() != initParams2.size())
787+
return None;
788+
789+
// Don't compare if there are variadic differences. This preserves the
790+
// behavior of when we'd compare through matchTupleTypes with the parameter
791+
// flags intact.
792+
for (auto idx : indices(initParams1)) {
793+
if (initParams1[idx].isVariadic() != initParams2[idx].isVariadic())
794+
return None;
795+
}
796+
auto tuple1 = AnyFunctionType::composeTuple(ctx, initParams1,
797+
/*wantParamFlags*/ false);
798+
auto tuple2 = AnyFunctionType::composeTuple(ctx, initParams2,
799+
/*wantParamFlags*/ false);
800+
return std::make_pair(tuple1, tuple2);
801+
}
802+
769803
SolutionCompareResult ConstraintSystem::compareSolutions(
770804
ConstraintSystem &cs, ArrayRef<Solution> solutions,
771805
const SolutionDiff &diff, unsigned idx1, unsigned idx2) {
@@ -1127,11 +1161,23 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
11271161

11281162
for (const auto &binding1 : bindings1) {
11291163
auto *typeVar = binding1.first;
1164+
auto *loc = typeVar->getImpl().getLocator();
1165+
1166+
// Check whether this is the overload type for a short-form init call
1167+
// 'X(...)' or 'self.init(...)' call.
1168+
auto isShortFormOrSelfDelegatingConstructorBinding = false;
1169+
if (auto initMemberTypeElt =
1170+
loc->getLastElementAs<LocatorPathElt::ConstructorMemberType>()) {
1171+
isShortFormOrSelfDelegatingConstructorBinding =
1172+
initMemberTypeElt->isShortFormOrSelfDelegatingConstructor();
1173+
}
11301174

11311175
// If the type variable isn't one for which we should be looking at the
11321176
// bindings, don't.
1133-
if (!typeVar->getImpl().prefersSubtypeBinding())
1177+
if (!typeVar->getImpl().prefersSubtypeBinding() &&
1178+
!isShortFormOrSelfDelegatingConstructorBinding) {
11341179
continue;
1180+
}
11351181

11361182
// If both solutions have a binding for this type variable
11371183
// let's consider it.
@@ -1142,9 +1188,24 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
11421188
auto concreteType1 = binding1.second;
11431189
auto concreteType2 = binding2->second;
11441190

1145-
if (!concreteType1->isEqual(concreteType2)) {
1146-
typeDiff.insert({typeVar, {concreteType1, concreteType2}});
1191+
// For short-form and self-delegating init calls, we want to prefer
1192+
// parameter lists with subtypes over supertypes. To do this, compose tuples
1193+
// for the bound parameter lists, and compare them in the type diff. This
1194+
// logic preserves the behavior of when we used to bind the parameter list
1195+
// as a tuple to a TVO_PrefersSubtypeBinding type variable for such calls.
1196+
// FIXME: We should come up with a better way of doing this, though note we
1197+
// have some ranking and subtyping rules specific to tuples that we may need
1198+
// to preserve to avoid breaking source.
1199+
if (isShortFormOrSelfDelegatingConstructorBinding) {
1200+
auto diffs = getConstructorParamsAsTuples(cs.getASTContext(),
1201+
concreteType1, concreteType2);
1202+
if (!diffs)
1203+
continue;
1204+
std::tie(concreteType1, concreteType2) = *diffs;
11471205
}
1206+
1207+
if (!concreteType1->isEqual(concreteType2))
1208+
typeDiff.insert({typeVar, {concreteType1, concreteType2}});
11481209
}
11491210

11501211
for (auto &binding : typeDiff) {

0 commit comments

Comments
 (0)