Skip to content

Commit cab39bf

Browse files
committed
[CS] Formalize param flag handling for imploding params
By default avoid imploding params that have parameter flags, but carve out exceptions for ownership flags, which can be thunked, and `@_nonEphemeral` which can be freely dropped without issue.
1 parent af14bba commit cab39bf

File tree

6 files changed

+62
-9
lines changed

6 files changed

+62
-9
lines changed

include/swift/AST/Types.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3005,7 +3005,11 @@ class AnyFunctionType : public TypeBase {
30053005

30063006
public:
30073007
/// Take an array of parameters and turn it into a tuple or paren type.
3008-
static Type composeTuple(ASTContext &ctx, ArrayRef<Param> params);
3008+
///
3009+
/// \param wantParamFlags Whether to preserve the parameter flags from the
3010+
/// given set of parameters.
3011+
static Type composeTuple(ASTContext &ctx, ArrayRef<Param> params,
3012+
bool wantParamFlags = true);
30093013

30103014
/// Given two arrays of parameters determine if they are equal in their
30113015
/// canonicalized form. Internal labels and type sugar is *not* taken into

lib/AST/ASTContext.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3456,11 +3456,13 @@ Type AnyFunctionType::Param::getParameterType(bool forCanonical,
34563456
return type;
34573457
}
34583458

3459-
Type AnyFunctionType::composeTuple(ASTContext &ctx, ArrayRef<Param> params) {
3459+
Type AnyFunctionType::composeTuple(ASTContext &ctx, ArrayRef<Param> params,
3460+
bool wantParamFlags) {
34603461
SmallVector<TupleTypeElt, 4> elements;
34613462
for (const auto &param : params) {
3462-
elements.emplace_back(param.getParameterType(), param.getLabel(),
3463-
param.getParameterFlags());
3463+
auto flags = wantParamFlags ? param.getParameterFlags()
3464+
: ParameterTypeFlags();
3465+
elements.emplace_back(param.getParameterType(), param.getLabel(), flags);
34643466
}
34653467
return TupleType::get(elements, ctx);
34663468
}

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2209,16 +2209,27 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
22092209
if (params.size() == 1)
22102210
return false;
22112211

2212-
for (auto param : params)
2213-
if (param.isVariadic() || param.isInOut() || param.isAutoClosure())
2212+
for (auto &param : params) {
2213+
// We generally cannot handle parameter flags, though we can carve out an
2214+
// exception for ownership flags such as __owned, which we can thunk, and
2215+
// flags that can freely dropped from a function type such as
2216+
// @_nonEphemeral.
2217+
auto flags = param.getParameterFlags();
2218+
flags = flags.withValueOwnership(
2219+
param.isInOut() ? ValueOwnership::InOut : ValueOwnership::Default);
2220+
flags = flags.withNonEphemeral(false);
2221+
if (!flags.isNone())
22142222
return false;
2215-
2223+
}
22162224
return true;
22172225
};
22182226

22192227
auto implodeParams = [&](SmallVectorImpl<AnyFunctionType::Param> &params) {
2220-
auto input = AnyFunctionType::composeTuple(getASTContext(), params);
2221-
2228+
// Form an imploded tuple type, dropping the parameter flags as although
2229+
// canImplodeParams makes sure we're not dealing with vargs, inout, etc,
2230+
// we may still have e.g ownership flags left over, which we can drop.
2231+
auto input = AnyFunctionType::composeTuple(getASTContext(), params,
2232+
/*wantParamFlags*/ false);
22222233
params.clear();
22232234
// If fixes are disabled let's do an easy thing and implode
22242235
// tuple directly into parameters list.

test/Concurrency/isolated_parameters.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,13 @@ actor TestActor {
102102

103103
func redecl(_: TestActor) { } // expected-note{{'redecl' previously declared here}}
104104
func redecl(_: isolated TestActor) { } // expected-error{{invalid redeclaration of 'redecl'}}
105+
106+
func tuplify<Ts>(_ fn: (Ts) -> Void) {} // expected-note {{in call to function 'tuplify'}}
107+
108+
@available(SwiftStdlib 5.5, *)
109+
func testTuplingIsolated(_ a: isolated A, _ b: isolated A) {
110+
// FIXME: We shouldn't duplicate the "cannot convert value of type" diagnostic (SR-15179)
111+
tuplify(testTuplingIsolated)
112+
// expected-error@-1 {{generic parameter 'Ts' could not be inferred}}
113+
// expected-error@-2 2{{cannot convert value of type '(isolated A, isolated A) -> ()' to expected argument type '(Ts) -> Void'}}
114+
}

test/Constraints/function.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,16 @@ func test_passing_noescape_function_ref_to_generic_parameter() {
250250
func SR14784<T>(_ fs: () -> T..., a _ : Int) -> T {
251251
fs.first! // expected-error{{function produces expected type 'T'; did you mean to call it with '()'?}} {{11-11=()}}
252252
}
253+
254+
func tuplify<Ts>(_ fn: (Ts) -> Void) {}
255+
256+
func testInvalidTupleImplosions() {
257+
func takesVargs(_ x: Int, _ y: String...) {}
258+
tuplify(takesVargs) // expected-error {{cannot convert value of type '(Int, String...) -> ()' to expected argument type '(Int) -> Void'}}
259+
260+
func takesAutoclosure(_ x: @autoclosure () -> Int, y: String) {}
261+
tuplify(takesAutoclosure) // expected-error {{cannot convert value of type '(@autoclosure () -> Int, String) -> ()' to expected argument type '(@escaping () -> Int) -> Void'}}
262+
263+
func takesInout(_ x: Int, _ y: inout String) {}
264+
tuplify(takesInout) // expected-error {{cannot convert value of type '(Int, inout String) -> ()' to expected argument type '(Int) -> Void'}}
265+
}

test/Sema/diag_non_ephemeral.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,3 +525,16 @@ func ambiguous_fn(_ ptr: UnsafeRawPointer) {} // expected-note {{found this cand
525525
func test_ambiguity_with_function_instead_of_argument(_ x: inout Int) {
526526
ambiguous_fn(&x) // expected-error {{ambiguous use of 'ambiguous_fn'}}
527527
}
528+
529+
func tuplify<Ts>(_ fn: @escaping (Ts) -> Void) -> (Ts) -> Void { fn }
530+
531+
func testTuplingNonEphemeral(_ ptr: UnsafePointer<Int>) {
532+
// Make sure we drop @_nonEphemeral when imploding params. This is to ensure
533+
// we don't accidently break any potentially valid code.
534+
let fn = tuplify(takesTwoPointers)
535+
fn((ptr, ptr))
536+
537+
// Note we can't perform X-to-pointer conversions in this case even if we
538+
// wanted to.
539+
fn(([1], ptr)) // expected-error {{tuple type '([Int], UnsafePointer<Int>)' is not convertible to tuple type '(UnsafePointer<Int>, UnsafePointer<Int>)'}}
540+
}

0 commit comments

Comments
 (0)