Skip to content

Commit ad3a385

Browse files
committed
[Sema] Eliminate single-element tuples after parameter pack substitution.
1 parent a9e5075 commit ad3a385

File tree

9 files changed

+138
-71
lines changed

9 files changed

+138
-71
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5289,6 +5289,9 @@ ERROR(dot_protocol_on_non_existential,none,
52895289
"cannot use 'Protocol' with non-protocol type %0", (Type))
52905290
ERROR(tuple_single_element,none,
52915291
"cannot create a single-element tuple with an element label", ())
5292+
ERROR(tuple_pack_element_label,none,
5293+
"cannot use label with pack expansion tuple element",
5294+
())
52925295
ERROR(vararg_not_allowed,none,
52935296
"variadic parameter cannot appear outside of a function parameter list",
52945297
())

include/swift/AST/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2395,7 +2395,7 @@ class TupleType final : public TypeBase, public llvm::FoldingSetNode,
23952395

23962396
bool containsPackExpansionType() const;
23972397

2398-
TupleType *flattenPackTypes();
2398+
Type flattenPackTypes();
23992399

24002400
private:
24012401
TupleType(ArrayRef<TupleTypeElt> elements, const ASTContext *CanCtx,

lib/AST/ParameterPack.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ bool TupleType::containsPackExpansionType() const {
158158
}
159159

160160
/// (W, {X, Y}..., Z) => (W, X, Y, Z)
161-
TupleType *TupleType::flattenPackTypes() {
161+
Type TupleType::flattenPackTypes() {
162162
bool anyChanged = false;
163163
SmallVector<TupleTypeElt, 4> elts;
164164

@@ -193,6 +193,15 @@ TupleType *TupleType::flattenPackTypes() {
193193
if (!anyChanged)
194194
return this;
195195

196+
// If pack substitution yields a single-element tuple, the tuple
197+
// structure is flattened to produce the element type.
198+
if (elts.size() == 1) {
199+
auto type = elts.front().getType();
200+
if (!type->is<PackExpansionType>() && !type->is<TypeVariableType>()) {
201+
return type;
202+
}
203+
}
204+
196205
return TupleType::get(elts, getASTContext());
197206
}
198207

lib/Sema/CSSimplify.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6743,22 +6743,21 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
67436743
// If the tuple has consecutive pack expansions, packs must be
67446744
// resolved before matching.
67456745
auto delayMatching = [](TupleType *tuple) {
6746-
bool afterUnresolvedPack = false;
6746+
bool afterPack = false;
67476747
for (auto element : tuple->getElements()) {
6748-
if (afterUnresolvedPack && !element.hasName()) {
6749-
return true;
6750-
}
6751-
6752-
if (element.getType()->is<PackExpansionType>()) {
6748+
if (afterPack && !element.hasName()) {
67536749
SmallPtrSet<TypeVariableType *, 2> typeVars;
67546750
element.getType()->getTypeVariables(typeVars);
67556751

6756-
afterUnresolvedPack = llvm::any_of(typeVars, [](auto *tv) {
6752+
bool hasUnresolvedPack = llvm::any_of(typeVars, [](auto *tv) {
67576753
return tv->getImpl().canBindToPack();
67586754
});
6759-
} else {
6760-
afterUnresolvedPack = false;
6755+
6756+
if (hasUnresolvedPack)
6757+
return true;
67616758
}
6759+
6760+
afterPack = element.getType()->is<PackExpansionType>();
67626761
}
67636762

67646763
return false;

lib/Sema/ConstraintSystem.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,16 @@ Type ConstraintSystem::getFixedTypeRecursive(Type type,
11181118
return getFixedTypeRecursive(newType, flags, wantRValue);
11191119
}
11201120

1121+
// Tuple types can lose their tuple structure under substitution
1122+
// when a parameter pack is substituted with one element.
1123+
if (auto tuple = type->getAs<TupleType>()) {
1124+
auto simplified = simplifyType(type);
1125+
if (simplified.getPointer() == type.getPointer())
1126+
return type;
1127+
1128+
return getFixedTypeRecursive(simplified, flags, wantRValue);
1129+
}
1130+
11211131
if (auto typeVar = type->getAs<TypeVariableType>()) {
11221132
if (auto fixed = getFixedType(typeVar))
11231133
return getFixedTypeRecursive(fixed, flags, wantRValue);
@@ -3702,6 +3712,20 @@ Type ConstraintSystem::simplifyTypeImpl(Type type,
37023712
if (auto tvt = dyn_cast<TypeVariableType>(type.getPointer()))
37033713
return getFixedTypeFn(tvt);
37043714

3715+
if (auto tuple = dyn_cast<TupleType>(type.getPointer())) {
3716+
if (tuple->getNumElements() == 1) {
3717+
auto element = tuple->getElement(0);
3718+
auto elementType = simplifyTypeImpl(element.getType(), getFixedTypeFn);
3719+
3720+
// Flatten single-element tuples containing type variables that cannot
3721+
// bind to packs.
3722+
auto typeVar = elementType->getAs<TypeVariableType>();
3723+
if (!element.hasName() && typeVar && !typeVar->getImpl().canBindToPack()) {
3724+
return typeVar;
3725+
}
3726+
}
3727+
}
3728+
37053729
// If this is a dependent member type for which we end up simplifying
37063730
// the base to a non-type-variable, perform lookup.
37073731
if (auto depMemTy = dyn_cast<DependentMemberType>(type.getPointer())) {

lib/Sema/TypeCheckType.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4634,6 +4634,11 @@ NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr,
46344634
if (eltName.empty())
46354635
continue;
46364636

4637+
if (ty->is<PackExpansionType>()) {
4638+
diagnose(repr->getElementNameLoc(i), diag::tuple_pack_element_label);
4639+
hadError = true;
4640+
}
4641+
46374642
if (seenEltNames.count(eltName) == 1) {
46384643
foundDupLabel = true;
46394644
}
@@ -4649,23 +4654,24 @@ NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr,
46494654
diagnose(repr->getLoc(), diag::tuple_duplicate_label);
46504655
}
46514656

4652-
if (options.contains(TypeResolutionFlags::SILType) ||
4653-
ctx.LangOpts.hasFeature(Feature::VariadicGenerics)) {
4657+
if (options.contains(TypeResolutionFlags::SILType)) {
46544658
if (repr->isParenType())
46554659
return ParenType::get(ctx, elements[0].getType());
46564660
} else {
46574661
// Single-element labeled tuples are not permitted outside of declarations
46584662
// or SIL, either.
4659-
if (elements.size() == 1 && elements[0].hasName()
4660-
&& !(options & TypeResolutionFlags::SILType)) {
4663+
if (elements.size() == 1 && elements[0].hasName() &&
4664+
!elements[0].getType()->is<PackExpansionType>() &&
4665+
!(options & TypeResolutionFlags::SILType)) {
46614666
diagnose(repr->getElementNameLoc(0), diag::tuple_single_element)
46624667
.fixItRemoveChars(repr->getElementNameLoc(0),
46634668
repr->getElementType(0)->getStartLoc());
46644669

46654670
elements[0] = TupleTypeElt(elements[0].getType());
46664671
}
46674672

4668-
if (elements.size() == 1 && !elements[0].hasName())
4673+
if (elements.size() == 1 && !elements[0].hasName() &&
4674+
!elements[0].getType()->is<PackExpansionType>())
46694675
return ParenType::get(ctx, elements[0].getType());
46704676
}
46714677

test/Constraints/one_element_tuple.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,29 @@
33
// REQUIRES: asserts
44

55
let t1: (_: Int) = (_: 3)
6+
7+
// FIXME: diag::tuple_single_element should be diagnosed in the constraint system
8+
// instead of MiscDiagnostics, which will allow the compiler to emit that
9+
// error instead of bogus type mismatches for tuple expressions.
610
let t2: (x: Int) = (x: 3)
11+
// expected-error@-1{{cannot create a single-element tuple with an element label}}
12+
// expected-error@-2 {{cannot convert value of type '(x: Int)' to specified type 'Int'}}
713

814
let i1: Int = t1.0
15+
// expected-error@-1 {{value of type 'Int' has no member '0'}}
16+
917
let i2: Int = t2.x
18+
// expected-error@-1 {{value of type 'Int' has no member 'x'}}
1019

1120
let m1: (_: Int).Type = (_: Int).self
1221
let m2: (x: Int).Type = (x: Int).self
22+
// expected-error@-1 2 {{cannot create a single-element tuple with an element label}}
23+
24+
struct S<each T> {
25+
var t: (repeat each T)
26+
}
27+
28+
func packSubstitution() -> Int {
29+
let s = S<Int>(t: 1)
30+
return s.t
31+
}

0 commit comments

Comments
 (0)