Skip to content

Commit e78cf22

Browse files
authored
Merge pull request #64526 from hborla/invalid-repeat
[ConstraintSystem] Diagnose pack expansion expressions in non-variadic contexts.
2 parents f3ad288 + da3079d commit e78cf22

File tree

8 files changed

+130
-9
lines changed

8 files changed

+130
-9
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5316,6 +5316,12 @@ ERROR(vararg_not_allowed,none,
53165316
ERROR(expansion_not_allowed,none,
53175317
"pack expansion %0 can only appear in a function parameter list, "
53185318
"tuple element, or generic argument list", (Type))
5319+
ERROR(expansion_expr_not_allowed,none,
5320+
"value pack expansion can only appear inside a function argument list "
5321+
"or tuple element", ())
5322+
ERROR(invalid_expansion_argument,none,
5323+
"cannot pass value pack expansion to non-pack parameter of type %0",
5324+
(Type))
53195325
ERROR(expansion_not_variadic,none,
53205326
"pack expansion %0 must contain at least one pack reference", (Type))
53215327
ERROR(pack_reference_outside_expansion,none,

include/swift/Sema/CSFix.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,9 @@ enum class FixKind : uint8_t {
431431

432432
/// Allow pack references outside of pack expansions.
433433
AllowInvalidPackReference,
434+
435+
/// Allow pack expansion expressions in a context that does not support them.
436+
AllowInvalidPackExpansion,
434437
};
435438

436439
class ConstraintFix {
@@ -2128,6 +2131,26 @@ class AllowInvalidPackReference final : public ConstraintFix {
21282131
}
21292132
};
21302133

2134+
class AllowInvalidPackExpansion final : public ConstraintFix {
2135+
AllowInvalidPackExpansion(ConstraintSystem &cs,
2136+
ConstraintLocator *locator)
2137+
: ConstraintFix(cs, FixKind::AllowInvalidPackExpansion, locator) {}
2138+
2139+
public:
2140+
std::string getName() const override {
2141+
return "allow invalid pack expansion";
2142+
}
2143+
2144+
bool diagnose(const Solution &solution, bool asNote = false) const override;
2145+
2146+
static AllowInvalidPackExpansion *create(ConstraintSystem &cs,
2147+
ConstraintLocator *locator);
2148+
2149+
static bool classof(const ConstraintFix *fix) {
2150+
return fix->getKind() == FixKind::AllowInvalidPackExpansion;
2151+
}
2152+
};
2153+
21312154
class CollectionElementContextualMismatch final
21322155
: public ContextualMismatch,
21332156
private llvm::TrailingObjects<CollectionElementContextualMismatch,

lib/Sema/CSDiagnostics.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6176,6 +6176,20 @@ bool InvalidPackReference::diagnoseAsError() {
61766176
return true;
61776177
}
61786178

6179+
bool InvalidPackExpansion::diagnoseAsError() {
6180+
auto *locator = getLocator();
6181+
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
6182+
if (auto argInfo = getFunctionArgApplyInfo(locator)) {
6183+
emitDiagnostic(diag::invalid_expansion_argument,
6184+
argInfo->getParamInterfaceType());
6185+
return true;
6186+
}
6187+
}
6188+
6189+
emitDiagnostic(diag::expansion_expr_not_allowed);
6190+
return true;
6191+
}
6192+
61796193
bool CollectionElementContextualFailure::diagnoseAsError() {
61806194
auto anchor = getRawAnchor();
61816195
auto *locator = getLocator();

lib/Sema/CSDiagnostics.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,6 +1875,17 @@ class InvalidPackReference final : public FailureDiagnostic {
18751875
bool diagnoseAsError() override;
18761876
};
18771877

1878+
/// Diagnose pack expansion expressions appearing in contexts that do not
1879+
/// accept a comma-separated list of values.
1880+
class InvalidPackExpansion final : public FailureDiagnostic {
1881+
public:
1882+
InvalidPackExpansion(const Solution &solution,
1883+
ConstraintLocator *locator)
1884+
: FailureDiagnostic(solution, locator) {}
1885+
1886+
bool diagnoseAsError() override;
1887+
};
1888+
18781889
/// Diagnose a contextual mismatch between expected collection element type
18791890
/// and the one provided (e.g. source of the assignment or argument to a call)
18801891
/// e.g.:

lib/Sema/CSFix.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,18 @@ AllowInvalidPackReference::create(ConstraintSystem &cs, Type packType,
14291429
AllowInvalidPackReference(cs, packType, locator);
14301430
}
14311431

1432+
bool AllowInvalidPackExpansion::diagnose(const Solution &solution,
1433+
bool asNote) const {
1434+
InvalidPackExpansion failure(solution, getLocator());
1435+
return failure.diagnose(asNote);
1436+
}
1437+
1438+
AllowInvalidPackExpansion *
1439+
AllowInvalidPackExpansion::create(ConstraintSystem &cs,
1440+
ConstraintLocator *locator) {
1441+
return new (cs.getAllocator()) AllowInvalidPackExpansion(cs, locator);
1442+
}
1443+
14321444
bool CollectionElementContextualMismatch::diagnose(const Solution &solution,
14331445
bool asNote) const {
14341446
CollectionElementContextualFailure failure(

lib/Sema/CSSimplify.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4311,6 +4311,23 @@ ConstraintSystem::matchTypesBindTypeVar(
43114311
return getTypeMatchFailure(locator);
43124312
}
43134313

4314+
// Binding to a pack expansion type is always an error. This indicates
4315+
// that a pack expansion expression was used in a context that doesn't
4316+
// support it.
4317+
if (type->is<PackExpansionType>()) {
4318+
if (!shouldAttemptFixes())
4319+
return getTypeMatchFailure(locator);
4320+
4321+
auto *fix =
4322+
AllowInvalidPackExpansion::create(*this, getConstraintLocator(locator));
4323+
if (recordFix(fix))
4324+
return getTypeMatchFailure(locator);
4325+
4326+
// Don't allow the pack expansion type to propagate to other
4327+
// bindings.
4328+
type = PlaceholderType::get(typeVar->getASTContext(), typeVar);
4329+
}
4330+
43144331
// We do not allow keypaths to go through AnyObject. Let's create a fix
43154332
// so this can be diagnosed later.
43164333
if (auto loc = typeVar->getImpl().getLocator()) {
@@ -7154,6 +7171,22 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
71547171
}
71557172
}
71567173

7174+
// Matching types where one side is a pack expansion and the other is not
7175+
// means a pack expansion was used where it isn't supported.
7176+
if (type1->is<PackExpansionType>() != type2->is<PackExpansionType>()) {
7177+
if (!shouldAttemptFixes())
7178+
return getTypeMatchFailure(locator);
7179+
7180+
if (type1->isPlaceholder() || type2->isPlaceholder())
7181+
return getTypeMatchSuccess();
7182+
7183+
auto *loc = getConstraintLocator(locator);
7184+
if (recordFix(AllowInvalidPackExpansion::create(*this, loc)))
7185+
return getTypeMatchFailure(locator);
7186+
7187+
return getTypeMatchSuccess();
7188+
}
7189+
71577190
if (kind >= ConstraintKind::Conversion) {
71587191
// An lvalue of type T1 can be converted to a value of type T2 so long as
71597192
// T1 is convertible to T2 (by loading the value). Note that we cannot get
@@ -14171,6 +14204,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1417114204
case FixKind::MustBeCopyable:
1417214205
case FixKind::AllowInvalidPackElement:
1417314206
case FixKind::AllowInvalidPackReference:
14207+
case FixKind::AllowInvalidPackExpansion:
1417414208
case FixKind::MacroMissingPound:
1417514209
case FixKind::AllowGlobalActorMismatch:
1417614210
case FixKind::GenericArgumentsMismatch: {

test/Constraints/pack-expansion-expressions.swift

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func coerceExpansion<each T>(_ value: repeat each T) {
3939
func localValuePack<each T>(_ t: repeat each T) -> (repeat each T, repeat each T) {
4040
let local = repeat each t
4141
let localAnnotated: repeat each T = repeat each t
42+
// expected-error@-1{{value pack expansion can only appear inside a function argument list or tuple element}}
4243

4344
return (repeat each local, repeat each localAnnotated)
4445
}
@@ -52,14 +53,14 @@ protocol P {
5253
}
5354

5455
func outerArchetype<each T, U>(t: repeat each T, u: U) where each T: P {
55-
let _: repeat (each T.A, U) = repeat ((each t).value, u)
56+
let _: (repeat (each T.A, U)) = (repeat ((each t).value, u))
5657
}
5758

5859
func sameElement<each T, U>(t: repeat each T, u: U) where each T: P, each T == U {
5960
// expected-error@-1{{same-element requirements are not yet supported}}
6061

6162
// FIXME: Opened element archetypes in diagnostics
62-
let _: repeat each T = repeat (each t).f(u)
63+
let _: (repeat each T) = (repeat (each t).f(u))
6364
// expected-error@-1 {{cannot convert value of type 'U' to expected argument type 'τ_1_0'}}
6465
}
6566

@@ -68,23 +69,23 @@ func forEachEach<each C, U>(c: repeat each C, function: (U) -> Void)
6869
// expected-error@-1{{same-element requirements are not yet supported}}
6970

7071
// FIXME: Opened element archetypes in diagnostics
71-
_ = repeat (each c).forEach(function)
72+
_ = (repeat (each c).forEach(function))
7273
// expected-error@-1 {{cannot convert value of type '(U) -> Void' to expected argument type '(τ_1_0.Element) throws -> Void'}}
7374
}
7475

7576
func typeReprPacks<each T>(_ t: repeat each T) where each T: ExpressibleByIntegerLiteral {
76-
_ = repeat Array<each T>()
77-
_ = repeat 1 as each T
77+
_ = (repeat Array<each T>())
78+
_ = (repeat 1 as each T)
7879

7980
_ = Array<each T>() // expected-error {{pack reference 'T' requires expansion using keyword 'repeat'}}
8081
_ = 1 as each T // expected-error {{pack reference 'T' requires expansion using keyword 'repeat'}}
8182
repeat Invalid<String, each T>("") // expected-error {{cannot find 'Invalid' in scope}}
8283
}
8384

8485
func sameShapeDiagnostics<each T, each U>(t: repeat each T, u: repeat each U) {
85-
_ = repeat (each t, each u) // expected-error {{pack expansion requires that 'U' and 'T' have the same shape}}
86-
_ = repeat Array<(each T, each U)>() // expected-error {{pack expansion requires that 'U' and 'T' have the same shape}}
87-
_ = repeat (Array<each T>(), each u) // expected-error {{pack expansion requires that 'U' and 'T' have the same shape}}
86+
_ = (repeat (each t, each u)) // expected-error {{pack expansion requires that 'U' and 'T' have the same shape}}
87+
_ = (repeat Array<(each T, each U)>()) // expected-error {{pack expansion requires that 'U' and 'T' have the same shape}}
88+
_ = (repeat (Array<each T>(), each u)) // expected-error {{pack expansion requires that 'U' and 'T' have the same shape}}
8889
}
8990

9091
func returnPackExpansionType<each T>(_ t: repeat each T) -> repeat each T { // expected-error {{pack expansion 'repeat each T' can only appear in a function parameter list, tuple element, or generic argument list}}
@@ -240,3 +241,23 @@ func packOutsideExpansion<each T>(_ t: repeat each T) {
240241
_ = each tuple.element
241242
// expected-error@-1{{pack reference 'T' can only appear in pack expansion}}
242243
}
244+
245+
func identity<T>(_ t: T) -> T { t }
246+
func concrete(_: Int) {}
247+
248+
func invalidRepeat<each T>(t: repeat each T) {
249+
_ = repeat each t
250+
// expected-error@-1 {{value pack expansion can only appear inside a function argument list or tuple element}}
251+
252+
let _: Int = repeat each t
253+
// expected-error@-1 {{value pack expansion can only appear inside a function argument list or tuple element}}
254+
255+
identity(identity(repeat each t))
256+
// expected-error@-1 {{cannot pass value pack expansion to non-pack parameter of type 'T'}}
257+
258+
concrete(repeat each t)
259+
// expected-error@-1 {{cannot pass value pack expansion to non-pack parameter of type 'Int'}}
260+
261+
_ = [repeat each t]
262+
// expected-error@-1 {{value pack expansion can only appear inside a function argument list or tuple element}}
263+
}

test/type/pack_expansion.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,5 @@ func packRefOutsideExpansion<each T>(_: each T.Type) {}
9393
// coverage to ensure a 'repeat each' type is considered Copyable
9494
func golden<Z>(_ z: Z) {}
9595
func hour<each T>(_ t: repeat each T) {
96-
_ = repeat golden(each t)
96+
_ = (repeat golden(each t))
9797
}

0 commit comments

Comments
 (0)