Skip to content

Commit 306a857

Browse files
committed
[ConstraintSystem] Add same-shape constraint
The constraint takes two pack types and makes sure that their reduced shapes are equal. This helps with diagnostics because constraint has access to the original pack expansion pattern types. (cherry picked from commit bbe305c)
1 parent 22d8e1a commit 306a857

File tree

8 files changed

+100
-17
lines changed

8 files changed

+100
-17
lines changed

include/swift/Sema/Constraint.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ enum class ConstraintKind : char {
233233
/// an overload. The second type is a PackType containing the explicit
234234
/// generic arguments.
235235
ExplicitGenericArguments,
236+
/// Both (first and second) pack types should have the same reduced shape.
237+
SameShape,
236238
};
237239

238240
/// Classification of the different kinds of constraints.
@@ -701,6 +703,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
701703
case ConstraintKind::DefaultClosureType:
702704
case ConstraintKind::UnresolvedMemberChainBase:
703705
case ConstraintKind::PackElementOf:
706+
case ConstraintKind::SameShape:
704707
return ConstraintClassification::Relational;
705708

706709
case ConstraintKind::ValueMember:

include/swift/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4864,6 +4864,12 @@ class ConstraintSystem {
48644864
Type type1, Type type2, TypeMatchOptions flags,
48654865
ConstraintLocatorBuilder locator);
48664866

4867+
/// Simplify a same-shape constraint by comparing the reduced shape of the
4868+
/// left hand side to the right hand side.
4869+
SolutionKind simplifySameShapeConstraint(Type type1, Type type2,
4870+
TypeMatchOptions flags,
4871+
ConstraintLocatorBuilder locator);
4872+
48674873
public: // FIXME: Public for use by static functions.
48684874
/// Simplify a conversion constraint with a fix applied to it.
48694875
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
@@ -1480,6 +1480,7 @@ void PotentialBindings::infer(Constraint *constraint) {
14801480
case ConstraintKind::ShapeOf:
14811481
case ConstraintKind::ExplicitGenericArguments:
14821482
case ConstraintKind::PackElementOf:
1483+
case ConstraintKind::SameShape:
14831484
// Constraints from which we can't do anything.
14841485
break;
14851486

lib/Sema/CSSimplify.cpp

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
22732273
case ConstraintKind::PackElementOf:
22742274
case ConstraintKind::ShapeOf:
22752275
case ConstraintKind::ExplicitGenericArguments:
2276+
case ConstraintKind::SameShape:
22762277
llvm_unreachable("Bad constraint kind in matchTupleTypes()");
22772278
}
22782279

@@ -2486,13 +2487,9 @@ ConstraintSystem::matchPackExpansionTypes(PackExpansionType *expansion1,
24862487
ConstraintKind kind, TypeMatchOptions flags,
24872488
ConstraintLocatorBuilder locator) {
24882489
// The count types of two pack expansion types must have the same shape.
2489-
auto *shapeLoc = getConstraintLocator(
2490-
locator.withPathElement(ConstraintLocator::PackShape));
2491-
auto *shapeTypeVar = createTypeVariable(shapeLoc, TVO_CanBindToPack);
2492-
addConstraint(ConstraintKind::ShapeOf,
2493-
expansion1->getCountType(), shapeTypeVar, shapeLoc);
2494-
addConstraint(ConstraintKind::ShapeOf,
2495-
expansion2->getCountType(), shapeTypeVar, shapeLoc);
2490+
addConstraint(ConstraintKind::SameShape, expansion1->getCountType(),
2491+
expansion2->getCountType(),
2492+
locator.withPathElement(ConstraintLocator::PackShape));
24962493

24972494
auto pattern1 = expansion1->getPatternType();
24982495
auto pattern2 = expansion2->getPatternType();
@@ -2652,6 +2649,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
26522649
case ConstraintKind::PackElementOf:
26532650
case ConstraintKind::ShapeOf:
26542651
case ConstraintKind::ExplicitGenericArguments:
2652+
case ConstraintKind::SameShape:
26552653
return true;
26562654
}
26572655

@@ -3159,6 +3157,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
31593157
case ConstraintKind::PackElementOf:
31603158
case ConstraintKind::ShapeOf:
31613159
case ConstraintKind::ExplicitGenericArguments:
3160+
case ConstraintKind::SameShape:
31623161
llvm_unreachable("Not a relational constraint");
31633162
}
31643163

@@ -6819,6 +6818,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
68196818
case ConstraintKind::PackElementOf:
68206819
case ConstraintKind::ShapeOf:
68216820
case ConstraintKind::ExplicitGenericArguments:
6821+
case ConstraintKind::SameShape:
68226822
llvm_unreachable("Not a relational constraint");
68236823
}
68246824
}
@@ -13195,6 +13195,18 @@ ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint(
1319513195
return SolutionKind::Solved;
1319613196
}
1319713197

