This restriction came from wanting to make resilient and non-resilient
code follow the same rules whenever possible, but after thinking about
it a bit more we realized there was no reason why you /wouldn't/ just
mark your structs @_fixed_layout in non-resilient libraries anyway.
Since that (currently?) doesn't affect what you can do with the struct
across module boundaries, and since the layout of the struct is
available anyway in a non-resilient library, there's no real downside,
which means it's a meaningless restriction.
The same logic doesn't /quite/ apply to classes, since classes are
normally much more flexible than structs. (For example, you could add
a stored property to a class without recompiling clients, as long as
no initializers are inlined.) But it's close enough that we don't want
to put in the restriction at this time.
All of this is about attributes that haven't been finalized yet anyway
(hence the leading underscore), but it's still useful information.
rdar://problem/37408668
This is technically a source break, but the @_fixed_layout attribute
is not official yet. If anyone really cares, we can make this
conditional on -swift-version 5 later, but I'd rather not.
This change is necessary so that we can give property initializers
non-public linkage. Currently they are public, because they can be
referenced from inlinable initializers.
Now that property initializers inside a @_fixed_layout type can
only reference public symbols, they no longer have to be public,
but making that change requires a bit more work.
Now that struct initializers "just" fall into the delegating case when
they're made inlinable, the only interesting case is class
initializers, which can be checked in a more direct way than what we
were doing before.
(and when the struct in question is non-fixed-layout, which was
already implemented)
This ensures that these initializers are never fieldwise in Swift 5
mode, which makes it safe for library authors to add new fields.
Initializers for non-fixed-layout structs that are inlinable or
are defined in a different module are treated as delegating
initializers.
Previously, only initializers containing a 'self.init' call were
delegating; initializers that assigned to 'self' were not, which
resulted in DI treating them as a root initializer where the
stored 'self' value was exploded into a series of stores to each
stored property member.
They were not resilient as a result.
Fixes <https://bugs.swift.org/browse/SR-5649>,
<rdar://problem/33767516>.
Value type initializers must initialize stored properties directly
if they do not delegate to another initializer via self.init().
Since direct stored property access is not permitted for resilient
value types from outside their resilience domain, this means that
such initializers are prohibited in two cases:
- If the initializer is defined in an extension from outside the
value type's resilience domain
- If the initializer is public and @_inlineable, since it might get
inlined outside the value type's resilience domain
Right now, such initializers cannot *assign* to self either;
I filed <https://bugs.swift.org/browse/SR-3686> to track the issue.