Skip to content

Commit 2d926c5

Browse files
authored
Merge pull request #61710 from slavapestov/shape-of-constraint
Sema: Instantiate constraints for RequirementKind::SameShape
2 parents c3f15cb + bb04542 commit 2d926c5

13 files changed

+242
-20
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,6 +2104,9 @@ NOTE(type_does_not_inherit_or_conform_requirement,none,
21042104
ERROR(types_not_equal,none,
21052105
"%0 requires the types %1 and %2 be equivalent",
21062106
(Type, Type, Type))
2107+
ERROR(types_not_same_shape,none,
2108+
"%0 requires the type packs %1 and %2 have the same shape",
2109+
(Type, Type, Type))
21072110
ERROR(type_does_not_conform_owner,none,
21082111
"%0 requires that %1 conform to %2", (Type, Type, Type))
21092112
ERROR(type_does_not_conform_in_decl_ref,none,
@@ -2133,6 +2136,12 @@ ERROR(types_not_equal_decl,none,
21332136
ERROR(types_not_equal_in_decl_ref,none,
21342137
"referencing %0 %1 on %2 requires the types %3 and %4 be equivalent",
21352138
(DescriptiveDeclKind, DeclName, Type, Type, Type))
2139+
ERROR(types_not_same_shape_decl,none,
2140+
"%0 %1 requires the type packs %2 and %3 have the same shape",
2141+
(DescriptiveDeclKind, DeclName, Type, Type))
2142+
ERROR(types_not_same_shape_in_decl_ref,none,
2143+
"referencing %0 %1 on %2 requires the type packs %3 and %4 have the same shape",
2144+
(DescriptiveDeclKind, DeclName, Type, Type, Type))
21362145
ERROR(types_not_inherited_decl,none,
21372146
"%0 %1 requires that %2 inherit from %3",
21382147
(DescriptiveDeclKind, DeclName, Type, Type))
@@ -2155,6 +2164,10 @@ NOTE(candidate_types_equal_requirement,none,
21552164
"candidate requires that the types %0 and %1 be equivalent "
21562165
"(requirement specified as %2 == %3)",
21572166
(Type, Type, Type, Type))
2167+
NOTE(candidate_types_same_shape_requirement,none,
2168+
"candidate requires that the type packs %0 and %1 have the same shape "
2169+
"(requirement specified as %2.shape == %3.shape)",
2170+
(Type, Type, Type, Type))
21582171
NOTE(candidate_types_inheritance_requirement,none,
21592172
"candidate requires that %1 inherit from %2 "
21602173
"(requirement specified as %2 : %3)",

include/swift/Sema/CSFix.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ enum class FixKind : uint8_t {
9393
/// and assume that types are equal.
9494
SkipSameTypeRequirement,
9595

96+
/// Skip same-shape generic requirement constraint,
97+
/// and assume that pack types have the same shape.
98+
SkipSameShapeRequirement,
99+
96100
/// Skip superclass generic requirement constraint,
97101
/// and assume that types are related.
98102
SkipSuperclassRequirement,
@@ -655,6 +659,34 @@ class SkipSameTypeRequirement final : public ConstraintFix {
655659
}
656660
};
657661

662+
/// Skip same-shape generic requirement constraint,
663+
/// and assume that types are equal.
664+
class SkipSameShapeRequirement final : public ConstraintFix {
665+
Type LHS, RHS;
666+
667+
SkipSameShapeRequirement(ConstraintSystem &cs, Type lhs, Type rhs,
668+
ConstraintLocator *locator)
669+
: ConstraintFix(cs, FixKind::SkipSameShapeRequirement, locator), LHS(lhs),
670+
RHS(rhs) {}
671+
672+
public:
673+
std::string getName() const override {
674+
return "skip same-shape generic requirement";
675+
}
676+
677+
bool diagnose(const Solution &solution, bool asNote = false) const override;
678+
679+
Type lhsType() { return LHS; }
680+
Type rhsType() { return RHS; }
681+
682+
static SkipSameShapeRequirement *create(ConstraintSystem &cs, Type lhs,
683+
Type rhs, ConstraintLocator *locator);
684+
685+
static bool classof(ConstraintFix *fix) {
686+
return fix->getKind() == FixKind::SkipSameTypeRequirement;
687+
}
688+
};
689+
658690
/// Skip 'superclass' generic requirement constraint,
659691
/// and assume that types are equal.
660692
class SkipSuperclassRequirement final : public ConstraintFix {

include/swift/Sema/Constraint.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ enum class ConstraintKind : char {
223223
///
224224
/// Binds the RHS type to a tuple of the params of a function typed LHS. Note
225225
/// this discards function parameter flags.
226-
BindTupleOfFunctionParams
226+
BindTupleOfFunctionParams,
227+
/// The first type is a type pack, and the second type is its reduced shape.
228+
ShapeOf,
227229
};
228230

229231
/// Classification of the different kinds of constraints.
@@ -705,6 +707,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
705707
case ConstraintKind::KeyPathApplication:
706708
case ConstraintKind::Defaultable:
707709
case ConstraintKind::BindTupleOfFunctionParams:
710+
case ConstraintKind::ShapeOf:
708711
return ConstraintClassification::TypeProperty;
709712

710713
case ConstraintKind::Disjunction:

include/swift/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5613,6 +5613,12 @@ class ConstraintSystem {
56135613
ASTNode element, ContextualTypeInfo context, bool isDiscarded,
56145614
TypeMatchOptions flags, ConstraintLocatorBuilder locator);
56155615

5616+
/// Simplify a shape constraint by binding the reduced shape of the
5617+
/// left hand side to the right hand side.
5618+
SolutionKind simplifyShapeOfConstraint(
5619+
Type type1, Type type2, TypeMatchOptions flags,
5620+
ConstraintLocatorBuilder locator);
5621+
56165622
public: // FIXME: Public for use by static functions.
56175623
/// Simplify a conversion constraint with a fix applied to it.
56185624
SolutionKind simplifyFixConstraint(ConstraintFix *fix, Type type1, Type type2,

lib/Sema/CSBindings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,7 @@ void PotentialBindings::infer(Constraint *constraint) {
13971397
case ConstraintKind::Conjunction:
13981398
case ConstraintKind::BindTupleOfFunctionParams:
13991399
case ConstraintKind::PackElementOf:
1400+
case ConstraintKind::ShapeOf:
14001401
// Constraints from which we can't do anything.
14011402
break;
14021403

lib/Sema/CSDiagnostics.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7059,7 +7059,6 @@ bool ExtraneousCallFailure::diagnoseAsError() {
70597059
}
70607060
}
70617061

7062-
anchor.dump();
70637062
auto diagnostic =
70647063
emitDiagnostic(diag::cannot_call_non_function_value, getType(anchor));
70657064
removeParensFixIt(diagnostic);

lib/Sema/CSDiagnostics.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,40 @@ class SameTypeRequirementFailure final : public RequirementFailure {
435435
}
436436
};
437437

438+
/// Diagnose failures related to same-shape generic requirements, e.g.
439+
/// ```swift
440+
/// func foo<T..., U...>(t: T..., u: U...) -> (T, U)... {}
441+
/// func bar<T..., U...>(t: T..., u: U...) {
442+
/// foo(t: t..., u: u...)
443+
/// }
444+
/// ```
445+
///
446+
/// `S.T` is not the same type as `Int`, which is required by `foo`.
447+
class SameShapeRequirementFailure final : public RequirementFailure {
448+
public:
449+
SameShapeRequirementFailure(const Solution &solution, Type lhs, Type rhs,
450+
ConstraintLocator *locator)
451+
: RequirementFailure(solution, lhs, rhs, locator) {
452+
#ifndef NDEBUG
453+
auto reqElt = locator->castLastElementTo<LocatorPathElt::AnyRequirement>();
454+
assert(reqElt.getRequirementKind() == RequirementKind::SameShape);
455+
#endif
456+
}
457+
458+
protected:
459+
DiagOnDecl getDiagnosticOnDecl() const override {
460+
return diag::types_not_same_shape_decl;
461+
}
462+
463+
DiagInReference getDiagnosticInRereference() const override {
464+
return diag::types_not_same_shape_in_decl_ref;
465+
}
466+
467+
DiagAsNote getDiagnosticAsNote() const override {
468+
return diag::candidate_types_same_shape_requirement;
469+
}
470+
};
471+
438472
/// Diagnose failures related to superclass generic requirements, e.g.
439473
/// ```swift
440474
/// class A {

lib/Sema/CSFix.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,18 @@ SkipSameTypeRequirement::create(ConstraintSystem &cs, Type lhs, Type rhs,
465465
return new (cs.getAllocator()) SkipSameTypeRequirement(cs, lhs, rhs, locator);
466466
}
467467

468+
bool SkipSameShapeRequirement::diagnose(const Solution &solution,
469+
bool asNote) const {
470+
SameShapeRequirementFailure failure(solution, LHS, RHS, getLocator());
471+
return failure.diagnose(asNote);
472+
}
473+
474+
SkipSameShapeRequirement *
475+
SkipSameShapeRequirement::create(ConstraintSystem &cs, Type lhs, Type rhs,
476+
ConstraintLocator *locator) {
477+
return new (cs.getAllocator()) SkipSameShapeRequirement(cs, lhs, rhs, locator);
478+
}
479+
468480
bool SkipSuperclassRequirement::diagnose(const Solution &solution,
469481
bool asNote) const {
470482
SuperclassRequirementFailure failure(solution, LHS, RHS, getLocator());

lib/Sema/CSSimplify.cpp

Lines changed: 101 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2425,6 +2425,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
24252425
case ConstraintKind::SyntacticElement:
24262426
case ConstraintKind::BindTupleOfFunctionParams:
24272427
case ConstraintKind::PackElementOf:
2428+
case ConstraintKind::ShapeOf:
24282429
llvm_unreachable("Bad constraint kind in matchTupleTypes()");
24292430
}
24302431

@@ -2597,6 +2598,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
25972598
case ConstraintKind::SyntacticElement:
25982599
case ConstraintKind::BindTupleOfFunctionParams:
25992600
case ConstraintKind::PackElementOf:
2601+
case ConstraintKind::ShapeOf:
26002602
return true;
26012603
}
26022604

@@ -3013,6 +3015,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
30133015
case ConstraintKind::SyntacticElement:
30143016
case ConstraintKind::BindTupleOfFunctionParams:
30153017
case ConstraintKind::PackElementOf:
3018+
case ConstraintKind::ShapeOf:
30163019
llvm_unreachable("Not a relational constraint");
30173020
}
30183021

@@ -4219,16 +4222,14 @@ static ConstraintFix *fixRequirementFailure(ConstraintSystem &cs, Type type1,
42194222
auto *reqLoc = cs.getConstraintLocator(anchor, path);
42204223

42214224
switch (req.getRequirementKind()) {
4222-
case RequirementKind::SameShape:
4223-
llvm_unreachable("Same-shape requirement not supported here");
4224-
4225-
case RequirementKind::SameType: {
4225+
case RequirementKind::SameType:
42264226
return SkipSameTypeRequirement::create(cs, type1, type2, reqLoc);
4227-
}
42284227

4229-
case RequirementKind::Superclass: {
4228+
case RequirementKind::SameShape:
4229+
return SkipSameShapeRequirement::create(cs, type1, type2, reqLoc);
4230+
4231+
case RequirementKind::Superclass:
42304232
return SkipSuperclassRequirement::create(cs, type1, type2, reqLoc);
4231-
}
42324233

42334234
case RequirementKind::Layout:
42344235
case RequirementKind::Conformance:
@@ -6366,6 +6367,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
63666367
case ConstraintKind::SyntacticElement:
63676368
case ConstraintKind::BindTupleOfFunctionParams:
63686369
case ConstraintKind::PackElementOf:
6370+
case ConstraintKind::ShapeOf:
63696371
llvm_unreachable("Not a relational constraint");
63706372
}
63716373
}
@@ -7442,17 +7444,14 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifySubclassOfConstraint(
74427444
return SolutionKind::Solved;
74437445
}
74447446

7445-
auto formUnsolved = [&](bool activate = false) {
7447+
auto formUnsolved = [&]() {
74467448
// If we're supposed to generate constraints, do so.
74477449
if (flags.contains(TMF_GenerateConstraints)) {
7448-
auto *conformance = Constraint::create(
7450+
auto *subclassOf = Constraint::create(
74497451
*this, ConstraintKind::SubclassOf, type, classType,
74507452
getConstraintLocator(locator));
74517453

7452-
addUnsolvedConstraint(conformance);
7453-
if (activate)
7454-
activateConstraint(conformance);
7455-
7454+
addUnsolvedConstraint(subclassOf);
74567455
return SolutionKind::Solved;
74577456
}
74587457

@@ -12510,6 +12509,74 @@ ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint(
1251012509
return SolutionKind::Solved;
1251112510
}
1251212511

12512+
static Type getReducedShape(Type type) {
12513+
// Pack archetypes know their reduced shape
12514+
if (auto *packArchetype = type->getAs<PackArchetypeType>())
12515+
return packArchetype->getShape();
12516+
12517+
// Reduced shape of pack is computed recursively
12518+
if (auto *packType = type->getAs<PackType>()) {
12519+
auto &ctx = type->getASTContext();
12520+
SmallVector<Type, 2> elts;
12521+
12522+
for (auto elt : packType->getElementTypes()) {
12523+
// T... => shape(T)...
12524+
if (auto *packExpansionType = elt->getAs<PackExpansionType>()) {
12525+
auto shapeType = getReducedShape(packExpansionType->getCountType());
12526+
assert(shapeType && "Should not end up here if pack type's shape "
12527+
"is still potentially unknown");
12528+
elts.push_back(PackExpansionType::get(shapeType, shapeType));
12529+
}
12530+
12531+
// Use () as a placeholder for scalar shape
12532+
elts.push_back(ctx.TheEmptyTupleType);
12533+
}
12534+
12535+
return PackType::get(ctx, elts);
12536+
}
12537+
12538+
// Getting the shape of any other type is an error.
12539+
return Type();
12540+
}
12541+
12542+
ConstraintSystem::SolutionKind ConstraintSystem::simplifyShapeOfConstraint(
12543+
Type type1, Type type2, TypeMatchOptions flags,
12544+
ConstraintLocatorBuilder locator) {
12545+
// Recursively replace all type variables with fixed bindings if
12546+
// possible.
12547+
type1 = simplifyType(type1, flags);
12548+
12549+
auto formUnsolved = [&]() {
12550+
// If we're supposed to generate constraints, do so.
12551+
if (flags.contains(TMF_GenerateConstraints)) {
12552+
auto *shapeOf = Constraint::create(
12553+
*this, ConstraintKind::ShapeOf, type1, type2,
12554+
getConstraintLocator(locator));
12555+
12556+
addUnsolvedConstraint(shapeOf);
12557+
return SolutionKind::Solved;
12558+
}
12559+
12560+
return SolutionKind::Unsolved;
12561+
};
12562+
12563+
// We can't compute a reduced shape if the input type still
12564+
// contains type variables that might bind to pack archetypes.
12565+
SmallPtrSet<TypeVariableType *, 2> typeVars;
12566+
type1->getTypeVariables(typeVars);
12567+
for (auto *typeVar : typeVars) {
12568+
if (typeVar->getImpl().canBindToPack())
12569+
return formUnsolved();
12570+
}
12571+
12572+
if (Type shape = getReducedShape(type1)) {
12573+
addConstraint(ConstraintKind::Bind, shape, type2, locator);
12574+
return SolutionKind::Solved;
12575+
}
12576+
12577+
return SolutionKind::Error;
12578+
}
12579+
1251312580
static llvm::PointerIntPair<Type, 3, unsigned>
1251412581
getBaseTypeForPointer(TypeBase *type) {
1251512582
unsigned unwrapCount = 0;
@@ -13573,6 +13640,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1357313640

1357413641
case FixKind::AddConformance:
1357513642
case FixKind::SkipSameTypeRequirement:
13643+
case FixKind::SkipSameShapeRequirement:
1357613644
case FixKind::SkipSuperclassRequirement: {
1357713645
return recordFix(fix, assessRequirementFailureImpact(*this, type1,
1357813646
fix->getLocator()))
@@ -13847,6 +13915,9 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
1384713915
case ConstraintKind::PackElementOf:
1384813916
return simplifyPackElementOfConstraint(first, second, subflags, locator);
1384913917

13918+
case ConstraintKind::ShapeOf:
13919+
return simplifyShapeOfConstraint(first, second, subflags, locator);
13920+
1385013921
case ConstraintKind::ValueMember:
1385113922
case ConstraintKind::UnresolvedValueMember:
1385213923
case ConstraintKind::ValueWitness:
@@ -14010,8 +14081,18 @@ void ConstraintSystem::addConstraint(Requirement req,
1401014081
bool conformsToAnyObject = false;
1401114082
Optional<ConstraintKind> kind;
1401214083
switch (req.getKind()) {
14013-
case RequirementKind::SameShape:
14014-
llvm_unreachable("Same-shape requirement not supported here");
14084+
case RequirementKind::SameShape: {
14085+
auto type1 = req.getFirstType();
14086+
auto type2 = req.getSecondType();
14087+
14088+
// FIXME: Locator for diagnostics
14089+
auto typeVar = createTypeVariable(getConstraintLocator(locator),
14090+
TVO_CanBindToPack);
14091+
14092+
addConstraint(ConstraintKind::ShapeOf, type1, typeVar, locator);
14093+
addConstraint(ConstraintKind::ShapeOf, type2, typeVar, locator);
14094+
return;
14095+
}
1401514096

1401614097
case RequirementKind::Conformance:
1401714098
kind = ConstraintKind::ConformsTo;
@@ -14421,6 +14502,11 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1442114502
return simplifyPackElementOfConstraint(
1442214503
constraint.getFirstType(), constraint.getSecondType(), /*flags*/None,
1442314504
constraint.getLocator());
14505+
14506+
case ConstraintKind::ShapeOf:
14507+
return simplifyShapeOfConstraint(
14508+
constraint.getFirstType(), constraint.getSecondType(), /*flags*/ None,
14509+
constraint.getLocator());
1442414510
}
1442514511

1442614512
llvm_unreachable("Unhandled ConstraintKind in switch.");

0 commit comments

Comments
 (0)