13198+
static bool hasUnresolvedPackVars(Type type) {
13199+
// We can't compute a reduced shape if the input type still
13200+
// contains type variables that might bind to pack archetypes
13201+
// or pack expansions.
13202+
SmallPtrSet<TypeVariableType *, 2> typeVars;
13203+
type->getTypeVariables(typeVars);
13204+
return llvm::any_of(typeVars, [](const TypeVariableType *typeVar) {
13205+
return typeVar->getImpl().canBindToPack() ||
13206+
typeVar->getImpl().isPackExpansion();
13207+
});
13208+
}
13209+
1319813210
ConstraintSystem::SolutionKind ConstraintSystem::simplifyShapeOfConstraint(
1319913211
Type type1, Type type2, TypeMatchOptions flags,
1320013212
ConstraintLocatorBuilder locator) {
@@ -13236,6 +13248,51 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyShapeOfConstraint(
1323613248
return SolutionKind::Solved;
1323713249
}
1323813250

13251+
ConstraintSystem::SolutionKind ConstraintSystem::simplifySameShapeConstraint(
13252+
Type type1, Type type2, TypeMatchOptions flags,
13253+
ConstraintLocatorBuilder locator) {
13254+
type1 = simplifyType(type1);
13255+
type2 = simplifyType(type2);
13256+
13257+
auto formUnsolved = [&]() {
13258+
// If we're supposed to generate constraints, do so.
13259+
if (flags.contains(TMF_GenerateConstraints)) {
13260+
auto *sameShape =
13261+
Constraint::create(*this, ConstraintKind::SameShape, type1, type2,
13262+
getConstraintLocator(locator));
13263+
13264+
addUnsolvedConstraint(sameShape);
13265+
return SolutionKind::Solved;
13266+
}
13267+
13268+
return SolutionKind::Unsolved;
13269+
};
13270+
13271+
if (hasUnresolvedPackVars(type1) || hasUnresolvedPackVars(type2))
13272+
return formUnsolved();
13273+
13274+
auto shape1 = type1->getReducedShape();
13275+
auto shape2 = type2->getReducedShape();
13276+
13277+
if (shape1->isEqual(shape2))
13278+
return SolutionKind::Solved;
13279+
13280+
if (shouldAttemptFixes()) {
13281+
if (type1->hasPlaceholder() || type2->hasPlaceholder())
13282+
return SolutionKind::Solved;
13283+
13284+
unsigned impact = 1;
13285+
if (locator.endsWith<LocatorPathElt::AnyRequirement>())
13286+
impact = assessRequirementFailureImpact(*this, shape1, locator);
13287+
13288+
auto *fix = SkipSameShapeRequirement::create(*this, type1, type2,
13289+
getConstraintLocator(locator));
13290+
return recordFix(fix, impact) ? SolutionKind::Error : SolutionKind::Solved;
13291+
}
13292+
13293+
return SolutionKind::Error;
13294+
}
13295+
1323913296
ConstraintSystem::SolutionKind
1324013297
ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1324113298
Type type1, Type type2, TypeMatchOptions flags,
@@ -14707,6 +14764,9 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
1470714764
case ConstraintKind::ShapeOf:
1470814765
return simplifyShapeOfConstraint(first, second, subflags, locator);
1470914766

14767+
case ConstraintKind::SameShape:
14768+
return simplifySameShapeConstraint(first, second, subflags, locator);
14769+
1471014770
case ConstraintKind::ExplicitGenericArguments:
1471114771
return simplifyExplicitGenericArgumentsConstraint(
1471214772
first, second, subflags, locator);
@@ -14878,13 +14938,7 @@ void ConstraintSystem::addConstraint(Requirement req,
1487814938
auto type1 = req.getFirstType();
1487914939
auto type2 = req.getSecondType();
1488014940

14881-
auto *shapeLoc = getConstraintLocator(
14882-
locator.withPathElement(ConstraintLocator::PackShape));
14883-
auto typeVar = createTypeVariable(shapeLoc,
14884-
TVO_CanBindToPack);
14885-
14886-
addConstraint(ConstraintKind::ShapeOf, type1, typeVar, locator);
14887-
addConstraint(ConstraintKind::ShapeOf, type2, typeVar, locator);
14941+
addConstraint(ConstraintKind::SameShape, type1, type2, locator);
1488814942
return;
1488914943
}
1489014944

@@ -15308,6 +15362,11 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1530815362
constraint.getFirstType(), constraint.getSecondType(), /*flags*/ None,
1530915363
constraint.getLocator());
1531015364

