Skip to content

Commit 484e0a7

Browse files
committed
[ConstraintSystem] Sendable-to-Any: Allow conversion when in inout positions
It should be possible to pass values with `any Sendable` as arguments to `inout` parameters that expect `Any`. This is pretty much the same as an l-value conversion. Resolves: #79361 Resolves: rdar://144794132
1 parent ff5e2dd commit 484e0a7

File tree

5 files changed

+74
-2
lines changed

5 files changed

+74
-2
lines changed

lib/Sema/CSApply.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7414,6 +7414,19 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
74147414
/*isImplicit*/ true));
74157415
}
74167416

7417+
case TypeKind::InOut: {
7418+
auto *inOutExpr = getAsExpr<InOutExpr>(expr);
7419+
if (!inOutExpr)
7420+
break;
7421+
7422+
// If there is an `any Sendable` -> `Any` mismatch here,
7423+
// the conversion should be performed on l-value and the
7424+
// address taken from that. This is something that is already
7425+
// done as part of implicit `inout` injection for operators
7426+
// and could be reused here.
7427+
return coerceToType(inOutExpr->getSubExpr(), toType, locator);
7428+
}
7429+
74177430
case TypeKind::Pack:
74187431
case TypeKind::PackElement: {
74197432
llvm_unreachable("Unimplemented!");
@@ -7777,7 +7790,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
77777790
#define TYPE(Name, Parent)
77787791
#include "swift/AST/TypeNodes.def"
77797792
case TypeKind::Error:
7780-
case TypeKind::InOut:
77817793
case TypeKind::Module:
77827794
case TypeKind::Enum:
77837795
case TypeKind::Struct:

lib/Sema/CSSimplify.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3686,7 +3686,8 @@ static bool matchSendableExistentialToAnyInGenericArgumentPosition(
36863686

36873687
for (unsigned i = 0, n = path.size(); i < n; ++i) {
36883688
const auto &elt = path[i];
3689-
if (elt.is<LocatorPathElt::GenericType>()) {
3689+
if (elt.is<LocatorPathElt::GenericType>() ||
3690+
elt.is<LocatorPathElt::LValueConversion>()) {
36903691
if (!dropFromIdx)
36913692
dropFromIdx = i;
36923693
continue;
@@ -3727,6 +3728,12 @@ static bool matchSendableExistentialToAnyInGenericArgumentPosition(
37273728
return isPreconcurrencyContext(
37283729
cs.getConstraintLocator(simplifyLocatorToAnchor(locator)));
37293730

3731+
if (locator->directlyAt<InOutExpr>()) {
3732+
auto *IOE = castToExpr<InOutExpr>(locator->getAnchor());
3733+
return isPreconcurrencyContext(
3734+
cs.getConstraintLocator(IOE->getSubExpr()));
3735+
}
3736+
37303737
auto *calleeLoc = cs.getCalleeLocator(locator);
37313738
if (!calleeLoc)
37323739
return false;

test/Concurrency/sendable_to_any_for_generic_arguments.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,15 @@ extension User {
189189
// expected-error@-1 {{referencing initializer 'init(age:)' on '[String : any Sendable].Type' requires the types 'any Sendable' and 'Any' be equivalent}}
190190
}
191191
}
192+
193+
// https://github.com/swiftlang/swift/issues/79361
194+
do {
195+
@preconcurrency var d = Dictionary<String, any Sendable>()
196+
197+
func test(_ dict: inout Dictionary<String, Any>) {}
198+
test(&d) // Ok
199+
200+
@preconcurrency var a = Array<any Sendable>()
201+
let values: [Any] = []
202+
a += values // Ok
203+
}

test/Interpreter/sendable_erasure_to_any_in_preconcurrency.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ struct Test {
4141
@preconcurrency var funcRef: S<([any Sendable]) -> (any Sendable)?> = S(v: { $0.first })
4242
}
4343

44+
func testInOut(_ dict: inout Dictionary<String, Any>) {
45+
dict["inout"] = "yes"
46+
}
47+
48+
func testInOut(_ arr: inout [Any]) {
49+
arr.append("inout")
50+
}
4451

4552
func test() {
4653
var c = C()
@@ -98,6 +105,19 @@ func test() {
98105

99106
expectsFuncAny(v1.funcRef)
100107
// CHECK: 42
108+
109+
testInOut(&c.dict)
110+
print(c.dict["inout"] ?? "no")
111+
// CHECK: yes
112+
113+
testInOut(&c.arr)
114+
print(c.arr.contains(where: { $0 as? String == "inout" }))
115+
// CHECK: true
116+
117+
var newValues: [Any] = ["other inout"]
118+
c.arr += newValues // checks implicit inout injection via operator
119+
print(c.arr.contains(where: { $0 as? String == "other inout" }))
120+
// CHECK: true
101121
}
102122

103123
test()

test/SILGen/sendable_to_any_for_generic_arguments.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,24 @@ func test_subscript_computed_property_and_mutating_access(u: User) {
261261
// CHECK-NEXT: assign [[COPIED_SENDABLE_DICT]] to [[DICT]]
262262
u.dict.testMutating()
263263
}
264+
265+
// CHECK-LABEL: sil hidden [ossa] @$s37sendable_to_any_for_generic_arguments15test_inout_usesyyF
266+
// CHECK: [[SENDABLE_ARR_REF:%.*]] = begin_access [modify] [unknown] %2
267+
// CHECK-NEXT: [[ANY_ARR:%.*]] = alloc_stack $Array<Any>
268+
// CHECK-NEXT: [[SENDABLE_ARR:%.*]] = load [copy] [[SENDABLE_ARR_REF]]
269+
// CHECK-NEXT: [[ANY_ARR_CAST:%.*]] = unchecked_bitwise_cast [[SENDABLE_ARR]] to $Array<Any>
270+
// CHECK-NEXT: [[ANY_ARR_COPY:%.*]] = copy_value [[ANY_ARR_CAST]]
271+
// CHECK-NEXT: store [[ANY_ARR_COPY]] to [init] [[ANY_ARR]]
272+
// CHECK: [[INOUT_FUNC:%.*]] = function_ref @$s37sendable_to_any_for_generic_arguments15test_inout_usesyyF0G0L_yySayypGzF : $@convention(thin) (@inout Array<Any>) -> ()
273+
// CHECK-NEXT: {{.*}} = apply [[INOUT_FUNC]]([[ANY_ARR]]) : $@convention(thin) (@inout Array<Any>) -> ()
274+
// CHECK-NEXT: [[ANY_ARR_VALUE:%.*]] = load [take] [[ANY_ARR]]
275+
// CHECK-NEXT: [[SENDABLE_ARR_VALUE:%.*]] = unchecked_bitwise_cast [[ANY_ARR_VALUE]] to $Array<any Sendable>
276+
// CHECK-NEXT: [[SENDABLE_ARR_VALUE_COPY:%.*]] = copy_value [[SENDABLE_ARR_VALUE]]
277+
// CHECK-NEXT: assign [[SENDABLE_ARR_VALUE_COPY]] to [[SENDABLE_ARR_REF]]
278+
func test_inout_uses() {
279+
func test(_ arr: inout [Any]) {
280+
}
281+
282+
@preconcurrency var arr: [any Sendable] = []
283+
test(&arr)
284+
}

0 commit comments

Comments
 (0)