This change has a subtle impact on debug info emission and causes
a regression with a subsequent patch I'm about to commit.
This reverts commit 62d1adb409.
We had two predicates that were used to determine whether the default
argument for a wrapped property in the memberwise initializer would be
of the wrapper type (e.g., Lazy<Int>) vs. the wrapped type
(Int). Those two predicates could disagree, causing a SILGen assertion
and crash. Collapse the two predicates into one correct one,
fixing rdar://problem/57545381.
https://forums.swift.org/t/improving-the-representation-of-polymorphic-interfaces-in-sil-with-substituted-function-types/29711
This prepares SIL to be able to more accurately preserve the calling convention of
polymorphic generic interfaces by letting the type system represent "substituted function types".
We add a couple of fields to SILFunctionType to support this:
- A substitution map, accessed by `getSubstitutions()`, which maps the generic signature
of the function to its concrete implementation. This will allow, for instance, a protocol
witness for a requirement of type `<Self: P> (Self, ...) -> ...` for a concrete conforming
type `Foo` to express its type as `<Self: P> (Self, ...) -> ... for <Foo>`, preserving the relation
to the protocol interface without relying on the pile of hacks that is the `witness_method`
protocol.
- A bool for whether the generic signature of the function is "implied" by the substitutions.
If true, the generic signature isn't really part of the calling convention of the function.
This will allow closure types to distinguish a closure being passed to a generic function, like
`<T, U> in (*T, *U) -> T for <Int, String>`, from the concrete type `(*Int, *String) -> Int`,
which will make it easier for us to differentiate the representation of those as types, for
instance by giving them different pointer authentication discriminators to harden arm64e
code.
This patch is currently NFC, it just introduces the new APIs and takes a first pass at updating
code to use them. Much more work will need to be done once we start exercising these new
fields.
This does bifurcate some existing APIs:
- SILFunctionType now has two accessors to get its generic signature.
`getSubstGenericSignature` gets the generic signature that is used to apply its
substitution map, if any. `getInvocationGenericSignature` gets the generic signature
used to invoke the function at apply sites. These differ if the generic signature is
implied.
- SILParameterInfo and SILResultInfo values carry the unsubstituted types of the parameters
and results of the function. They now have two APIs to get that type. `getInterfaceType`
returns the unsubstituted type of the generic interface, and
`getArgumentType`/`getReturnValueType` produce the substituted type that is used at
apply sites.
Switch most callers to explicit indices. The exceptions lie in things that needs to manipulate the parsed output directly including the Parser and components of the ASTScope. These are included as friend class exceptions.
Before using the capture info, SILGen now asserts that it has computed, except for declarations which are not in a local context and therefore can’t have captures.
This causes failures in REPL tests, but they are actual failures—there’s a bug in TypeCheckREPL.
Since getSpecifier() now kicks off a request instead of always
returning what was previously set, we can't pass a ParamSpecifier
to the ParamDecl constructor anymore. Instead, callers either
call setSpecifier() if the ParamDecl is synthesized, or they
rely on the request, which can compute the specifier in three
specific cases:
- Ordinary parsed parameters get their specifier from the TypeRepr.
- The 'self' parameter's specifier is based on the self access kind.
- Accessor parameters are either the 'newValue' parameter of a
setter, or a cloned subscript parameter.
For closure parameters with inferred types, we still end up
calling setSpecifier() twice, once to set the initial defalut
value and a second time when applying the solution in the
case that we inferred an 'inout' specifier. In practice this
should not be a big problem because expression type checking
walks the AST in a pre-determined order anyway.
Teach SILGen to emit a separate SIL function to capture the
initialization of the backing storage type for a wrapped property
based on the wrapped value. This eliminates manual code expansion at
every use site.
Unfortuantely this commit is bigger than I would like but I couldn't think
of any reasonable ways to split it up.
The general idea here is that capture computation is now done for a
SILDeclRef and not an AnyFunctionRef. This allows SIL to represent the
captures of a default argument generator.
Most of AST, Parse, and Sema deal with FileUnits regularly, but SIL
and IRGen certainly don't. Split FileUnit out into its own header to
cut down on recompilation times when something changes.
No functionality change.
This improves on the previous situation:
- The request ensures that the backing storage for lazy properties
and property wrappers gets synthesized first; previously it was
only somewhat guaranteed by callers.
- Instead of returning a range this just returns an ArrayRef,
which simplifies clients.
- Indexing into the ArrayRef is O(1), which addresses some FIXMEs
in the SIL optimizer.
The new analysis simply checks if the captured value has been defined
yet; instead of asserting if it hasn't, we can now emit a diagnostic
using the source location tracked in the capture list.
Fixes <https://bugs.swift.org/browse/SR-4812>, <rdar://problem/40600800>.
Assign separate SILProfiler instances to stored property initializers
and constructors.
Starting with rdar://39460313, coverage reporting for these constructs
was bundled up into a single SILProfiler uniqued by the NominalTypeDecl.
There are two problems with doing this.
First, the shared SILProfiler is given a fake name that can't be
demangled. That breaks Xcode's reports. Second, the relationship
between SILProfiler and SILFunction is supposed to be 1:1. Having a
shared SILProfiler muddies things a bit and requires extra bookkeeping.
rdar://47467864
This is a large patch; I couldn't split it up further while still
keeping things working. There are four things being changed at
once here:
- Places that call SILType::isAddressOnly()/isLoadable() now call
the SILFunction overload and not the SILModule one.
- SILFunction's overloads of getTypeLowering() and getLoweredType()
now pass the function's resilience expansion down, instead of
hardcoding ResilienceExpansion::Minimal.
- Various other places with '// FIXME: Expansion' now use a better
resilience expansion.
- A few tests were updated to reflect SILGen's improved code
generation, and some new tests are added to cover more code paths
that previously were uncovered and only manifested themselves as
standard library build failures while I was working on this change.
The initialization of an instance property that has an attached
property delegate involves the initial value written on the property
declaration, the implicit memberwise initializer, and the default
arguments to the implicit memberwise initializer. Implement SILGen
support for each of these cases.
There is a small semantic change to the creation of the implicit
memberwise initializer due to SE-0242 (default arguments for the
memberwise initializer). Specifically, the memberwise initializer will
use the original property type for the parameter to memberwise
initializer when either of the following is true:
- The corresponding property has an initial value specified with the
`=` syntax, e.g., `@Lazy var i = 17`, or
- The corresponding property has no initial value, but the property
delegate type has an `init(initialValue:)`.
The specific case that changed is when a property has an initial value
specified as a direct initialization of the delegate *and* the
property delegate type has an `init(initialValue:)`, e.g.,
```swift
struct X {
@Lazy(closure: { ... })
var i: Int
}
```
Previously, this would have synthesized an initializer:
```swift
init(i: Int = ???) { ... }
```
However, there is no way for the initialization specified within the
declaration of i to be expressed via the default argument. Now, it
synthesizes an initializer:
```swift
init(i: Lazy<Int> = Lazy(closure: { ... }))
```
The bulk of the changes are to SILGenApply. As we must now evaluate the
payload ArgumentSource to an RValue, we follow the example of subscripts
and lie to the argument emitter. This evaluates arguments at +1 which
can lead to slightly worse codegen at -Onone.
Removes the _getBuiltinLogicValue intrinsic in favor of an open-coded
struct_extract in SIL. This removes Sema's last non-literal use of builtin
integer types and unblocks a bunch of cleanup.
This patch would be NFC, but it improves line information for conditional expression codegen.
Avoid emitting unnecessary basic block for cleanup chains. This is a
general approach that handles all cases while simplifying SILGen
emission and keeping the CFG in a valid state during SILGen.
ASTWalker visits a lazy_initializer_expr once within its associated
var_decl (by way of the parent nominal type). However, SILGen visits the
lazy_initializer_expr while inside of the var_decl's getter. The result
is that there is no coverage mapping information for the contents of the
lazy init within the getter's SILProfiler.
Fixing this will require reworking how profile counters are assigned to
be more in line with what SILGen needs.
As a stop-gap, this patch prevents SILGen from asserting that coverage
mappings are complete with a defensive check which prevents a crash seen
in SR-8429.
rdar://42792053
This initial implementation just delegates from SILGenFunctionBuilder to
SILFunctionBuilder. I was going to start transforming verbose uses of
SILFunctionBuilder into higher level APIs on SILGenFunctionBuilder, but I have
run out of time.
This is a good incremental step forward that will let me hide the constructor of
SILFunctionBuilder after I update the optimizer and thus ensure that
SILFunctionBuilder is only used through appropriate composition APIs.
rdar://42301529