Merge pull request #77816 from xedin/fix-property-wrapper-projected-value-applies

[CSApply] Avoid shortcutting argument conversion when parameter has a…
This commit is contained in:
Pavel Yaskevich
2024-12-02 13:52:30 -08:00
committed by GitHub
3 changed files with 77 additions and 2 deletions

View File

@@ -5,6 +5,29 @@
## Swift 6.1
* Projected value initializers are now correctly injected into calls when
an argument exactly matches a parameter with an external property wrapper.
For example:
```swift
struct Binding {
...
init(projectedValue: Self) { ... }
}
func checkValue(@Binding value: Int) {}
func use(v: Binding<Int>) {
checkValue($value: v)
// Transformed into: `checkValue(value: Binding(projectedValue: v))`
}
```
Previous versions of the Swift compiler incorrectly omitted projected value
initializer injection in the call to `checkValue` because the argument type
matched the parameter type exactly.
* [SE-0444][]:
When the upcoming feature `MemberImportVisibility` is enabled, Swift will
require that a module be directly imported in a source file when resolving

View File

@@ -1264,6 +1264,8 @@ namespace {
args.emplace_back(SourceLoc(), calleeParam.getLabel(), paramRef);
}
ASSERT(appliedWrapperIndex == appliedPropertyWrappers.size());
// SILGen knows how to emit property-wrapped parameters, but the
// corresponding parameter types need to match the backing wrapper types.
// To handle this, build a new callee function type out of the adjusted
@@ -6288,9 +6290,17 @@ ArgumentList *ExprRewriter::coerceCallArguments(
// `sending` parameter etc.
applyFlagsToArgument(paramIdx, argExpr);
// If the types exactly match, this is easy.
auto canShortcutConversion = [&](Type argType, Type paramType) {
if (shouldInjectWrappedValuePlaceholder ||
paramInfo.hasExternalPropertyWrapper(paramIdx))
return false;
return argType->isEqual(paramType);
};
auto paramType = param.getOldType();
if (argType->isEqual(paramType) && !shouldInjectWrappedValuePlaceholder) {
if (canShortcutConversion(argType, paramType)) {
newArgs.push_back(arg);
continue;
}

View File

@@ -537,3 +537,45 @@ func testCaptures(@ClassWrapper ref: Int, @Wrapper value: Int) {
// closure #2 in closure #2 in implicit closure #2 in testCaptures(ref:value:)
// CHECK-LABEL: sil private [ossa] @$s26property_wrapper_parameter12testCaptures3ref5valueySi_AA7WrapperVySiGtFyAA010ProjectionH0VySiGcfu0_yAJcfU1_AJycfU0_ : $@convention(thin) (ProjectionWrapper<Int>) -> ProjectionWrapper<Int>
}
do {
@propertyWrapper
struct Binding<Value> {
var wrappedValue: Value {
get { fatalError() }
nonmutating set { }
}
var projectedValue: Self { self }
init(projectedValue: Self) { self = projectedValue }
}
final class Value {
enum Kind {
}
var kind: Binding<Kind> {
fatalError()
}
}
struct Test {
var value: Value
// CHECK-LABEL: sil private [ossa] @$s26property_wrapper_parameter4TestL_V4test5otheryAA7BindingL_VyAA5ValueL_C4KindOG_tF : $@convention(method) (Binding<Value.Kind>, @guaranteed Test) -> ()
// CHECK: [[CHECK_PROJECTED_VALUE_INIT_1:%.*]] = function_ref @$s26property_wrapper_parameter4TestL_V9checkKind4kindyAA7BindingL_VyAA5ValueL_C0F0OG_tFAEL_AKvpfW
// CHECK-NEXT: {{.*}} = apply [[CHECK_PROJECTED_VALUE_INIT_1]]({{.*}}) : $@convention(thin) (Binding<Value.Kind>) -> Binding<Value.Kind>
// CHECK: [[CHECK_PROJECTED_VALUE_INIT_A:%.*]] = function_ref @$s26property_wrapper_parameter4TestL_V15doubleCheckKind1a1byAA7BindingL_VyAA5ValueL_C0G0OG_AMtFAEL_ALvpfW
// CHECK-NEXT: {{.*}} = apply [[CHECK_PROJECTED_VALUE_INIT_A]]({{.*}}) : $@convention(thin) (Binding<Value.Kind>) -> Binding<Value.Kind>
// CHECK: [[CHECK_PROJECTED_VALUE_INIT_B:%.*]] = function_ref @$s26property_wrapper_parameter4TestL_V15doubleCheckKind1a1byAA7BindingL_VyAA5ValueL_C0G0OG_AMtFAFL_ALvpfW
// CHECK-NEXT: {{.*}} = apply [[CHECK_PROJECTED_VALUE_INIT_B]]({{.*}}) : $@convention(thin) (Binding<Value.Kind>) -> Binding<Value.Kind>
func test(other: Binding<Value.Kind>) {
checkKind($kind: value.kind) // Ok
doubleCheckKind($a: value.kind, $b: other) // Ok
}
func checkKind(@Binding kind: Value.Kind) {}
func doubleCheckKind(@Binding a: Value.Kind, @Binding b: Value.Kind) {}
}
}