Skip to content

Commit d44d8ec

Browse files
committed
Allow Converting Pack Types to Tuples
Insert an implicit conversion from pack types to tuples with equivalent parallel structure. That means 1) The tuple must have the same arity 2) The tuple may not have any argument labels 3) The tuple may not have any variadic or inout components 4) The tuple must have the same element types as the pack
1 parent 0471e2c commit d44d8ec

File tree

8 files changed

+53
-1
lines changed

8 files changed

+53
-1
lines changed

include/swift/Sema/Constraint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ enum class ConversionRestrictionKind {
306306
// - Unsafe[Mutable]RawPointer -> Unsafe[Mutable]Pointer<[U]Int>
307307
// - Unsafe[Mutable]Pointer<Int{8, 16, ...}> <-> Unsafe[Mutable]Pointer<UInt{8, 16, ...}>
308308
PointerToCPointer,
309+
// Convert a pack into a type with an equivalent arity.
310+
// - If the arity of the pack is 1, drops the pack structure <T> => T
311+
// - If the arity of the pack is n >= 1, converts the pack structure into a tuple <T, U, V> => (T, U, V)
312+
ReifyPackToType,
309313
};
310314

311315
/// Specifies whether a given conversion requires the creation of a temporary

lib/Sema/CSApply.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5718,6 +5718,8 @@ ArgumentList *ExprRewriter::coerceCallArguments(
57185718
newArgs.push_back(Argument(labelLoc, paramLabel, packExpr));
57195719
continue;
57205720
}
5721+
5722+
// Handle plain variadic parameters.
57215723
if (param.isVariadic()) {
57225724
assert(!param.isInOut());
57235725

@@ -6694,6 +6696,11 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
66946696
finishApply(implicitInit, toType, callLocator, callLocator);
66956697
return implicitInit;
66966698
}
6699+
case ConversionRestrictionKind::ReifyPackToType: {
6700+
auto reifyPack =
6701+
cs.cacheType(new (ctx) ReifyPackExpr(expr, toType));
6702+
return coerceToType(reifyPack, toType, locator);
6703+
}
66976704
}
66986705
}
66996706

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6747,6 +6747,7 @@ void NonEphemeralConversionFailure::emitSuggestionNotes() const {
67476747
case ConversionRestrictionKind::ObjCTollFreeBridgeToCF:
67486748
case ConversionRestrictionKind::CGFloatToDouble:
67496749
case ConversionRestrictionKind::DoubleToCGFloat:
6750+
case ConversionRestrictionKind::ReifyPackToType:
67506751
llvm_unreachable("Expected an ephemeral conversion!");
67516752
}
67526753
}

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11630,6 +11630,22 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1163011630
{getConstraintLocator(locator), restriction});
1163111631
return SolutionKind::Solved;
1163211632
}
11633+
case ConversionRestrictionKind::ReifyPackToType: {
11634+
type1 = simplifyType(type1);
11635+
auto *PET = type1->castTo<PackType>();
11636+
if (auto *TT = type2->getAs<TupleType>()) {
11637+
llvm::SmallVector<TupleTypeElt, 8> elts;
11638+
for (Type elt : PET->getElementTypes()) {
11639+
elts.push_back(elt);
11640+
}
11641+
Type tupleType1 = TupleType::get(elts, getASTContext());
11642+
return matchTypes(tupleType1, TT, ConstraintKind::Bind, subflags,
11643+
locator);
11644+
} else {
11645+
return matchTypes(PET->getElementType(0), type2, ConstraintKind::Bind,
11646+
subflags, locator);
11647+
}
11648+
}
1163311649
}
1163411650

1163511651
llvm_unreachable("bad conversion restriction");

lib/Sema/Constraint.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,8 @@ StringRef swift::constraints::getName(ConversionRestrictionKind kind) {
619619
return "[CGFloat-to-Double]";
620620
case ConversionRestrictionKind::DoubleToCGFloat:
621621
return "[Double-to-CGFloat]";
622+
case ConversionRestrictionKind::ReifyPackToType:
623+
return "[Pack-to-Type]";
622624
}
623625
llvm_unreachable("bad conversion restriction kind");
624626
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5273,6 +5273,7 @@ ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion,
52735273
case ConversionRestrictionKind::ObjCTollFreeBridgeToCF:
52745274
case ConversionRestrictionKind::CGFloatToDouble:
52755275
case ConversionRestrictionKind::DoubleToCGFloat:
5276+
case ConversionRestrictionKind::ReifyPackToType:
52765277
// @_nonEphemeral has no effect on these conversions, so treat them as all
52775278
// being non-ephemeral in order to allow their passing to an @_nonEphemeral
52785279
// parameter.

test/Constraints/type_sequence.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,23 @@ func call() {
8888
_ = multipleSequences(xs: "", ys: "")
8989
_ = multipleSequences(xs: "", 5.0, ys: 5.0, "")
9090
}
91+
92+
func contextualTyping() {
93+
func firsts<@_typeSequence T>(_ seqs: [T]...) -> (T?...) {
94+
fatalError()
95+
}
96+
97+
let (_, _): (Int?, String?) = firsts([42], [""]) // OK
98+
let (_, _): (String?, String?) = firsts([42], [""]) // expected-error {{cannot convert value of type '(Int?, String?)' to specified type '(String?, String?)'}}
99+
let (_, _): ([Int], String?) = firsts([42], [""]) // expected-error {{cannot convert value of type '(Int?, String?)' to specified type '([Int], String?)'}}
100+
let (_, _, _): (String?, String?, Int) = firsts([42], [""]) // expected-error {{'(Int?, String?)' is not convertible to '(String?, String?, Int)', tuples have a different number of elements}}
101+
102+
func dependent<@_typeSequence T>(_ seqs: Array<T>...) -> (Array<T>.Element?...) {
103+
fatalError()
104+
}
105+
106+
let (_, _): (Int?, String?) = dependent([42], [""]) // OK
107+
let (_, _): (String?, String?) = dependent([42], [""]) // expected-error {{cannot convert value of type '(Int?, String?)' to specified type '(String?, String?)'}}
108+
let (_, _): ([Int], String?) = dependent([42], [""]) // expected-error {{cannot convert value of type '(Int?, String?)' to specified type '([Int], String?)'}}
109+
let (_, _, _): (String?, String?, Int) = dependent([42], [""]) // expected-error {{'(Int?, String?)' is not convertible to '(String?, String?, Int)', tuples have a different number of elements}}
110+
}

test/decl/func/vararg.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %target-typecheck-verify-swift
22

3-
var t1a: (Int...) = (1) // expected-error{{cannot create a variadic tuple}}
3+
var t1a: (Int...) = (1) // expected-error{{cannot create expansion with non-variadic type 'Int'}}
4+
// expected-error@-1 {{cannot convert value of type 'Int' to specified type '(Int...)'}}
45
var t2d: (Double = 0.0) = 1 // expected-error {{default argument not permitted in a tuple type}} {{18-23=}}
56

67
func f1(_ a: Int...) { for _ in a {} }

0 commit comments

Comments
 (0)