diff --git a/include/swift/Sema/Constraint.h b/include/swift/Sema/Constraint.h index 083bf90f0a2..c737934f737 100644 --- a/include/swift/Sema/Constraint.h +++ b/include/swift/Sema/Constraint.h @@ -306,6 +306,10 @@ enum class ConversionRestrictionKind { // - Unsafe[Mutable]RawPointer -> Unsafe[Mutable]Pointer<[U]Int> // - Unsafe[Mutable]Pointer <-> Unsafe[Mutable]Pointer PointerToCPointer, + // Convert a pack into a type with an equivalent arity. + // - If the arity of the pack is 1, drops the pack structure => T + // - If the arity of the pack is n >= 1, converts the pack structure into a tuple => (T, U, V) + ReifyPackToType, }; /// Specifies whether a given conversion requires the creation of a temporary diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 492f585ba65..f5df09b9184 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5718,6 +5718,8 @@ ArgumentList *ExprRewriter::coerceCallArguments( newArgs.push_back(Argument(labelLoc, paramLabel, packExpr)); continue; } + + // Handle plain variadic parameters. if (param.isVariadic()) { assert(!param.isInOut()); @@ -6694,6 +6696,11 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, finishApply(implicitInit, toType, callLocator, callLocator); return implicitInit; } + case ConversionRestrictionKind::ReifyPackToType: { + auto reifyPack = + cs.cacheType(new (ctx) ReifyPackExpr(expr, toType)); + return coerceToType(reifyPack, toType, locator); + } } } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 25236fdcd6c..52b58b38082 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -6747,6 +6747,7 @@ void NonEphemeralConversionFailure::emitSuggestionNotes() const { case ConversionRestrictionKind::ObjCTollFreeBridgeToCF: case ConversionRestrictionKind::CGFloatToDouble: case ConversionRestrictionKind::DoubleToCGFloat: + case ConversionRestrictionKind::ReifyPackToType: llvm_unreachable("Expected an ephemeral conversion!"); } } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 3950c8410d4..58b7d97beab 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -11630,6 +11630,22 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( {getConstraintLocator(locator), restriction}); return SolutionKind::Solved; } + case ConversionRestrictionKind::ReifyPackToType: { + type1 = simplifyType(type1); + auto *PET = type1->castTo(); + if (auto *TT = type2->getAs()) { + llvm::SmallVector elts; + for (Type elt : PET->getElementTypes()) { + elts.push_back(elt); + } + Type tupleType1 = TupleType::get(elts, getASTContext()); + return matchTypes(tupleType1, TT, ConstraintKind::Bind, subflags, + locator); + } else { + return matchTypes(PET->getElementType(0), type2, ConstraintKind::Bind, + subflags, locator); + } + } } llvm_unreachable("bad conversion restriction"); diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index 9bb7de867d0..1001ab23be2 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -619,6 +619,8 @@ StringRef swift::constraints::getName(ConversionRestrictionKind kind) { return "[CGFloat-to-Double]"; case ConversionRestrictionKind::DoubleToCGFloat: return "[Double-to-CGFloat]"; + case ConversionRestrictionKind::ReifyPackToType: + return "[Pack-to-Type]"; } llvm_unreachable("bad conversion restriction kind"); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 054eb1fe2c6..ae861b74af5 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -5273,6 +5273,7 @@ ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion, case ConversionRestrictionKind::ObjCTollFreeBridgeToCF: case ConversionRestrictionKind::CGFloatToDouble: case ConversionRestrictionKind::DoubleToCGFloat: + case ConversionRestrictionKind::ReifyPackToType: // @_nonEphemeral has no effect on these conversions, so treat them as all // being non-ephemeral in order to allow their passing to an @_nonEphemeral // parameter. diff --git a/test/Constraints/type_sequence.swift b/test/Constraints/type_sequence.swift index 2895c4777db..4ec10db9ad9 100644 --- a/test/Constraints/type_sequence.swift +++ b/test/Constraints/type_sequence.swift @@ -88,3 +88,23 @@ func call() { _ = multipleSequences(xs: "", ys: "") _ = multipleSequences(xs: "", 5.0, ys: 5.0, "") } + +func contextualTyping() { + func firsts<@_typeSequence T>(_ seqs: [T]...) -> (T?...) { + fatalError() + } + + let (_, _): (Int?, String?) = firsts([42], [""]) // OK + let (_, _): (String?, String?) = firsts([42], [""]) // expected-error {{cannot convert value of type '(Int?, String?)' to specified type '(String?, String?)'}} + let (_, _): ([Int], String?) = firsts([42], [""]) // expected-error {{cannot convert value of type '(Int?, String?)' to specified type '([Int], String?)'}} + let (_, _, _): (String?, String?, Int) = firsts([42], [""]) // expected-error {{'(Int?, String?)' is not convertible to '(String?, String?, Int)', tuples have a different number of elements}} + + func dependent<@_typeSequence T>(_ seqs: Array...) -> (Array.Element?...) { + fatalError() + } + + let (_, _): (Int?, String?) = dependent([42], [""]) // OK + let (_, _): (String?, String?) = dependent([42], [""]) // expected-error {{cannot convert value of type '(Int?, String?)' to specified type '(String?, String?)'}} + let (_, _): ([Int], String?) = dependent([42], [""]) // expected-error {{cannot convert value of type '(Int?, String?)' to specified type '([Int], String?)'}} + let (_, _, _): (String?, String?, Int) = dependent([42], [""]) // expected-error {{'(Int?, String?)' is not convertible to '(String?, String?, Int)', tuples have a different number of elements}} +} diff --git a/test/decl/func/vararg.swift b/test/decl/func/vararg.swift index 71befae75ef..506199f82b7 100644 --- a/test/decl/func/vararg.swift +++ b/test/decl/func/vararg.swift @@ -1,6 +1,7 @@ // RUN: %target-typecheck-verify-swift -var t1a: (Int...) = (1) // expected-error{{cannot create a variadic tuple}} +var t1a: (Int...) = (1) // expected-error{{cannot create expansion with non-variadic type 'Int'}} +// expected-error@-1 {{cannot convert value of type 'Int' to specified type '(Int...)'}} var t2d: (Double = 0.0) = 1 // expected-error {{default argument not permitted in a tuple type}} {{18-23=}} func f1(_ a: Int...) { for _ in a {} }