It can't witness for RawRepresentable.rawValue by itself, but since it's public, the compiler can synthesize RawRepresentable.rawValue as a trampoline to P.rawValue.
private protocol P { // notice the absence of 'RawRepresentable' here
init(name: String)
var name: String { get }
}
extension P {
public init(rawValue: String) {
self.init(name: rawValue)
}
public var rawValue: String { self.name }
// none of these are here to satisfy something, they just exist
}
public struct Struct: P {
let name: String
init(name: String) {
self.name = name
}
}
extension Struct: RawRepresentable {
// We need 'init?(rawValue:)' and 'var rawValue: Self.RawValue { get }'.
// In this visibility scope, we see them implemented and accessible because
// 'extension P' declares them as public.
// So we can syntesize the witnesses with simple proxies.
// public init?(rawValue: String) {
// self = Self.`extension P`::init(rawValue: rawValue)
// }
// public var rawValue: String {
// self.`extension P`::rawValue
// }
}
And in SIL you can see that:
- the witness for
RawRepresentable.init(rawValue:) calls P.init(rawValue:)
- the witness for
RawRepresentable.rawValue.getter calls P.rawValue.getter
sil [transparent] [thunk] [ossa] @protocol witness for Swift.RawRepresentable.init(rawValue: A.RawValue) -> A? in conformance output.Struct : Swift.RawRepresentable in output : $@convention(witness_method: RawRepresentable) (@in String, @thick Struct.Type) -> @out Optional<Struct> {
bb0(%0 : $*Optional<Struct>, %1 : $*String, %2 : $@thick Struct.Type):
%3 = load [take] %1, loc * "/app/example.swift":9:10, scope 8 // user: %6
// here
%4 = function_ref @(extension in output):output.(P in _60494E8B9C642A7C4A26F3A3B6CECEB9).init(rawValue: Swift.String) -> A : $@convention(method) <τ_0_0 where τ_0_0 : P> (@owned String, @thick τ_0_0.Type) -> @out τ_0_0, loc * "/app/example.swift":9:10, scope 8 // user: %6
%5 = alloc_stack $Struct, loc * "/app/example.swift":9:10, scope 8 // users: %11, %7, %6
%6 = apply %4<Struct>(%5, %3, %2) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@owned String, @thick τ_0_0.Type) -> @out τ_0_0, loc * "/app/example.swift":9:10, scope 8
%7 = load [take] %5, loc * "/app/example.swift":9:10, scope 8 // user: %8
%8 = enum $Optional<Struct>, #Optional.some!enumelt, %7, loc * "/app/example.swift":9:10, scope 8 // user: %9
store %8 to [init] %0, loc * "/app/example.swift":9:10, scope 8 // id: %9
%10 = tuple (), loc * "/app/example.swift":9:10, scope 8 // user: %12
dealloc_stack %5, loc * "/app/example.swift":11:3, scope 8 // id: %11
return %10, loc * "/app/example.swift":9:10, scope 8 // id: %12
} // end sil function 'protocol witness for Swift.RawRepresentable.init(rawValue: A.RawValue) -> A? in conformance output.Struct : Swift.RawRepresentable in output'
sil [transparent] [thunk] [ossa] @protocol witness for Swift.RawRepresentable.rawValue.getter : A.RawValue in conformance output.Struct : Swift.RawRepresentable in output : $@convention(witness_method: RawRepresentable) (@in_guaranteed Struct) -> @out String {
bb0(%0 : $*String, %1 : $*Struct):
// here
%2 = function_ref @(extension in output):output.(P in _60494E8B9C642A7C4A26F3A3B6CECEB9).rawValue.getter : Swift.String : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned String, loc * "/app/example.swift":12:31, scope 9 // user: %3
%3 = apply %2<Struct>(%1) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned String, loc * "/app/example.swift":12:31, scope 9 // user: %4
store %3 to [init] %0, loc * "/app/example.swift":12:31, scope 9 // id: %4
%5 = tuple (), loc * "/app/example.swift":12:31, scope 9 // user: %6
return %5, loc * "/app/example.swift":12:31, scope 9 // id: %6
} // end sil function 'protocol witness for Swift.RawRepresentable.rawValue.getter : A.RawValue in conformance output.Struct : Swift.RawRepresentable in output'
(Compiler Explorer)
If they were fileprivate, you'd have to do that manually.