mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
23
CHANGELOG.md
23
CHANGELOG.md
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user