15365+
case ConstraintKind::SameShape:
15366+
return simplifySameShapeConstraint(constraint.getFirstType(),
15367+
constraint.getSecondType(),
15368+
/*flags*/ None, constraint.getLocator());
15369+
1531115370
case ConstraintKind::ExplicitGenericArguments:
1531215371
return simplifyExplicitGenericArgumentsConstraint(
1531315372
constraint.getFirstType(), constraint.getSecondType(),

lib/Sema/Constraint.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
8282
case ConstraintKind::PackElementOf:
8383
case ConstraintKind::ShapeOf:
8484
case ConstraintKind::ExplicitGenericArguments:
85+
case ConstraintKind::SameShape:
8586
assert(!First.isNull());
8687
assert(!Second.isNull());
8788
break;
@@ -171,6 +172,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
171172
case ConstraintKind::PackElementOf:
172173
case ConstraintKind::ShapeOf:
173174
case ConstraintKind::ExplicitGenericArguments:
175+
case ConstraintKind::SameShape:
174176
llvm_unreachable("Wrong constructor");
175177

176178
case ConstraintKind::KeyPath:
@@ -319,6 +321,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
319321
case ConstraintKind::PackElementOf:
320322
case ConstraintKind::ShapeOf:
321323
case ConstraintKind::ExplicitGenericArguments:
324+
case ConstraintKind::SameShape:
322325
return create(cs, getKind(), getFirstType(), getSecondType(), getLocator());
323326

324327
case ConstraintKind::ApplicableFunction:
@@ -569,6 +572,10 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm,
569572
Out << " shape of ";
570573
break;
571574

575+
case ConstraintKind::SameShape:
576+
Out << " same-shape ";
577+
break;
578+
572579
case ConstraintKind::ExplicitGenericArguments:
573580
Out << " explicit generic argument binding ";
574581
break;
@@ -742,6 +749,7 @@ gatherReferencedTypeVars(Constraint *constraint,
742749
case ConstraintKind::PackElementOf:
743750
case ConstraintKind::ShapeOf:
744751
case ConstraintKind::ExplicitGenericArguments:
752+
case ConstraintKind::SameShape:
745753
constraint->getFirstType()->getTypeVariables(typeVars);
746754
constraint->getSecondType()->getTypeVariables(typeVars);
747755
break;

test/Constraints/pack-expansion-expressions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func tupleExpansion<each T, each U>(
133133
_ = zip(repeat each tuple1.element, with: repeat each tuple1.element)
134134

135135
_ = zip(repeat each tuple1.element, with: repeat each tuple2.element)
136-
// expected-error@-1 {{global function 'zip(_:with:)' requires the type packs 'each U' and 'each T' have the same shape}}
136+
// expected-error@-1 {{global function 'zip(_:with:)' requires the type packs 'each T' and 'each U' have the same shape}}
137137
}
138138

139139
protocol Generatable {

test/Constraints/variadic_generic_constraints.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,5 @@ func goodCallToZip<each T, each U>(t: repeat each T, u: repeat each U) where (re
7373

7474
func badCallToZip<each T, each U>(t: repeat each T, u: repeat each U) {
7575
_ = zip(t: repeat each t, u: repeat each u)
76-
// expected-error@-1 {{global function 'zip(t:u:)' requires the type packs 'each U' and 'each T' have the same shape}}
76+
// expected-error@-1 {{global function 'zip(t:u:)' requires the type packs 'each T' and 'each U' have the same shape}}
7777
}

test/Constraints/variadic_generic_functions.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,15 @@ func call() {
3232

3333
let x: String = multipleParameters(xs: "", ys: "")
3434
let (one, two) = multipleParameters(xs: "", 5.0, ys: "", 5.0)
35-
multipleParameters(xs: "", 5.0, ys: 5.0, "") // expected-error {{type of expression is ambiguous without more context}}
35+
multipleParameters(xs: "", 5.0, ys: 5.0, "") // expected-error {{conflicting arguments to generic parameter 'each T' ('Pack{Double, String}' vs. 'Pack{String, String}' vs. 'Pack{String, Double}' vs. 'Pack{Double, Double}')}}
3636

3737
func multipleSequences<each T, each U>(xs: repeat each T, ys: repeat each U) -> (repeat each T) {
38+
return (repeat each ys)
39+
// expected-error@-1 {{pack expansion requires that 'each U' and 'each T' have the same shape}}
40+
// expected-error@-2 {{cannot convert return expression of type '(repeat each U)' to return type '(repeat each T)'}}
41+
}
42+
43+
func multipleSequencesWithSameShape<each T, each U>(xs: repeat each T, ys: repeat each U) -> (repeat each T) where (repeat (each T, each U)): Any {
3844
return (repeat each ys)
3945
// expected-error@-1 {{cannot convert return expression of type '(repeat each U)' to return type '(repeat each T)'}}
4046
}

0 commit comments

Comments
 (0)