Allow a behavior protocol to declare an `initStorage` implementation with a parameter. If we have an initializer expression, use `initStorage(initExpr)` to initialize the storage; otherwise, remember the storage declaration and its initializer. Definite
initialization will have to use these to insert the initialization operation for the behavior property at the right place.
We had four duplicated implementations of checking how a protocol
requirement uses 'Self', all slightly wrong or incomplete:
- When deciding if the protocol type can be used as an existential.
This one would just ignore 'Self' in the return type of a method
completely, which was incorrect for cases where 'Self' is
contravariant but part of the return value, for example:
func foo() -> (Self -> ())
- When deciding if a member access can be performed on an existential
value. This is distinct from the former, because the member may
have been defined in a protocol extension, in which case it cannot
be used even if the protocol type can be used as an existential.
Unfortunately, this implementation was overly conservative, and
would reject uses of 'Self' where Sema could in fact erase the
existential type, for example:
func foo() -> Self??
func foo() -> Self.Type
func foo() -> (Self, Self)
This function handled function return types correctly, effectively
plugging the leak in the previous code. It did lead to inconsistent
behavior with protocols that had contravariant Self in requirements
though; sometimes we would diagnose uses of the existential type,
other times we would only complain about specific members.
- When deciding if a method in a non-final class can model a protocol
requirement. This one was the most elaborate one, but here
contravariance and uses of associated types are actually okay, so
it was written to pick up covariant 'Self' only. However, it also
did not handle metatypes and tuples.
- When opening the type of member of an existential, we would check
if the return value was 'Self' or an optional of 'Self', but again
this check was too conservative, so after the previous three were
fixed, we could reference members on existentials that did not
have a correct opened type.
Now, these have been combined into one check. To fix some crashes,
Sema's implementation of erasing existentials now relies on
coerceToType() instead of hand-rolling a few coercions of its own,
and wrapping the rest in CovariantFunctionConversionExpr, which
didn't make much sense if the result was not a function type.
SILGen still does not support function type conversions where an
existential return value is being erased; these would silently
miscompile before, but crash with an assertion now, because they
are correctly modeled as a FunctionConversionExpr, and not
CovariantFunctionConversionExpr.
If behaviors are specified after the declaration, something like this:
```swift
var x: Int __behavior foo // __behavior is a stand-in keyword
```
we're thinking this encourages a simpler design for smaller, more composable behaviors. If we think of behavior application as function-like, then parameters to the behavior could be passed with function-like syntax:
```swift
__behavior lazy(@autoclosure initialValue: () -> Value) { ... }
var x: Int __behavior lazy(1738)
__behavior didSet(body: (oldValue: Value) -> Void) { ... }
var x: Int __behavior didSet {
trailingClosure()
}
```
Since behaviors are implementation details, they arguably belong to the right of the declaration as well.
The Objective-C Cocoa convention eschew "is" on property names, but
use it on the getter, while the Swift API guidelines state that
Boolean properties should read as assertions (e.g., "isEmpty" rather
than "empty"). Map Swift properties named "isFoo" to Objective-C by
removing the "is" from the resulting Objective-C property name (so it
will be named "foo") and from the setter (which will have the
Objective-C selector "setFoo:") while retaining the "is" for the
getter selector ("isFoo").
Fixes rdar://problem/17090661.
Parse 'var [behavior] x: T', and when we see it, try to instantiate the property's
implementation in terms of the given behavior. To start out, behaviors are modeled
as protocols. If the protocol follows this pattern:
```
protocol behavior {
associatedtype Value
}
extension behavior {
var value: Value { ... }
}
```
then the property is instantiated by forming a conformance to `behavior` where
`Self` is bound to the enclosing type and `Value` is bound to the property's
declared type, and invoking the accessors of the `value` implementation:
```
struct Foo {
var [behavior] foo: Int
}
/* behaves like */
extension Foo: private behavior {
@implements(behavior.Value)
private typealias `[behavior].Value` = Int
var foo: Int {
get { return value }
set { value = newValue }
}
}
```
If the protocol requires a `storage` member, and provides an `initStorage` method
to provide an initial value to the storage:
```
protocol storageBehavior {
associatedtype Value
var storage: Something<Value> { ... }
}
extension storageBehavior {
var value: Value { ... }
static func initStorage() -> Something<Value> { ... }
}
```
then a stored property of the appropriate type is instantiated to witness the
requirement, using `initStorage` to initialize:
```
struct Foo {
var [storageBehavior] foo: Int
}
/* behaves like */
extension Foo: private storageBehavior {
@implements(storageBehavior.Value)
private typealias `[storageBehavior].Value` = Int
@implements(storageBehavior.storage)
private var `[storageBehavior].storage`: Something<Int> = initStorage()
var foo: Int {
get { return value }
set { value = newValue }
}
}
```
In either case, the `value` and `storage` properties should support any combination
of get-only/settable and mutating/nonmutating modifiers. The instantiated property
follows the settability and mutating-ness of the `value` implementation. The
protocol can also impose requirements on the `Self` and `Value` types.
Bells and whistles such as initializer expressions, accessors,
out-of-line initialization, etc. are not implemented. Additionally, behaviors
that instantiate storage are currently only supported on instance properties.
This also hasn't been tested past sema yet; SIL and IRGen will likely expose
additional issues.
Replace pointer arithmetic between multiple base classes with pointer arithmetic
between adjacent allocations. This is still pretty fragile, but at least not
ABI-dependent, and in practice we should generate exactly the same code.
This class formalizes the common case of the "trailing allocation" idiom we use
frequently. I didn't spot any true bugs while making this change, but I did see
places where we were using the wrong pointer type or casting through void* for
no good reason. This will keep us honest.
I'll get to the other libraries soon.
TypeAlignments.h predates this whole mess; it was used for types with
stronger alignment in PointerLikeTypeTraits than the old default of
"2 by fiat and assumption". All remaining forward-declared types are
AST types, so fold them into TypeAlignments.h.
(The one exception is SILTypeList.h, but that's already gone on master.)
To avoid future ODR issues, explicitly include TypeAlignments.h into
every header that defines a type it forward-declares.
I wish we could use partial specialization to provide PointerLikeTypeTraits
for all derived classes of Decl, TypeBase, etc, but that's not something
you can do in C++ if you don't control the traits class.
The idea here is to do more marking of the generic parts of the
protocol as being invalid as soon as the recursiveness is diagnosed in
order to simplify checking (and avoid infinite loops) down the line.
This is a preliminary cleanup before adding resilient access to
global variables. It might also enable @_fixed_layout properties
on resilient structs one day, if we choose to do that.
Also, change NominalTypeDecl::hasFixedLayout() to not care about
classes imported from Clang. IRGen already has its own fine-grained
queries and abstractions for asking this question, so don't try
to capture in the AST.
As part of this, use a different enum for parsed generic requirements.
NFC except that I noticed that ASTWalker wasn't visiting the second
type in a conformance constraint; fixing this seems to have no effect
beyond producing better IDE annotations.
A decl’s full GenericSignature is set during validateGenericTypeSignature().
Then during ConstraintSystem::openTypes(), in ReplaceDependentTypes, the GenericArgs list is built from the generic signature (via getGenericParamTypes()) and passed into a new BoundGenericType.
In BoundGenericType::getSubstitutions(), the GenericArgs are assumed to match getGenericParamsOfContext()->getParams().
However, in reality, the GenericArgs include all levels of generic args, whereas getGenericParamsOfContext() are the params of the innermost context only, so the params array is accessed past its end.
This commit changes NominalTypeDecl::getGenericParamTypes() to return the innermost params, in order to match the output of BoundGenericType::getGenericArgs(). For clarity and to hopefully prevent future confusion, we also rename getGenericParamTypes() to getInnermostGenericParamTypes().
Parameters (to methods, initializers, accessors, subscripts, etc) have always been represented
as Pattern's (of a particular sort), stemming from an early design direction that was abandoned.
Being built on top of patterns leads to patterns being overly complicated (e.g. tuple patterns
have to have varargs and default parameters) and make working on parameter lists complicated
and error prone. This might have been ok in 2015, but there is no way we can live like this in
2016.
Instead of using Patterns, carve out a new ParameterList and Parameter type to represent all the
parameter specific stuff. This simplifies many things and allows a lot of simplifications.
Unfortunately, I wasn't able to do this very incrementally, so this is a huge patch. The good
news is that it erases a ton of code, and the technical debt that went with it. Ignoring test
suite changes, we have:
77 files changed, 2359 insertions(+), 3221 deletions(-)
This patch also makes a bunch of wierd things dead, but I'll sweep those out in follow-on
patches.
Fixes <rdar://problem/22846558> No code completions in Foo( when Foo has error type
Fixes <rdar://problem/24026538> Slight regression in generated header, which I filed to go with 3a23d75.
Fixes an overloading bug involving default arguments and curried functions (see the diff to
Constraints/diagnostics.swift, which we now correctly accept).
Fixes cases where problems with parameters would get emitted multiple times, e.g. in the
test/Parse/subscripting.swift testcase.
The source range for ParamDecl now includes its type, which permutes some of the IDE / SourceModel tests
(for the better, I think).
Eliminates the bogus "type annotation missing in pattern" error message when a type isn't
specified for a parameter (see test/decl/func/functions.swift).
This now consistently parenthesizes argument lists in function types, which leads to many diffs in the
SILGen tests among others.
This does break the "sibling indentation" test in SourceKit/CodeFormat/indent-sibling.swift, and
I haven't been able to figure it out. Given that this is experimental functionality anyway,
I'm just XFAILing the test for now. i'll look at it separately from this mongo diff.
This is necessary for some other work I'm doing, which really wants
paramdecls to have reasonable declcontexts. It is also a small step
towards generic subscripts.
to consolidate the kajillion places the allocate the decl for self.
- Move the ParamDecl ctor implementation out of line, since only one TU
calls it.
NFC.
is used by precisely one thing (producing a warning in a scenario that is obsolete
because we deprecated the entire thing), so the complexity isn't worth it anymore.