Skip to content

Commit cb19fc3

Browse files
committed
[ConstraintSystem] Enforce TVO_CanBindToPack, and diagnose pack references outside
of pack expansion expressions.
1 parent 6c5ac51 commit cb19fc3

File tree

9 files changed

+124
-9
lines changed

9 files changed

+124
-9
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5317,8 +5317,9 @@ ERROR(expansion_not_allowed,none,
53175317
ERROR(expansion_not_variadic,none,
53185318
"pack expansion %0 must contain at least one pack reference", (Type))
53195319
ERROR(pack_reference_outside_expansion,none,
5320-
"pack reference %0 can only appear in pack expansion or generic requirement",
5321-
(Type))
5320+
"pack reference %0 can only appear in pack expansion "
5321+
"%select{or generic requirement|}1",
5322+
(Type, /*inExpression*/ bool))
53225323
ERROR(each_non_pack,none,
53235324
"'each' cannot be applied to non-pack type %0",
53245325
(Type))

include/swift/Sema/CSFix.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,9 @@ enum class FixKind : uint8_t {
428428

429429
/// Allow 'each' applied to a non-pack type.
430430
AllowInvalidPackElement,
431+
432+
/// Allow pack references outside of pack expansions.
433+
AllowInvalidPackReference,
431434
};
432435

433436
class ConstraintFix {
@@ -2099,6 +2102,30 @@ class AllowInvalidPackElement final : public ConstraintFix {
20992102
}
21002103
};
21012104

2105+
class AllowInvalidPackReference final : public ConstraintFix {
2106+
Type packType;
2107+
2108+
AllowInvalidPackReference(ConstraintSystem &cs, Type packType,
2109+
ConstraintLocator *locator)
2110+
: ConstraintFix(cs, FixKind::AllowInvalidPackReference, locator),
2111+
packType(packType) {}
2112+
2113+
public:
2114+
std::string getName() const override {
2115+
return "allow pack outside pack expansion";
2116+
}
2117+
2118+
bool diagnose(const Solution &solution, bool asNote = false) const override;
2119+
2120+
static AllowInvalidPackReference *create(ConstraintSystem &cs,
2121+
Type packType,
2122+
ConstraintLocator *locator);
2123+
2124+
static bool classof(const ConstraintFix *fix) {
2125+
return fix->getKind() == FixKind::AllowInvalidPackReference;
2126+
}
2127+
};
2128+
21022129
class CollectionElementContextualMismatch final
21032130
: public ContextualMismatch,
21042131
private llvm::TrailingObjects<CollectionElementContextualMismatch,

lib/Sema/CSDiagnostics.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6146,6 +6146,12 @@ bool InvalidPackElement::diagnoseAsError() {
61466146
return true;
61476147
}
61486148

