Skip to content

Commit c60b486

Browse files
authored
Merge pull request #64498 from hborla/diagnose-pack-outside-expansion-expr
[ConstraintSystem] Enforce `TVO_CanBindToPack`, and diagnose pack references outside of pack expansion expressions.
2 parents 1482108 + cb19fc3 commit c60b486

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
@@ -5319,8 +5319,9 @@ ERROR(expansion_not_allowed,none,
53195319
ERROR(expansion_not_variadic,none,
53205320
"pack expansion %0 must contain at least one pack reference", (Type))
53215321
ERROR(pack_reference_outside_expansion,none,
5322-
"pack reference %0 can only appear in pack expansion or generic requirement",
5323-
(Type))
5322+
"pack reference %0 can only appear in pack expansion "
5323+
"%select{or generic requirement|}1",
5324+
(Type, /*inExpression*/ bool))
53245325
ERROR(each_non_pack,none,
53255326
"'each' cannot be applied to non-pack type %0",
53265327
(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
@@ -6170,6 +6170,12 @@ bool InvalidPackElement::diagnoseAsError() {
61706170
return true;
61716171
}
61726172

6173+
bool InvalidPackReference::diagnoseAsError() {
6174+
emitDiagnostic(diag::pack_reference_outside_expansion,
6175+
packType, /*inExpression*/true);
6176+
return true;
6177+
}
6178+
61736179
bool CollectionElementContextualFailure::diagnoseAsError() {
61746180
auto anchor = getRawAnchor();
61756181
auto *locator = getLocator();

lib/Sema/CSDiagnostics.h

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

1865+
/// Diagnose pack references outside of pack expansion expressions.
1866+
class InvalidPackReference final : public FailureDiagnostic {
1867+
Type packType;
1868+
1869+
public:
1870+
InvalidPackReference(const Solution &solution, Type packType,
1871+
ConstraintLocator *locator)
1872+
: FailureDiagnostic(solution, locator),
1873+
packType(packType) {}
1874+
1875+
bool diagnoseAsError() override;
1876+
};
1877+
18651878
/// Diagnose a contextual mismatch between expected collection element type
18661879
/// and the one provided (e.g. source of the assignment or argument to a call)
18671880
/// 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());
@@ -3097,8 +3105,15 @@ namespace {
30973105
Type visitPackElementExpr(PackElementExpr *expr) {
30983106
auto packType = CS.getType(expr->getPackRefExpr());
30993107

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

31033118
// The type of a PackElementExpr is the opened pack element archetype
31043119
// 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()) {
@@ -14153,6 +14170,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1415314170
case FixKind::RenameConflictingPatternVariables:
1415414171
case FixKind::MustBeCopyable:
1415514172
case FixKind::AllowInvalidPackElement:
14173+
case FixKind::AllowInvalidPackReference:
1415614174
case FixKind::MacroMissingPound:
1415714175
case FixKind::AllowGlobalActorMismatch:
1415814176
case FixKind::GenericArgumentsMismatch: {

lib/Sema/TypeCheckType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4618,7 +4618,7 @@ NeverNullType TypeResolver::resolvePackElement(PackElementTypeRepr *repr,
46184618
if (!options.contains(TypeResolutionFlags::AllowPackReferences)) {
46194619
ctx.Diags.diagnose(repr->getLoc(),
46204620
diag::pack_reference_outside_expansion,
4621-
packReference);
4621+
packReference, /*inExpression*/false);
46224622
return ErrorType::get(ctx);
46234623
}
46244624

test/Constraints/pack-expansion-expressions.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,25 @@ func takesFunctionPack<each T, R>(functions: repeat ((each T) -> R)) {}
218218
func forwardFunctionPack<each T>(functions: repeat (each T) -> Bool) {
219219
takesFunctionPack(functions: repeat each functions)
220220
}
221+
222+
func packOutsideExpansion<each T>(_ t: repeat each T) {
223+
_ = t
224+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
225+
226+
forward(t)
227+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
228+
229+
_ = each t
230+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
231+
232+
forward(each t)
233+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
234+
235+
let tuple = (repeat each t)
236+
237+
_ = tuple.element
238+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
239+
240+
_ = each tuple.element
241+
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
242+
}

0 commit comments

Comments
 (0)