ModuleInterface: Only print API-level property wrappers in swiftinterfaces.

When a function parameter has attached property wrappers (SE-0293) those
property wrappers are either considered "implementation" or "API" level.
Property wrappers that are implementation-level don't affect how the function
is called and therefore shouldn't be included in swiftinterfaces unless the
function's body is also printed.

Resolves rdar://156711817.
This commit is contained in:
Allan Shortlidge
2025-08-27 21:34:01 -07:00
parent c654ad459c
commit 441132426f
2 changed files with 58 additions and 15 deletions

View File

@@ -1417,7 +1417,20 @@ void PrintAST::printAttributes(const Decl *D) {
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Consuming); scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Consuming);
scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Borrowing); scope.Options.ExcludeAttrList.push_back(DeclAttrKind::Borrowing);
} }
// If we're printing a swiftinterface and the attached property wrappers don't
// have an external effect, skip them.
if (Options.IsForSwiftInterface) {
if (auto *PD = dyn_cast<ParamDecl>(D)) {
if (!PD->hasExternalPropertyWrapper() &&
PD->getDeclContext()->getResilienceExpansion() !=
ResilienceExpansion::Minimal) {
for (auto *attr : PD->getAttachedPropertyWrappers())
scope.Options.ExcludeCustomAttrList.push_back(attr);
}
}
}
attrs.print(Printer, Options, D); attrs.print(Printer, Options, D);
} }

View File

@@ -9,34 +9,46 @@
@propertyWrapper @propertyWrapper
public struct Wrapper<T> { public struct Wrapper<T> {
public var value: T public var wrappedValue: T
public var wrappedValue: T { public init(wrappedValue: T) {
get { value } self.wrappedValue = wrappedValue
set { value = newValue }
} }
} }
@propertyWrapper @propertyWrapper
public struct WrapperWithInitialValue<T> { public struct WrapperWithInitialValue<T> {
private var value: T public var wrappedValue: T
public var wrappedValue: T {
get { value }
set { value = newValue }
}
public init(initialValue: T) { public init(initialValue: T) {
self.value = initialValue self.wrappedValue = initialValue
} }
public init(alternate value: T) { public init(alternate value: T) {
self.value = value self.wrappedValue = value
} }
public var projectedValue: Wrapper<T> { public var projectedValue: Wrapper<T> {
get { Wrapper(value: value) } get { Wrapper(wrappedValue: wrappedValue) }
set { value = newValue.value } set { wrappedValue = newValue.wrappedValue }
}
}
@propertyWrapper
public struct ProjectedValueWrapper<T> {
public var wrappedValue: T
public init(wrappedValue: T) {
self.wrappedValue = wrappedValue
}
public init(projectedValue: Wrapper<T>) {
self.wrappedValue = projectedValue.wrappedValue
}
public var projectedValue: Wrapper<T> {
get { Wrapper(wrappedValue: wrappedValue) }
set { wrappedValue = newValue.wrappedValue }
} }
} }
@@ -64,4 +76,22 @@ public struct HasWrappers {
// CHECK-NEXT: _modify // CHECK-NEXT: _modify
// CHECK-NEXT: } // CHECK-NEXT: }
@WrapperWithInitialValue(alternate: false) public var z @WrapperWithInitialValue(alternate: false) public var z
// CHECK: public func hasParameterWithImplementationWrapper(x: Swift.Int)
public func hasParameterWithImplementationWrapper(@Wrapper x: Int) { }
// CHECK: public func hasParameterWithImplementationWrapperComposed(x: Swift.Int)
public func hasParameterWithImplementationWrapperComposed(@Wrapper @ProjectedValueWrapper x: Int) { }
// CHECK: @inlinable public func hasParameterWithImplementationWrapperInlinable(@TestResilient.Wrapper x: Swift.Int)
@inlinable public func hasParameterWithImplementationWrapperInlinable(@Wrapper x: Int) { }
// CHECK: @_alwaysEmitIntoClient public func hasParameterWithImplementationWrapperAEIC(@TestResilient.Wrapper x: Swift.Int)
@_alwaysEmitIntoClient public func hasParameterWithImplementationWrapperAEIC(@Wrapper x: Int) { }
// CHECK: public func hasParameterWithAPIWrapper(@TestResilient.ProjectedValueWrapper x: Swift.Int)
public func hasParameterWithAPIWrapper(@ProjectedValueWrapper x: Int) { }
// CHECK: public func hasParameterWithAPIWrapperComposed(@TestResilient.ProjectedValueWrapper @TestResilient.Wrapper x: Swift.Int)
public func hasParameterWithAPIWrapperComposed(@ProjectedValueWrapper @Wrapper x: Int) { }
} }