Introduce an attribute @_disfavoredOverload that can be used to state
that a particular declaration should be avoided if there is a
successful type-check for a non-@_disfavoredOverload. It's a way to
nudge overload resolution away from particular solutions.
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: { ... }))
```
A property with an attached delegate can be initialized in one of two ways:
* By directly specifying initialization arguments on the attribute,
e.g., "@SomeDelegate(x: 17, y: 42) var a".
* By initializing the original property itself, which goes through the
delegate type's init(initialValue:) initializer, e.g.,
"@Lazy var x = 17".
Implement support for both forms of initialization, including type
inference and checking for inconsistencies (e.g., if the annotation on
the property type doesn't match what the delegate type would
provide).
Previously, nearly all of the type vars for a key path component were dumped under the KeyPathExpr itself, whcih made them difficult to differentiate when debugging. Attach each one to “key path component #N -> function result” instead.
# Conflicts:
# lib/Sema/CSGen.cpp
We have a systemic class of issues where noescape types end up bound to
type variables in places that should not. The existing diagnostic for
this is ad-hoc and duplicated in several places but it doesn't actually
address the root cause of the problem.
For now, I've changed all call sites of createTypeVariable() to set the
new flag. I plan on removing enough occurrences of the flag to replicate
the old diagnostics. Then we can continue to refine this over time.
Type-check based diagnostics could introduce keypath dynamic member
expressions into AST, which have to be converted back to their
original member or subscript reference form before attempting
re-typecheck.
The use of the reference to a private implementation caused a silent
use-after-free which would normally not trigger a problem as the use was
pretty close by. The reference would copy the pointer and the
destructor for the implementation would free the backing memory. We
would then continue to use the free'd memory to query the information.
The Windows heap allocator kindly scribbles over the memory which caused
an invalid memory access, helping isolate the use-after-free.
Instead of building ArgumentShuffleExprs, lets just build a TupleExpr,
with explicit representation of collected varargs and default
arguments.
This isn't quite as elegant as it should be, because when re-typechecking,
SanitizeExpr needs to restore the 'old' parameter list by stripping out
the nodes inserted by type checking. However that hackery is all isolated
in one place and will go away soon.
Note that there's a minor change the generated SIL. Caller default
arguments (#file, #line, etc) are no longer delayed and are instead
evaluated in their usual argument position. I don't believe this actually
results in an observable change in behavior, but if it turns out to be
a problem, we can pretty easily change it back to the old behavior with a
bit of extra work.
VarargExpansionExpr shows up in call argument lists in synthesized
initializers and modify accessors when we need to forward arguments
to a call taking varargs.
Previously we would say that the type of VarargExpansionExpr is
$T when its subexpression type is [$T]. matchCallArguments() would
then 'collect' the single VarargExpansionExpr into a variadic
argument list with a single element, and build an ArgumentShuffleExpr
for the argument list.
In turn, SILGen would peephole vararg emission of a variadic
argument list with a single entry that happens to be a
VarargExpansionExpr, by returning the subexpression's value,
which happened to be an array of the right element type,
instead of building a new array containing the elements of the
variadic argument list.
This was all too complicated. Instead, let's say that the type of
a VarargExpansionExpr is [$T], except that when it appears in a
TupleExpr, the variadic bit of the corresponding element is set.
Then, matchCallArguments() needs to support a case where both
the parameter and argument list have a matching vararg element.
In this case, instead of collecting multiple arguments into a
single variadic argument list, we treat the variadic argument like
an ordinary parameter, bypassing construction of the
ArgumentShuffleExpr altogether.
Finally, SILGen now needs to be able to emit a VarargExpansionExpr
in ordinary rvalue position, since it now appears as a child of a
TupleExpr; it can do this by simply emitting the sub-expression
to produce an array value.
The overload-favoring code had a couple of different ways in which it
tried to figure out the parameter lists of a given declaration. Have
those all depend on ConstraintSystem::getEffectiveOverloadType(),
which deals with the various member/non-member cases uniformly.
When favoring particular constraints in a disjunction, don't remove
the old disjunction and create a new one---it's just churn in the
constraint system. Instead, favor the constraints that need it.
This technically flips the SR-139 test case from "too complex" to
being fast enough, but it's still fairly slow.
The call-favoring code was creating a two-level disjunction, when would
then immediately get flattened into a single level. Instead, create a
single-level disjunction directly.
The walker that was setting argument labels was looking through ! and ?
postfix expressions, but the lookup code itself was not, leading to missed
opportunities for filtering based on argument labels. Generalize the
transformation that maps from the function expression down to the locator
for which we will retrieve argument labels.
Record the argument labels provided to a subscript in the solver, and
use that to filter out subscript declarations with non-matching
argument labels during function application. This reduces the number of
overloaded subscript declarations that will be considered in later
steps in the solver, reducing the solution space.
*Disable* this optimization in the normal member-lookup path, which is
intended to go away in the near future. This limits the scope of the
change somewhat, so we can separately tackle the diagnostics issue.
The one diagnostics change here is probably an improvement, because
the user explicitly stated the argument labels, and is more likely
missing a conversion on the argument than having typed the wrong
label.
Extend the computation of effective overload types, used in common result
type and common type computations, to also handle subscripts and variables.
This allows the optimization to also apply to subscripts, which did not
previously have a peephole in constraint generation.
Constraint generation for function application expressions contains a simple
hack to try to find the common result type for an overload set containing
callable things. Instead, perform this “common result type” computation
when simplifying an applicable function constraint, so it is more
widely applicable.
Rather than looking directly at the subexpressions of a function
application to determine whether they are literal expressions, look
instead at the type variables for the argument types: if they have a
literal-conforms-to constraint on them, use the named literal protocol
to determine favored declarations.
This refactoring is intended to broaden the applicability of the
existing "favored declaration" machinery to also consider the literal
constraints of other type variables that are equivalent to the type
variable named by the argument.
Given an overload set, attempt to compute a "common type" that
abstracts over all entries in the overload set, providing more
structure for the constraint solver.
Since @autoclosure attribute is associated with declarations
it makes more sense to move diagnostics to where type of the
parameter has been completely resolved. This also helps to support
parameters with typealiases pointing to function types without
any extra logic in the resolver.
Solving Bind is a little easier than Equal. The only remaining uses of Equal
are in the .member syntax and keypaths; if we can refactor those, we might be
able to simplify LValue handling in the type checker in general.
We're looking at the generic signature of the extension, so it must
have been validated at this point.
I don't have a test case for this and maybe it never came up, but
nothing forces it to be validated here so let's make it more robust
by doing it explicitly.
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.