This does not eliminate the entrypoints on SILBuilder yet. I want to do this in
two parts so that it is functionally easier to disentangle changing the APIs
above SILBuilder and changing the underlying instruction itself.
rdar://33440767
Most of this patch is just removing special cases for materializeForSet
or other fairly mechanical replacements. Unfortunately, the rest is
still a fairly big change, and not one that can be easily split apart
because of the quite reasonable reliance on metaprogramming throughout
the compiler. And, of course, there are a bunch of test updates that
have to be sync'ed with the actual change to code-generation.
This is SR-7134.
ConvertFunction and reabstraction thunks need this attribute. Otherwise,
there is no way to identify that withoutActuallyEscaping was used
to explicitly perform a conversion.
The destination of a [without_actually_escaping] conversion always has
an escaping function type. The source may have either an escaping or
@noescape function type. The conversion itself may be a nop, and there
is nothing distinctive about it. The thing that is special about these
conversions is that the source function type may have unboxed
captures. i.e. they have @inout_aliasable parameters. Exclusivity
requires that the compiler enforce a SIL data flow invariant that
nonescaping closures with unboxed captures can never be stored or
passed as an @escaping function argument. Adding this attribute allows
the compiler to enforce the invariant in general with an escape hatch
for withoutActuallyEscaping.
Instead of serializing the input type of a function type, which is a
TupleType or ParenType, serialize the individual parameters instead.
This means that we no longer need to serialize TupleTypes or
ParenTypes with custom flags, nor do we ever serialize standalone
InOutTypes, so all of that can be removed.
We can recover function, destructor, constructor, enum element
and subscript types from their parameter types and result type
(if present), by calling the AST's various computeType()
methods.
These methods don't do any more work than would be done if
we had deserialized the type and reconstructed it, so let's
just recompute it instead.
Note that we still serialize a ton of function types, due
to XREFs.
With my build configuration, this reduces the size of
Swift.swiftmodule by 237KiB (out of 20MiB).
SILFunctions no longer have a GenericParamList, so all of these
circularity and ordering problems are gone.
We *do* deserialize the generic parameters before creating decls
that have them though, so serialize generic parameters as if
their DeclContext was the DeclContext of the owner decl.
This is what we do when we parse generic parameters too; in
both cases, the constructor for the owner decl gives the
generic parameters the right DeclContext.
This allows us to dump it in the generated interface, though it's
still not syntax-highlighted. This is necessary for textual module
interfaces, but it's also just a longstanding request for Xcode's
"Generated Interface" / "Jump to Definition" feature.
rdar://problem/18675831
Way back in 6afe77d597 Chris removed the 'Parameter' type that tracked
extra information about parameters, collapsing it into ParamDecl and
making ParameterList "an overblown array of ParamDecl*'s". Do the same
thing for Serialization: push the few fields tracked in
PARAMETERLIST_ELT records down into PARAM_DECL, and then simplify the
PARAMETERLIST record to directly reference its parameters.
No functionality change.
We previously shied away from this in order to not /accidentally/
depend on it, but it becomes interesting again with textual
interfaces, which can certainly be read by humans. The cross-file
order is the order of input files, which is at least controllable by
users.
For now, the accessors have been underscored as `_read` and `_modify`.
I'll prepare an evolution proposal for this feature which should allow
us to remove the underscores or, y'know, rename them to `purple` and
`lettuce`.
`_read` accessors do not make any effort yet to avoid copying the
value being yielded. I'll work on it in follow-up patches.
Opaque accesses to properties and subscripts defined with `_modify`
accessors will use an inefficient `materializeForSet` pattern that
materializes the value to a temporary instead of accessing it in-place.
That will be fixed by migrating to `modify` over `materializeForSet`,
which is next up after the `read` optimizations.
SIL ownership verification doesn't pass yet for the test cases here
because of a general fault in SILGen where borrows can outlive their
borrowed value due to being cleaned up on the general cleanup stack
when the borrowed value is cleaned up on the formal-access stack.
Michael, Andy, and I discussed various ways to fix this, but it seems
clear to me that it's not in any way specific to coroutine accesses.
rdar://35399664
The other side of #17404. Since we don't want to generate up front key path metadata for properties/subscripts with no withheld implementation details, the client should generate a key path component that can be used to represent a key path component based on its public interface.
The storage kind has been replaced with three separate "impl kinds",
one for each of the basic access kinds (read, write, and read/write).
This makes it far easier to mix-and-match implementations of different
accessors, as well as subtleties like implementing both a setter
and an independent read/write operation.
AccessStrategy has become a bit more explicit about how exactly the
access should be implemented. For example, the accessor-based kinds
now carry the exact accessor intended to be used. Also, I've shifted
responsibilities slightly between AccessStrategy and AccessSemantics
so that AccessSemantics::Ordinary can be used except in the sorts of
semantic-bypasses that accessor synthesis wants. This requires
knowing the correct DC of the access when computing the access strategy;
the upshot is that SILGenFunction now needs a DC.
Accessor synthesis has been reworked so that only the declarations are
built immediately; body synthesis can be safely delayed out of the main
decl-checking path. This caused a large number of ramifications,
especially for lazy properties, and greatly inflated the size of this
patch. That is... really regrettable. The impetus for changing this
was necessity: I needed to rework accessor synthesis to end its reliance
on distinctions like Stored vs. StoredWithTrivialAccessors, and those
fixes were exposing serious re-entrancy problems, and fixing that... well.
Breaking the fixes apart at this point would be a serious endeavor.
We sometimes serialized the “isObjC” state, and sometimes not. When we did serialize it,
we rarely used the bit for anything. Serialize it for all declarations where it makes
sense, and consistently call setIsObjC() with the deserialized value.
The major important thing here is that by using copy_unowned_value we can
guarantee that the non-ownership SIL ARC optimizer will treat the release
associated with the strong_retain_unowned as on a distinc rc-identity from its
argument. As an example of this problem consider the following SILGen like
output:
----
%1 = copy_value %0 : $Builtin.NativeObject
%2 = ref_to_unowned %1
%3 = copy_unowned_value %2
destroy_value %1
...
destroy_value %3
----
In this case, we are converting a strong reference to an unowned value and then
lifetime extending the value past the original value. After eliminating
ownership this lowers to:
----
strong_retain %0 : $Builtin.NativeObject
%1 = ref_to_unowned %0
strong_retain_unowned %1
strong_release %0
...
strong_release %0
----
From an RC identity perspective, we have now blurred the lines in between %3 and
%1 in the previous example. This can then result in the following miscompile:
----
%1 = ref_to_unowned %0
strong_retain_unowned %1
...
strong_release %0
----
In this case, it is possible that we created a lifetime gap that will then cause
strong_retain_unowned to assert. By not lowering copy_unowned_value throughout
the SIL pipeline, we instead get this after lowering:
----
strong_retain %0 : $Builtin.NativeObject
%1 = ref_to_unowned %0
%2 = copy_unowned_value %1
strong_release %0
...
strong_release %2
----
And we do not miscompile since we preserved the high level rc identity
pairing.
There shouldn't be any performance impact since we do not really optimize
strong_retain_unowned at the SIL level. I went through all of the places that
strong_retain_unowned was referenced and added appropriate handling for
copy_unowned_value.
rdar://41328987
**NOTE** I am going to remove strong_retain_unowned in a forthcoming commit. I
just want something more minimal for cherry-picking purposes.
Cross-references are identified by their containing module, with the
assumption that two modules will never have the same name. However, an
overlay has the same name as its underlying Clang module, which means
that there can be two declarations with the same name, the same type,
and the same module name. This is the underlying cause of the
'UIEdgeInsetsZero' problem, but it also affects the CloudKit overlay.
By tracking a bit that just says "this came from Clang", we're able
to resolve otherwise ambiguous cross-references.
(Why didn't we do it this way all along? Because if a declaration
moves from Clang to Swift or vice versa, that would break the
cross-reference. But that's only interesting if the swiftmodule format
is meant to be persistent across changing dependencies, and it looks
like we're moving away from that anyway. It's also a little weird for
SerializedModuleLoader to have special cases for Clang, but this isn't
the first.)
Note that I'm not reverting the UIEdgeInsetsZero workaround here; the
end state will have that coming just from UIKit as originally
described.
rdar://problem/40839486
Introduce some metaprogramming of accessors and generally prepare
for storing less-structured accessor lists.
NFC except for a change to the serialization format.
This flag supports promoting KeyPath access violations to an error in
Swift 4+, while building the standard library in Swift 3 mode. This is
only necessary as long as the standard library continues to build in
Swift 3 mode. Once the standard library build migrates, it can all be
ripped out.
<rdar://problem/40115738> [Exclusivity] Enforce Keypath access as an error, not a warning in 4.2.
This reverts commit bb16ee049d,
reversing changes made to a8d831f5f5.
It's not sufficient to solve the problem, and the choices were to do
something more complicated, or just take a simple brute force
approach. We're going with the latter.
Mandatory pass will clean it up and replace it by a copy_block and
is_escaping/cond_fail/release combination on the %closure in follow-up
patches.
The instruction marks the dependence of a block on a closure that is
used as an 'withoutActuallyEscaping' sentinel.
rdar://39682865
Convert NameAliasType’s internal representation from tail-allocating an
array of Substitutions (to be treated as a SubstitutionList) to store a
single SubstitutionMap. Serialize using that SubstitutionMap.
Allow substitution maps to be serialized directly (via an ID), writing out
the replacement types and conformances as appropriate. This is a more
efficient form of serialization than the current SubstitutionList approach,
because it maintains uniqueness of substitution maps within a module file,
and is a step toward eliminating SubstitutionList entirely.
Add serialization layouts for rare instructions that take extra attributes. We
can continue adding bits to these layout without affecting the layout of the
vast majority of instructions.
We still use the old layout for NameAliasType for builtin types, so
rename the Layout struct and corresponding code to describe its new
(more restricted) purpose.
Introduce a new Type node, BoundNameAliasType, which describes a
reference to a typealias that requires substitutions to produce the
underlying type. This new type node is used both for references to
generic typealiases and for references to (non-generic) typealiases
that occur within generic contexts, e.g., Array<Int>.Element.
At present, the new type node is mainly useful in preserving type
sugar for diagnostics purposes, as well as being reflected in other
tools (indexing, code completion, etc.). The intent is to completely
replace NameAliasType in the future.
We have a predicate in ClassDecl, 'inheritsSuperclassInitializers',
that is used in a few places to decide if we need to do lookups into a
superclass to find all relevant initializers. That's useful, but the
actual work being computed in that function is almost identical to the
work done in figuring out whether the class has provided all its
superclass's /required/ initializers, which is part of the type
checker operation 'resolveImplicitConstructors'. Furthermore,
'inheritsSuperclassInitializers' is /already/ calling
'resolveImplicitConstructors' because those implicit constructors
might affect the result.
Simplify this whole mess and prevent further inconsistencies like the
previous commit by just making 'resolveImplicitConstructors' decide
whether superclass convenience initializers are inherited. It does
make that function more complicated, but with the benefit of not
having duplication anymore.
No intended user-visible change, except that this bit is now
serialized instead of being recomputed, which means the module format
changed.