Skip to content

Commit e3d1317

Browse files
committed
[ConstraintSystem] Detect and diagnose missing each for value pack reference
Detect that a value pack is missing 'each' keyword during constraint generation and fix-it by injecting `PackElementExpr`.
1 parent eee7e18 commit e3d1317

File tree

3 files changed

+70
-21
lines changed

3 files changed

+70
-21
lines changed

lib/Sema/CSFix.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2787,7 +2787,9 @@ AllowValueExpansionWithoutPackReferences::create(ConstraintSystem &cs,
27872787

27882788
bool IgnoreMissingEachKeyword::diagnose(const Solution &solution,
27892789
bool asNote) const {
2790-
return false;
2790+
MissingEachForValuePackReference failure(solution, ValuePackType,
2791+
getLocator());
2792+
return failure.diagnose(asNote);
27912793
}
27922794

27932795
IgnoreMissingEachKeyword *

lib/Sema/CSGen.cpp

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,23 @@ namespace {
10891089
return outputTy;
10901090
}
10911091

1092+
Type openPackElement(Type packType, ConstraintLocator *locator) {
1093+
// If 'each t' is written outside of a pack expansion expression, allow the
1094+
// type to bind to a hole. The invalid pack reference will be diagnosed when
1095+
// attempting to bind the type variable for the underlying pack reference to
1096+
// a pack type without TVO_CanBindToPack.
1097+
if (PackElementEnvironments.empty()) {
1098+
return CS.createTypeVariable(locator,
1099+
TVO_CanBindToHole | TVO_CanBindToNoEscape);
1100+
}
1101+
1102+
// The type of a PackElementExpr is the opened pack element archetype
1103+
// of the pack reference.
1104+
OpenPackElementType openPackElement(CS, locator,
1105+
PackElementEnvironments.back());
1106+
return openPackElement(packType, /*packRepr*/ nullptr);
1107+
}
1108+
10921109
public:
10931110
ConstraintGenerator(ConstraintSystem &CS, DeclContext *DC)
10941111
: CS(CS), CurDC(DC ? DC : CS.DC), CurrPhase(CS.getPhase()) {
@@ -1407,6 +1424,20 @@ namespace {
14071424
return invalidateReference();
14081425
}
14091426

1427+
// value packs cannot be referenced without `each` immediately
1428+
// preceding them.
1429+
if (auto *expansion = knownType->getAs<PackExpansionType>()) {
1430+
if (!PackElementEnvironments.empty() &&
1431+
!isExpr<PackElementExpr>(CS.getParentExpr(E))) {
1432+
auto packType = expansion->getPatternType();
1433+
(void)CS.recordFix(
1434+
IgnoreMissingEachKeyword::create(CS, packType, locator));
1435+
auto eltType = openPackElement(packType, locator);
1436+
CS.setType(E, eltType);
1437+
return eltType;
1438+
}
1439+
}
1440+
14101441
if (!knownType->hasPlaceholder()) {
14111442
// Set the favored type for this expression to the known type.
14121443
CS.setFavoredType(E, knownType.getPointer());
@@ -3067,10 +3098,12 @@ namespace {
30673098
SmallVectorImpl<ASTNode> &packs) {
30683099
struct PackCollector : public ASTWalker {
30693100
private:
3101+
ConstraintSystem &CS;
30703102
SmallVectorImpl<ASTNode> &Packs;
30713103

30723104
public:
3073-
PackCollector(SmallVectorImpl<ASTNode> &packs) : Packs(packs) {}
3105+
PackCollector(ConstraintSystem &cs, SmallVectorImpl<ASTNode> &packs)
3106+
: CS(cs), Packs(packs) {}
30743107

30753108
/// Walk everything that's available.
30763109
MacroWalking getMacroWalkingBehavior() const override {
@@ -3087,6 +3120,21 @@ namespace {
30873120
Packs.push_back(E);
30883121
}
30893122

3123+
if (auto *declRef = dyn_cast<DeclRefExpr>(E)) {
3124+
auto type = CS.getTypeIfAvailable(declRef);
3125+
if (!type)
3126+
return Action::Continue(E);
3127+
3128+
if (type->is<ElementArchetypeType>() &&
3129+
CS.hasFixFor(CS.getConstraintLocator(declRef),
3130+
FixKind::IgnoreMissingEachKeyword)) {
3131+
Packs.push_back(PackElementExpr::create(CS.getASTContext(),
3132+
/*eachLoc=*/SourceLoc(),
3133+
declRef,
3134+
/*implicit=*/true));
3135+
}
3136+
}
3137+
30903138
return Action::Continue(E);
30913139
}
30923140

@@ -3102,7 +3150,7 @@ namespace {
31023150

31033151
return Action::Continue();
31043152
}
3105-
} packCollector(packs);
3153+
} packCollector(CS, packs);
31063154

31073155
expansion->getPatternExpr()->walk(packCollector);
31083156
}
@@ -3162,23 +3210,8 @@ namespace {
31623210
}
31633211

31643212
Type visitPackElementExpr(PackElementExpr *expr) {
3165-
auto packType = CS.getType(expr->getPackRefExpr());
3166-
3167-
// If 'each t' is written outside of a pack expansion expression, allow the
3168-
// type to bind to a hole. The invalid pack reference will be diagnosed when
3169-
// attempting to bind the type variable for the underlying pack reference to
3170-
// a pack type without TVO_CanBindToPack.
3171-
if (PackElementEnvironments.empty()) {
3172-
return CS.createTypeVariable(CS.getConstraintLocator(expr),
3173-
TVO_CanBindToHole |
3174-
TVO_CanBindToNoEscape);
3175-
}
3176-
3177-
// The type of a PackElementExpr is the opened pack element archetype
3178-
// of the pack reference.
3179-
OpenPackElementType openPackElement(CS, CS.getConstraintLocator(expr),
3180-
PackElementEnvironments.back());
3181-
return openPackElement(packType, /*packRepr*/ nullptr);
3213+
return openPackElement(CS.getType(expr->getPackRefExpr()),
3214+
CS.getConstraintLocator(expr));
31823215
}
31833216

31843217
Type visitMaterializePackExpr(MaterializePackExpr *expr) {

test/Constraints/pack-expansion-expressions.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,8 @@ do {
455455

456456
func test_misplaced_each<each T: P>(_ value: repeat each T) -> (repeat each T.A) {
457457
return (repeat each value.makeA())
458-
// expected-error@-1 {{pack reference 'each T' can only appear in pack expansion}}
458+
// expected-error@-1 {{value pack 'each T' must be referenced with 'each'}} {{25-25=(each }} {{30-30=)}}
459+
// expected-error@-2 {{pack expansion requires that '()' and 'each T' have the same shape}}
459460
}
460461
}
461462

@@ -481,3 +482,16 @@ do {
481482
// expected-error@-1:25 {{value pack expansion must contain at least one pack reference}}
482483
}
483484
}
485+
486+
// missing 'each' keyword before value pack references
487+
do {
488+
func overloaded<each U>(_: String, _: repeat each U) -> Int { 42 }
489+
func overloaded<each T>(_: Int, _ b: repeat each T) -> (repeat each T) {
490+
fatalError()
491+
}
492+
493+
func test<each T>(v: repeat each T) {
494+
_ = (repeat overloaded(42, v)) // expected-error {{value pack 'each T' must be referenced with 'each'}} {{32-32=each }}
495+
_ = (repeat overloaded(42, each v)) // Ok
496+
}
497+
}

0 commit comments

Comments
 (0)