We cannot in general use @guaranteed here, otherwise classes will not
be able to conform to protocols with mutable property requirements
(or we could always open-code materializeForSet witness thunks for
classes, but that has its own downsides so its not a clear win).
Fixes <rdar://problem/36867783>.
Factor out the code to lower an individual key path component to be independent of overall KeyPathExpr lowering, so that we can soon reuse the same code paths to build property descriptors for resilient properties. NFC intended.
This has three principal advantages:
- It gives some additional type-safety when working
with known accessors.
- It makes it significantly easier to test whether a declaration
is an accessor and encourages the use of a common idiom.
- It saves a small amount of memory in both FuncDecl and its
serialized form.
just for pointer identity.
The current technique for deciding whether that's the case is *extremely*
hacky and need to be replaced with an attribute, but I'm reluctant to
take that on so late in the schedule. The hack is terrible but not too
hard to back out in the future. Anyone who names a method like this just
to get the magic behavior knows well that they are not on the side of
righteousness.
rdar://33265254
conversions that reverse an implicit conversion done to align
foreign declarations with their imported types.
For example, consider an Objective-C method that returns an NSString*:
- (nonnull NSString*) foo;
This will be imported into Swift as a method returning a String:
func foo() -> String
A call to this method will implicitly convert the result to String
behind the scenes. If the user then casts the result back to NSString*,
that would normally be compiled as an additional conversion. The
compiler cannot simply eliminate the conversion because that is not
necessarily semantically equivalent.
This peephole recognizes as-casts that immediately reverse a bridging
conversion as a special case and gives them special power to eliminate
both conversions. For example, 'foo() as NSString' will simply return
the original return value. In addition to call results, this also
applies to call arguments, property accesses, and subscript accesses.
An assertion I added recently to check property overrides in
the ASTVerifier uncovered some bugs in this area:
- We did not synthesize a materializeForSet for properties
defined in extensions of imported classes unless they
witnessed a protocol requirement.
This triggered an assertion if the property had an
override that was checked before the protocol conformance,
since the override's materializeForSet would not be marked
as an override of the base materializeForSet.
- materializeForSet for properties defined in extensions would
statically dispatch the getter and setter instead of dynamically
dispatching. This is incorrect since we statically dispatch
to the materializeForSet in this case, and we can in fact
override it in a subclass.
Fixes <rdar://problem/31334272>.
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.
I've fixed a few bugs recently where I had to switch
a getCanonicalType() call to instead use the stronger
GenericSignature::getCanonicalTypeInContext().
Avoid the 'if (genericSig = ...)' dance by adding a new
form of TypeBase::getCanonicalType() which takes a
signature, and if it's null, just falls back to the
standard getCanonicalType().
- Property defined in constrained extension of a class
- Subscript defined in a constrained extension with non-canonical index type
Fixes <rdar://problem/31222187>.
A lot of files transitively include Expr.h, because it was
included from SILInstruction.h, SILLocation.h and SILDeclRef.h.
However in reality most of these files don't do anything
with Exprs, especially not anything in IRGen or the SILOptimizer.
Now we're down to 171 files in the frontend which depend on
Expr.h, which is still a lot but much better than before.
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.
We can get the generic signature from the generic environment
now, and for generic subscript protocol witnesses, using the
signature of the conformance is wrong; it won't have the
generic parameters of the subscript itself.
Also, emit the materializeForSet callback in the right place in
SILModule. Instead of adding it at the end, put it before the
materializeForSet itself. This makes tests a bit easier to write.
SubstitutionList is going to be a more compact representation of
a SubstitutionMap, suitable for inline allocation inside another
object.
For now, it's just a typedef for ArrayRef<Substitution>.
This is useful to discover when a specific cleanup is being eliminated while
debugging. The implementation is compiled out when assertions are disabled.
rdar://29791263