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
There were several bits of code which were unnecessarily
repeating the core logic of breaking down an access strategy
and either setting up an LValue or directly emitting it.
These places have now been unified to just create and then
load or othrwise use an LValue.
Introduce a visitor which handles the common parts of breaking
down an access strategy and computing information like the
LValueTypeData. In addition to its direct benefits (which are
somewhat lost in the boilerplate of capturing local state into
the visitor subclass), this eliminates some of the ad-hocness
of how the various emission paths use AccessStrategy.
Finally, implement the MaterializeToTemporary strategy in its
full generality by using the actual read and write sub-strategies
instead of always falling back on calling the getter and setter.
This part is not NFC because it causes us to perform the read
part of a read/write to a stored-with-observers property by
directly accessing the storage instead of calling the getter.
This comes up when invoking protocol methods on an existential that have covariant arguments of function type with Self arguments, e.g.:
```swift
protocol P {
mutating func foo(_: (Self) -> Void)
}
func bar(x: inout P) {
x.foo { y in return }
}
```
Although the type-erased method is presented as formally taking an argument of the existential type P, it still has a conversion thunk to perform type erasure on the argument coming from the underlying implementation. Since the `self` argument is inout, it isn't formally opened until late when formal accesses begin, so this closure conversion must also be deferred until after that occurs.
The only time the generic signature of the callee won't
match the generic signature of the substitution map is when
the callee is a non-generic closure inside a generic context.
Instead of remapping substitutions it suffices to just drop
them.
SubstitutionMaps are now just a trivial pointer-sized value, so
pass them by value instead.
I did have to move a couple of functors from Type.h to SubstitutionMap.h
to resolve some issues with forward declarations.
This causes default arguments to get emitted after formal evaluation of `self`, allowing protocol methods to access the opened `Self` type of an existential receiver. Fixes rdar://problem/39524104
Turns out it's really expensive and not really needed. On my machine
the testcase reported in SR-7691 goes down from 24 seconds to 2 seconds
after this change.
<rdar://problem/40258978>
Introduced during the bring-up of the generics system in July, 2012,
Substitution (and SubstitutionList) has been completely superseded by
SubstitutionMap. R.I.P.
Replace two prominent uses of SubstitutionList, in ConcreteDeclRef and
Witness, with SubstitutionMap. Deal with the myriad places where we
now have substitution maps and need substitution lists (or vice versa)
caused by this change.
Overall, removes ~50 explicit uses of SubstitutionList (of ~400).
The condition we want to test for emitting a downcast is isRequired(),
not isInheritable(). The latter is only true for convenience
initializers.
The other fix is that we actually have to emit a class_method
dispatch here to support class hierarchies conforming to literal
protocols.
closure lifetimes.
SILGen will now unconditionally emit
%cvt = convert_escape_to_noescape [guaranteed] %op
instructions. The mandatory ClosureLifetimeFixup pass ensures that %op's
lifetime spans %cvt's uses.
The code in DefiniteInitialization that handled a subset of cases is
removed.
If a property or subscript is referenceable from other modules, we need to give it a descriptor so that we can reliably build an equivalent key path in or out of that module.
There are some cases that we should handle but don't yet:
- Global and static properties ought to be key-path-able someday, so we should make descriptors for them, but this might need a new key path component kind.
- Subscripts with indexes that aren't Hashable in the current module ought to get descriptors too, in case we ever support non-hashable key path components, and also because a generic subscript might be substituted with Hashable types by an external user, or an external module might post-hoc extend a type to be Hashable, so we really need to change things so that the client supplies the hashing and equality implementations for the indexes instead of the descriptor.
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.
Since I used ensurePlusOne, this should not have any effect on the compiler
today. This happens quite often once "normal arguments" are at +0 though.
I also changed this code to use SILGenBuilder APIs to ensure that ownership is
forwarded correctly.
Found when updating SILGen tests for +0.
rdar://34222540
Some of the classes in this file were using LLVM style for long classes, i.e.:
```
namespace {
class Foo {
... long class ...
};
} // end anonymous namespace
```
Other places, we were adding a level of indentation, i.e.:
```
namespace {
class Foo {
... long class ...
};
} // end anonymous namespace
```
This PR just standardizes the classes in this file that follow the later style,
to instead follow the former style.