Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
This fixes an immediate bug with subst-to-orig conversion of
parameter functions that I'm surprised isn't otherwise tested.
More importantly, it preserves valuable information that should
let us handle a much wider variety of variant representations
that aren't necessarily expressed in the AbstractionPattern.
For anything else, we can decompose the argument list on the spot.
Note that builtins that are implemented as EarlyEmitters now take a
the argument list as a PreparedArguments instead of a single Expr.
Since the PreparedArguments can still be a scalar with an
ArgumentShuffleExpr, we have to jump through some hoops to turn
it into a list of argument Exprs. This will all go away soon.
Right now we use TupleShuffleExpr for two completely different things:
- Tuple conversions, where elements can be re-ordered and labels can be
introduced/eliminated
- Complex argument lists, involving default arguments or varargs
The first case does not allow default arguments or varargs, and the
second case does not allow re-ordering or introduction/elimination
of labels. Furthermore, the first case has a representation limitation
that prevents us from expressing tuple conversions that change the
type of tuple elements.
For all these reasons, it is better if we use two separate Expr kinds
for these purposes. For now, just make an identical copy of
TupleShuffleExpr and call it ArgumentShuffleExpr. In CSApply, use
ArgumentShuffleExpr when forming the arguments to a call, and keep
using TupleShuffleExpr for tuple conversions. Each usage of
TupleShuffleExpr has been audited to see if it should instead look at
ArgumentShuffleExpr.
In sequent commits I plan on redesigning TupleShuffleExpr to correctly
represent all tuple conversions without any unnecessary baggage.
Longer term, we actually want to change the representation of CallExpr
to directly store an argument list; then instead of a single child
expression that must be a ParenExpr, TupleExpr or ArgumentShuffleExpr,
all CallExprs will have a uniform representation and ArgumentShuffleExpr
will go away altogether. This should reduce memory usage and radically
simplify parts of SILGen.
The `Stmt` and `Expr` classes had both `dump` and `print` methods that behaved similarly, making it unclear what each method was for. Following a conversation in https://forums.swift.org/t/unifying-printing-logic-in-astdumper/15995/6 the `dump` methods will be used to print the S-Expression-like ASTs, and the `print` methods will be used to print the more textual ASTPrinter-based representations. The `Stmt` and `Expr` classes seem to be where this distinction was more ambiguous. These changes should fix that ambiguity.
A few other classes also have `print` methods used to print straightforward representations that are neither the S-Expressions nor ASTPrinters. These were left as they are, as they don't cause the same ambiguity.
It should be noted that the ASTPrinter implementations themselves haven't yet been finished and aren't a part of these changes.
Also, move the check to make it explicit that only a TupleShuffleExpr
at the top level goes through the argument emission code path; a
TupleShuffleExpr appearing inside a ParenExpr or TupleExpr is a
tuple conversion, which is totally unrelated and emitted as an RValue.
This is unfortunate and we should split off ArgumentShuffleExpr from
TupleShuffleExpr, and eventually, fold ArgumentShuffleExpr into
ApplyExpr.
This is NFC for now, but I plan to build on this to (1) immediately
remove some unnecessary materialization and loads of the base value
and (2) to allow clients to load a borrowed value.
This can only come up with the +1 runtime if we need to pass a +0 value into
memory. As with the other ArgumentSource change, I don't think such code can be
emitted today. It does happen often with the +0 runtime though.
rdar://34222540
This can only happen when +0 is enabled. The reason why is that guaranteed self
is immutable so can not be passed inout without going through a var. There are
no other cases I can think of where an ArgumentSource will put self into
memory.
This is tested by the updated SILGen +0 tests.
rdar://34222540
Now that we emit the callee at the right time, we no longer need
to force emit the 'self' argument source at +0 and possibly
convert it to +1 later.
This is NFC, except it means we end_borrow the self value a bit
sooner sometimes, which is a good thing.
This can get introduced by somewhat pathological behavior in the
importer combined with SILGenApply's reliance on parallel tuple
destructuring. Both of these should be fixed, but this patch is
much simpler.
rdar://34913800
This will let me treat self during delegating initialization as an lvalue and
thus be emitted later without a scope. Thus I can simplify delegating
initialization slightly and land my argument scoping work.
rdar://33358110
I am currently changing Callee to use an ArgumentSource instead of a SILValue to
represent self. Due to uncurrying/etc in certain cases, we need to communicate
that a value needs to be borrowed later before use. To do that in a clean way, I
am introducing a new form of ArgumentSource::Kind, DelayedBorrowedRValue.
This type of ArgumentSource can only be produced by calling
ArgumentSource::delayedBorrow(...). Such an argument source acts like a normal
RValue, except when you perform asKnownRValue, a borrow is performed before
returning the known rvalue.
Once uncurrying is ripped out/redone, this code can be removed in favor of just
using a borrowed ArgumentSource.
rdar://33358110
To remove some callers of 'is<InOutType>' after Sema, start using what will soon be a structural invariant - the only expressions that can possibly have 'inout' type are semantically InOut expressions.
ground work for the syntactic bridging peephole.
- Pass source and dest formal types to the bridging routines in addition
to the dest lowered type. The dest lowered type is still necessary
in order to handle non-standard abstraction patterns for the dest type.
- Change bridging abstraction patterns to store bridged formal types
instead of the formal type.
- Improve how SIL type lowering deals with import-as-member patterns.
- Fix some AST bugs where inadequate information was being stored in
various expressions.
- Introduce the idea of a converting SGFContext and use it to regularize
the existing id-as-Any conversion peephole.
- Improve various places in SILGen to emit directly into contexts.
The reason that this is being done is that:
1. SILGenFunction is passed around all throughout SILGen, including in between
APIs some of which call the SILGenFunction variable SGF and others that call it
gen.
2. Thus when one is debugging code in SILGen, one wastes time figuring out what
the variable name of SILGenFunction is in the current frame.
I did not do this by hand. I did this by:
1. Grepping for "SILGenFunction &gen".
2. By hand inspecting that the match was truly a SILGenFunction &gen site.
3. If so, use libclang tooling to rename the variable to SGF.
So I did not update any use sites.
Swift admits implicit conversions between tuple types to
introduce and eliminate argument labels, and re-order
argument labels. These are expressed as TupleShuffleExpr
in the AST.
SILGen has two different code paths for lowering TupleShuffleExpr,
which is also used for varargs and default arguments in call
argument emission.
These two code paths support different subsets of TupleShuffleExpr;
neither one supports the full generality of the other, but there
is some overlap.
Work around the damage by routing the two different "kinds" of
TupleShuffleExprs to the correct place in argument emission.
The next incremental step here would be to refactor ArgEmitter to
make it usable when lowering SubscriptExpr; then the RValueEmitter's
support for varargs in TupleShuffleExpr can go away. Once that's
done we can split off an ArgumentExpr from TupleShuffleExpr, and
in the fullness of time, fold ArgumentExpr into ApplyExpr.
At that point this dark corner of the AST will start to be sane...
Fixes <https://bugs.swift.org/browse/SR-2887>.
In Swift, default arguments are associated with a function or
initializer's declaration---not with its type. This was not always the
case, and TupleType's ability to store a default argument kind is a
messy holdover from those dark times.
Eliminate the default argument kind from TupleType, which involves
migrating a few more clients over to declaration-centric handling of
default arguments. Doing so is usually a bug-fix anyway: without the
declaration, one didn't really have
The SILGen test changes are due to a name-mangling fix that fell out
of this change: a tuple type is mangled differently than a non-tuple
type, and having a default argument would make the parameter list of a
single-parameter function into a tuple type. Hence,
func foo(x: Int = 5)
would get a different mangling from
func foo(x: Int)
even though we didn't actually allow overloading.
Fixes rdar://problem/24016341, and helps us along the way to SE-0111
(removing the significance of argument labels) because argument labels
are also declaration-centric, and need the same information.
Similarly to how we've always handled parameter types, we
now recursively expand tuples in result types and separately
determine a result convention for each result.
The most important code-generation change here is that
indirect results are now returned separately from each
other and from any direct results. It is generally far
better, when receiving an indirect result, to receive it
as an independent result; the caller is much more likely
to be able to directly receive the result in the address
they want to initialize, rather than having to receive it
in temporary memory and then copy parts of it into the
target.
The most important conceptual change here that clients and
producers of SIL must be aware of is the new distinction
between a SILFunctionType's *parameters* and its *argument
list*. The former is just the formal parameters, derived
purely from the parameter types of the original function;
indirect results are no longer in this list. The latter
includes the indirect result arguments; as always, all
the indirect results strictly precede the parameters.
Apply instructions and entry block arguments follow the
argument list, not the parameter list.
A relatively minor change is that there can now be multiple
direct results, each with its own result convention.
This is a minor change because I've chosen to leave
return instructions as taking a single operand and
apply instructions as producing a single result; when
the type describes multiple results, they are implicitly
bound up in a tuple. It might make sense to split these
up and allow e.g. return instructions to take a list
of operands; however, it's not clear what to do on the
caller side, and this would be a major change that can
be separated out from this already over-large patch.
Unsurprisingly, the most invasive changes here are in
SILGen; this requires substantial reworking of both call
emission and reabstraction. It also proved important
to switch several SILGen operations over to work with
RValue instead of ManagedValue, since otherwise they
would be forced to spuriously "implode" buffers.
Take apart exploded one-element tuples and be more careful with
passing around tuple abstraction patterns.
Also, now we can remove the inputSubstType parameter from
emitOrigToSubstValue() and emitSubstToOrigValue(), making the
signatures of these functions nice and simple once again.
Fixes <rdar://problem/19506347> and <rdar://problem/22502450>.
Right now, re-abstraction thunks are set up to convert values
as follows, where L is type lowering:
- OrigToSubst: L(origType, substType) -> L(substType)
- SubstToOrig: L(substType) -> L(origType, substType)
This assumes there's no AST-level type conversion, because
when we visit a type in contravariant position, we flip the
direction of the transform but we're still converting *to*
substType -- which will now equal to the type of the input,
not the type of the expected result!
This caused several problems:
- VTable thunk generation had a bunch of special logic to
compute a substOverrideType, and wrap the thunk result
in an optional, duplicating work done in the transform
- Witness thunk generation similarly had to handle the case
of upcasting to a base class to call the witness, and
casting the result of materializeForSet back to the right
type for properties defined on the base.
Now the materializeForSet cast sequence is a bit longer,
we unpack the returned tuple and do a convert_function
on the function, then pack it again -- before we would
unchecked_ref_cast the tuple, which is technically
incorrect since the tuple is not a ref, but IRGen didn't
seem to care...
To handle the conversions correctly, we add a third AST type
parameter to a transform, named inputType. Now, transforms
perform these conversions:
- OrigToSubst: L(origType, inputType) -> L(substType)
- SubstToOrig: L(inputType) -> L(origType, substType)
When we flip the direction of the transform while visiting
types in contravariant position, we also swap substType with
inputType.
Note that this is similar to how bridging thunks work, for
the same reason -- bridging thunks convert between AST types.
This is mostly just a nice cleanup that fixes some obscure
corner cases for now, but this functionality will be used
in a subsequent patch.
Swift SVN r31486
The main thing that this patch does is work around a shortcoming of
SILGenApply namely that we in certain cases emit self before we know
what the callee is. We work around this by emitting self at +0 assuming
that the callee does pass self at +0 and set a flag. After we know what
the callee is, if the flag is set, we emit an extra retain for self.
rdar://15729033
Swift SVN r27553
This is necessary for correctly dealing with non-standard
ownership conventions in secondary positions, and it should
also help with non-injective type imports (like BOOL/_Bool).
But right now we aren't doing much with it.
Swift SVN r26954
the call instead of during the formal evaluation of the argument.
This is the last major chunk of the semantic changes proposed
in the accessors document. It has two purposes, both related
to the fact that it shortens the duration of the formal access.
First, the change isolates later evaluations (as long as they
precede the call) from the formal access, preventing them from
spuriously seeing unspecified behavior. For example::
foo(&array[0], bar(array))
Here the value passed to bar is a proper copy of 'array',
and if bar() decides to stash it aside, any modifications
to 'array[0]' made by foo() will not spontaneously appear
in the copy. (In contrast, if something caused a copy of
'array' during foo()'s execution, that copy would violate
our formal access rules and would therefore be allowed to
have an arbitrary value at index 0.)
Second, when a mutating access uses a pinning addressor, the
change limits the amount of arbitrary code that falls between
the pin and unpin. For example::
array[0] += countNodes(subtree)
Previously, we would begin the access to array[0] before the
call to countNodes(). To eliminate the pin and unpin, the
optimizer would have needed to prove that countNodes didn't
access the same array. With this change, the call is evaluated
first, and the access instead begins immediately before the call
to +=. Since that operator is easily inlined, it becomes
straightforward to eliminate the pin/unpin.
A number of other changes got bundled up with this in ways that
are hard to tease apart. In particular:
- RValueSource is now ArgumentSource and can now store LValues.
- It is now illegal to use emitRValue to emit an l-value.
- Call argument emission is now smart enough to emit tuple
shuffles itself, applying abstraction patterns in reverse
through the shuffle. It also evaluates varargs elements
directly into the array.
- AllowPlusZero has been split in two. AllowImmediatePlusZero
is useful when you are going to immediately consume the value;
this is good enough to avoid copies/retains when reading a 'var'.
AllowGuaranteedPlusZero is useful when you need a stronger
guarantee, e.g. when arbitrary code might intervene between
evaluation and use; it's still good enough to avoid copies
from a 'let'. The upshot is that we're now a lot smarter
about generally avoiding retains on lets, but we've also
gotten properly paranoid about calling non-mutating methods
on vars.
(Note that you can't necessarily avoid a copy when passing
something in a var to an @in_guaranteed parameter! You
first have to prove that nothing can assign to the var during
the call. That should be easy as long as the var hasn't
escaped, but that does need to be proven first, so we can't
do it in SILGen.)
Swift SVN r24709