Skip to content

Commit 96f484b

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 (cherry picked from commit 484e0a7)
1 parent c3061e9 commit 96f484b

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
@@ -7468,6 +7468,19 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
74687468
/*isImplicit*/ true));
74697469
}
74707470

7471+
case TypeKind::InOut: {
7472+
auto *inOutExpr = getAsExpr<InOutExpr>(expr);
7473+
if (!inOutExpr)
7474+
break;
7475+
7476+
// If there is an `any Sendable` -> `Any` mismatch here,
7477+
// the conversion should be performed on l-value and the
7478+
// address taken from that. This is something that is already
7479+
// done as part of implicit `inout` injection for operators
7480+
// and could be reused here.
7481+
return coerceToType(inOutExpr->getSubExpr(), toType, locator);
7482+
}
7483+
74717484
case TypeKind::Pack:
74727485
case TypeKind::PackElement: {
74737486
llvm_unreachable("Unimplemented!");
@@ -7819,7 +7832,6 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
78197832
#define TYPE(Name, Parent)
78207833
#include "swift/AST/TypeNodes.def"
78217834
case TypeKind::Error:
7822-
case TypeKind::InOut:
78237835
case TypeKind::Module:
78247836
case TypeKind::Enum:
78257837
case TypeKind::Struct:

lib/Sema/CSSimplify.cpp

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

36693669
for (unsigned i = 0, n = path.size(); i < n; ++i) {
36703670
const auto &elt = path[i];
3671-
if (elt.is<LocatorPathElt::GenericType>()) {
3671+
if (elt.is<LocatorPathElt::GenericType>() ||
3672+
elt.is<LocatorPathElt::LValueConversion>()) {
36723673
if (!dropFromIdx)
36733674
dropFromIdx = i;
36743675
continue;
@@ -3709,6 +3710,12 @@ static bool matchSendableExistentialToAnyInGenericArgumentPosition(
37093710
return isPreconcurrencyContext(
37103711
cs.getConstraintLocator(simplifyLocatorToAnchor(locator)));
37113712

3713+
if (locator->directlyAt<InOutExpr>()) {
3714+
auto *IOE = castToExpr<InOutExpr>(locator->getAnchor());
3715+
return isPreconcurrencyContext(
3716+
cs.getConstraintLocator(IOE->getSubExpr()));
3717+
}
3718+
37123719
auto *calleeLoc = cs.getCalleeLocator(locator);
37133720
if (!calleeLoc)
37143721
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)