6149+
bool InvalidPackReference::diagnoseAsError() {
6150+
emitDiagnostic(diag::pack_reference_outside_expansion,
6151+
packType, /*inExpression*/true);
6152+
return true;
6153+
}
6154+
61496155
bool CollectionElementContextualFailure::diagnoseAsError() {
61506156
auto anchor = getRawAnchor();
61516157
auto *locator = getLocator();

lib/Sema/CSDiagnostics.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,6 +1851,19 @@ class InvalidPackElement final : public FailureDiagnostic {
18511851
bool diagnoseAsError() override;
18521852
};
18531853

1854+
/// Diagnose pack references outside of pack expansion expressions.
1855+
class InvalidPackReference final : public FailureDiagnostic {
1856+
Type packType;
1857+
1858+
public:
1859+
InvalidPackReference(const Solution &solution, Type packType,
1860+
ConstraintLocator *locator)
1861+
: FailureDiagnostic(solution, locator),
1862+
packType(packType) {}
1863+
1864+
bool diagnoseAsError() override;
1865+
};
1866+
18541867
/// Diagnose a contextual mismatch between expected collection element type
18551868
/// and the one provided (e.g. source of the assignment or argument to a call)
18561869
/// e.g.:

lib/Sema/CSFix.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,19 @@ AllowInvalidPackElement::create(ConstraintSystem &cs,
14011401
AllowInvalidPackElement(cs, packElementType, locator);
14021402
}
14031403

1404+
bool AllowInvalidPackReference::diagnose(const Solution &solution,
1405+
bool asNote) const {
1406+
InvalidPackReference failure(solution, packType, getLocator());
1407+
return failure.diagnose(asNote);
1408+
}
1409+
1410+
AllowInvalidPackReference *
1411+
AllowInvalidPackReference::create(ConstraintSystem &cs, Type packType,
1412+
ConstraintLocator *locator) {
1413+
return new (cs.getAllocator())
1414+
AllowInvalidPackReference(cs, packType, locator);
1415+
}
1416+
14041417
bool CollectionElementContextualMismatch::diagnose(const Solution &solution,
14051418
bool asNote) const {
14061419
CollectionElementContextualFailure failure(

lib/Sema/CSGen.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -923,9 +923,14 @@ namespace {
923923
CS.getConstraintLocator(expr, ConstraintLocator::Member),
924924
TVO_CanBindToHole);
925925
}
926+
unsigned options = (TVO_CanBindToLValue |
927+
TVO_CanBindToNoEscape);
928+
if (!PackElementEnvironments.empty())
929+
options |= TVO_CanBindToPack;
930+
926931
auto tv = CS.createTypeVariable(
927932
CS.getConstraintLocator(expr, ConstraintLocator::Member),
928-
TVO_CanBindToLValue | TVO_CanBindToNoEscape);
933+
options);
929934
SmallVector<OverloadChoice, 4> outerChoices;
930935
for (auto decl : outerAlternatives) {
931936
outerChoices.push_back(OverloadChoice(Type(), decl, functionRefKind));
@@ -1419,11 +1424,14 @@ namespace {
14191424
return invalidateReference();
14201425
}
14211426

1427+
unsigned options = (TVO_CanBindToLValue |
1428+
TVO_CanBindToNoEscape);
1429+
if (!PackElementEnvironments.empty())
1430+
options |= TVO_CanBindToPack;
1431+
14221432
// Create an overload choice referencing this declaration and immediately
14231433
// resolve it. This records the overload for use later.
1424-
auto tv = CS.createTypeVariable(locator,
1425-
TVO_CanBindToLValue |
1426-
TVO_CanBindToNoEscape);
1434+
auto tv = CS.createTypeVariable(locator, options);
14271435

14281436
OverloadChoice choice =
14291437
OverloadChoice(Type(), E->getDecl(), E->getFunctionRefKind());
@@ -3099,8 +3107,15 @@ namespace {
30993107
Type visitPackElementExpr(PackElementExpr *expr) {
31003108
auto packType = CS.getType(expr->getPackRefExpr());
31013109

3102-
if (PackElementEnvironments.empty())
3103-
return Type();
3110+
// If 'each t' is written outside of a pack expansion expression, allow the
3111+
// type to bind to a hole. The invalid pack reference will be diagnosed when
3112+
// attempting to bind the type variable for the underlying pack reference to
3113+
// a pack type without TVO_CanBindToPack.
3114+
if (PackElementEnvironments.empty()) {
3115+
return CS.createTypeVariable(CS.getConstraintLocator(expr),
3116+
TVO_CanBindToHole |
3117+
TVO_CanBindToNoEscape);
3118+
}
31043119

31053120
// The type of a PackElementExpr is the opened pack element archetype
31063121
// of the pack reference.

lib/Sema/CSSimplify.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4294,6 +4294,23 @@ ConstraintSystem::matchTypesBindTypeVar(
42944294
}
42954295
}
42964296

4297+
// If we're attempting to bind a PackType or PackArchetypeType to a type
4298+
// variable that doesn't support it, we have a pack reference outside of a
4299+
// pack expansion expression.
4300+
if (!typeVar->getImpl().canBindToPack() &&
4301+
(type->is<PackArchetypeType>() || type->is<PackType>())) {
4302+
if (shouldAttemptFixes()) {
4303+
auto *fix = AllowInvalidPackReference::create(*this, type,
4304+
getConstraintLocator(locator));
4305+
if (!recordFix(fix)) {
4306+
recordPotentialHole(typeVar);
4307+
return getTypeMatchSuccess();
4308+
}
4309+
}
4310+
4311+
return getTypeMatchFailure(locator);
4312+
}
4313+
42974314
// We do not allow keypaths to go through AnyObject. Let's create a fix
42984315
// so this can be diagnosed later.
42994316
if (auto loc = typeVar->getImpl().getLocator()) {
@@ -14151,6 +14168,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1415114168
case FixKind::RenameConflictingPatternVariables:
1415214169
case FixKind::MustBeCopyable:
1415314170
case FixKind::AllowInvalidPackElement:
14171+
case FixKind::AllowInvalidPackReference:
1415414172
case FixKind::MacroMissingPound:
1415514173
case FixKind::AllowGlobalActorMismatch:
1415614174
case FixKind::GenericArgumentsMismatch: {

lib/Sema/TypeCheckType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4598,7 +4598,7 @@ NeverNullType TypeResolver::resolvePackElement(PackElementTypeRepr *repr,
45984598
if (!options.contains(TypeResolutionFlags::AllowPackReferences)) {
45994599
ctx.Diags.diagnose(repr->getLoc(),
46004600
diag::pack_reference_outside_expansion,
4601-
packReference);
4601+
packReference, /*inExpression*/false);
46024602
return ErrorType::get(ctx);
46034603
}
46044604

test/Constraints/pack-expansion-expressions.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,25 @@ func takesFunctionPack<each T, R>(functions: repeat ((each T) -> R)) {}
202202
func forwardFunctionPack<each T>(functions: repeat (each T) -> Bool) {
203203
takesFunctionPack(functions: repeat each functions)
204204
}
205+
206+
func packOutsideExpansion<each T>(_ t: repeat each T) {
207+
_ = t
208+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
209+
210+
forward(t)
211+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
212+
213+
_ = each t
214+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
215+
216+
forward(each t)
217+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
218+
219+
let tuple = (repeat each t)
220+
221+
_ = tuple.element
222+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
223+
224+
_ = each tuple.element
225+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
226+
}

0 commit comments

Comments
 (0)