-
Notifications
You must be signed in to change notification settings - Fork 10.6k
[TypeChecker] Type wrappers (experimental feature) #60345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Hey @xedin, @Wrapper
struct Person {
var name: String
let age: Int = 0
}Since |
|
@LucianoPAlmeida properties like that are not currently wrapped. |
|
A more interesting example is the one which uses a class as a let e.g.: class X {
var v: Int = 42
}
struct S {
let x: X = X()
}Since var s = S()
s.x.v = 0I think this case would have to be wrapped but it would have to pick different overloads of |
Yeah, from my understanding an overload of let wkp: WritableKeyPath<X, Int> = \.v
let rwkp: ReferenceWritableKeyPath<X, Int> = \.v
let s = S()
s.x[keyPath: wkp] = 0 // error: cannot assign through subscript: 'x' is a let constant
s.x[keyPath: rwkp] = 0 // okIs that what you mean by different overload? |
Yes, it's currently modeled as implicitly generated AST so type wrapper could define multiple overloads of subscript and type-checker would just pick one that works for synthesized code. |
Ah got it, Thanks! |
|
@swift-ci please clean test |
|
@swift-ci please clean test |
|
@swift-ci please clean test |
|
@swift-ci please clean test Linux platform |
|
@swift-ci please test macOS platform |
|
@swift-ci please test Windows platform |
|
@swift-ci please test |
|
@swift-ci please test macOS platform |
2afa6cb to
d5d4338
Compare
`$Storage` type is going to used as a type of `$_storage` variable and contains all of the stored properties of the type it's attached to.
This is the property that would get used to route stored property accesses through a type wrapper.
…pper property Given a stored property associated with a type wrapped type, produce a property that mirrors it in the type wrapper context.
…ped type A getter routes accesses through a subscript of `$_storage` variable injected into a wrapped type.
…ped type A setter routes assignment through a subscript of `$_storage` variable injected into a wrapped type - `$_storage[storageKeyPath: \$Storage.<property>] = newValue`
Compiler cannot synthesize regular memberwise or default initializers for type wrapped types because stored properties of such a type cannot be accessed directly. A special initializer would be synthesized instead, it is going to initialize `$_storage` variable and handle default initialization of stored properties.
…a cached request
Synthesize an `init` declaration which is going to initialize type wrapper instance property `$_storage` via user provided values for all stored properties.
This is important because we need to force existance of the underlying storage at the right moment.
This is important because we need to force existance of the underlying storage at the right moment.
… vars are not transparent Type wrapped variables loose their storage and are accessed through `$Storage` and synthesized accessors cannot be transparent.
All of the stored properties are wrapped which means that their initializers are subsummed and moved to the synthesized `init` as default arguments.
…roperty wrappers Type wrapper doesn't wrap anything expect to a private backing storage property. This means that type wrapper is applied first and subsequent `.wrappedValue` and/or `.projectedValue` is referenced for the returned property wrapper type.
…members Since properties with property wrappers are not supported, default init synthesis needs to handle them as well by using correct interface type depending on outer wrapper capabilities and setting correct default expression.
…ed memberwise `init` If a stored property would be in a default memberwise initializer it would be added to the `init` synthesized for a type wrapped type as well i.e. a `let` property without a default.
… properties as `internal`
|
@swift-ci please test |
Initial implementation of
@typeWrapperattribute which could be used to declare a typeto "wrap" other types by routing all their stored property accesses through itself.
The type wrapper is very similar to a property wrapper but there are couple of fundamental
differences:
$Storagecontainer allocates storage for all of the wrapped properties;Valid type wrapper has to have:
Storage) which would be substituted with storage type;init(memberwise: Storage)- initializer that accepts a generic parameter of underlying storage;subscript<Value>(storageKeyPath path: {Writable, ReferenceWritable}KeyPath<Storage, Value>) -> Value-a subscript that would be called on every applicable property access.
Here is an example of a valid type wrapper declaration:
Now, let's see
Wrapperin action to appreciate how much boiler place it removes:Access to
nameandageof aPersonis going to get routed throughWrappertype.The transformed type looks like this:
All of the boilerplate code required to create and maintain 1-1 storage between type and
Storageand proper initialization is now handled by the compiler.Open questions: