The witness table had shared linkage, but we weren't serializing them,
which would cause linking errors if we emitted a reference to such a
witness table from a different module than the one where it was first
defined, as a result of deserializing and optimizing SIL.
This issue was introduced when SIL witness table serialization was
made conditional on the -sil-serialize-witness-tables flag, which is
normally only enabled for the standard library.
When the flag was added, existing tests were updated to pass the
flag, which masked the issue. Remove the flag from existing tests,
ensure that imported witness tables are still [serialized], and add
a new test specifically for the behavior enabled by this flag.
We used to give witness thunks public linkage if the
conforming type and the protocol are public.
This is completely unnecessary. If the conformance is
fragile, the thunk should be [shared] [serialized],
allowing the thunk to be serialized into callers after
devirtualization.
Otherwise for private protocols or resilient modules,
witness thunks can just always be private.
This should reduce the size of compiled binaries.
There are two other mildly interesting consequences:
1) In the bridged cast tests, we now inline the witness
thunks from the bridgeable conformances, which removes
one level of indirection.
2) This uncovered a flaw in our accessibility checking
model. Usually, we reject a witness that is less
visible than the protocol; however, we fail to
reject it in the case that it comes from an
extension.
This is because members of an extension can be
declared 'public' even if the extended type is not
public, and it appears that in this case the 'public'
keyword has no effect.
I would prefer it if a) 'public' generated a warning
here, and b) the conformance also generated a warning.
In Swift 4 mode, we could then make this kind of
sillyness into an error. But for now, live with the
broken behavior, and add a test to exercise it to ensure
we don't crash.
There are other places where this "allow public but
ignore it, kinda, except respect it in some places"
behavior causes problems. I don't know if it was intentional
or just emergent behavior from general messiness in Sema.
3) In the TBD code, there is one less 'failure' because now
that witness thunks are no longer public, TBDGen does not
need to reason about them (except for the case #2 above,
which will probably require a similar workaround in TBDGen
as what I put into SILGen).
Also, add a third [serializable] state for functions whose bodies we
*can* serialize, but only do so if they're referenced from another
serialized function.
This will be used for bodies synthesized for imported definitions,
such as init(rawValue:), etc, and various thunks, but for now this
change is NFC.
Instead of appending a character for each substitution, we now prefix the substitution with the repeat count, e.g.
AbbbbB -> A5B
The same is done for known-type substitutions, e.g.
SiSiSi -> S3i
This significantly shrinks mangled names which contain large lists of the same type, like
func foo(_ x: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int))
rdar://problem/30707433
First, use the correct generic environment to compute the substituted
storage type. Substitutions derived from 'self' are not enough,
because we also want the archetypes of the generic subscript's
innermost generic parameters.
Also, use the method and witness_method calling conventions for the
materializeForSet callback, depending on if we have a protocol
witness or concrete implementation.
Since the materializeForSet callback is called with a more
abstract type at the call site than the actual function type
of the callback, we used to rely on these two SIL types being
ABI compatible:
@convention(thin) <Self : P, T, U) (..., Self.Type) -> ()
@convention(thin) <T, U> (..., Foo<T, U>.Type) -> ()
The IRGen lowering is roughly the following -- the call site
passes two unused parameters, but that's fine:
(..., Self.Type*, Self.Type*, Self.P*)
(..., Foo<T, U>.Type*)
However if the callback has its own generic parameters because
the subscript is generic, we might have SIL types like so,
@convention(thin) <Self : P, T, U, V) (..., Self.Type) -> ()
@convention(thin) <T, U, V> (..., Foo<T, U>.Type) -> ()
And the IRGen lowering is the following:
(..., Self.Type*, Self.Type*, Self.P*, V.Type*)
(..., Foo<T, U>.Type*, V.Type*)
The parameters no longer line up, because the caller still passes
the two discarded arguments, and type metadata for V cannot be
derived from the Self metadata so must be passed separately.
The witness_method calling convention is designed to solve this
problem; it puts the Self metadata and protocol conformance last,
so if you have these SIL types:
@convention(witness_method) <Self : P, T, U, V) (..., swiftself Self.Type) -> ()
@convention(witness_method) <T, U, V> (..., swiftself Foo<T, U>.Type) -> ()
The IRGen lowering is the following:
(..., Self.Type*, V.Type*, Self.Type*, Self.P*)
(..., Foo<T, U>.Type*, V.Type*, Self.Type*, unused i8*)
However, the problem is now that witness_method and thin functions
are not ABI compatible, because thin functions don't have a
distinguished 'self', which is passed differently in LLVM's swiftcc
calling convention:
@convention(witness_method) <Self : P, T, U, V) (..., Self.Type) -> ()
@convention(thin) <T, U, V> (..., Foo<T, U>.Type) -> ()
So instead of using 'thin' representation for the concrete callback
case, use 'method', which is essentially the same as 'thin' except if
the last parameter is pointer-size, it is passed as the 'self' value.
This makes everything work out.
In 74d979f0ac, the policy was changed
so that only value type accessors are ever marked transparent, and
not class accessors.
This was intended to fix a bug where inlining an accessor of an
Objective-C-derived class across module boundaries caused a linker
failure because the accessor referenced a field offset variable,
which has hidden visibility.
However, this also caused a performance regression for Swift native
classes. Bring back the old behavior for Swift native classes in
non-resilient modules.
Fixes <rdar://problem/29884727>.
One minor revision: this lifts the proposed restriction against
overriding a non-open method with an open one. On reflection,
that was inconsistent with the existing rule permitting non-public
methods to be overridden with public ones. The restriction on
subclassing a non-open class with an open class remains, and is
in fact consistent with the existing access rule.
Also, mark witness thunks for [fragile] witnesses as [fragile].
This allows us to serialize the witness table, as well as any thunks
for witnesses declared @_transparent and @inline(__always).
The function pointer is a thin function and possibly polymorphic,
so it does not really have an AST type. Instead of pretending it has
an AST type, just return a RawPointer and remove some casts in the
process.