Follow-up to my earlier changes to drop 'inout' types when cloning parameter
lists, we also need to deal with substitutions into those parameter types.
This is an artifact of us having mostly---but not entirely---removed
InOutType from the AST. Fixes rdar://problem/34818336.
When type-checking a function or subscript that itself does not have generic
parameters (but is within a generic context), we were creating a generic
signature builder which will always produce the same generic signature as
the enclosing context. Stop creating that generic signature builder.
Instead, teach the CompleteGenericTypeResolver to use the generic signature
+ the canonical generic signature builder for that signature to resolve
types, which also eliminates some extraneous re-type-checking.
Improves type-checking performance of the standard library by 36%.
When type-checking a function or subscript that itself does not have generic
parameters (but is within a generic context), we were creating a generic
signature builder which will always produce the same generic signature as
the enclosing context. Stop creating that generic signature builder.
Instead, teach the CompleteGenericTypeResolver to use the generic signature
+ the canonical generic signature builder for that signature to resolve
types, which also eliminates some extraneous re-type-checking.
Improves type-checking performance of the standard library by 36%.
The base mutability of storage is part of the signature, so be sure
to compute that during validation. Also, serialize it as part of
the storage declaration, and fix some places that synthesize
declarations to set it correctly.
A lazy property setter stores a value to the underlying storage
of the lazy property. The underlying storage is private, and it
is not proper for a public transparent function body to reference
a private member.
In practice, this only failed if the private member had a
non-constant offset, which only occurs with subclasses of @objc
classes, and resilient classes.
For @objc classes we already had a workaround where no accessors
for stored properties are ever transparent. I put this in to fix
this very issue with lazy properties, but now I realize it was
the wrong workaround, because we still had this problem with
resilient classes.
Note that I'm keeping the logic which made @objc accessors
non-transparent in place, because there's a good chance we will
decide that field offset globals should always be private.
Also, to make this issue reproducible in the test, I changed the
resilience execution tests to build the resilient library as a
dylib and link against that instead of just linking .o files
together. This is because .o files can see each other's internal
symbols, so I was not able to reproduce the original failure
this way. I went ahead and updated the other resilient tests to
do this as well. Also, each test now builds in WMO and non-WMO
mode, to exercise different SIL linking behavior. Again, the
WMO variant was needed to reproduce the issue fixed by this
commit, because without WMO we currently discard serialized SIL,
so no cross-module inlining of the lazy property setter was
taking place.
"Accessibility" has a different meaning for app developers, so we've
already deliberately excised it from our diagnostics in favor of terms
like "access control" and "access level". Do the same in the compiler
now that we aren't constantly pulling things into the release branch.
This commit changes the 'Accessibility' enum to be named 'AccessLevel'.
Pushes __consuming through the frontend and extends existing
attribute-based diagnsotics to cover it. Unlike `nonmutating`,
__consuming is allowed in class methods, though it makes little
sense to put it there.
Also, begin to pass around base types instead of raw InOutType types. Ideally, only Sema needs to deal with them, but this means that a bunch of callers need to unwrap any inouts that might still be lying around before forming these types.
Multiple parts of the compiler were slicing, dicing, or just dropping these flags. Because I intend to use them for the new function type representation, I need them to be preserved all across the compiler. As a first pass, this stubs in what will eventually be structural rules as asserts and tracks down all callers of consequence to conform to the new invariants.
This is temporary.
In anticipation of future attributes, and perhaps the ability to
declare lvalues with specifiers other than 'let' and 'var', expand
the "isLet" bit into a more general "specifier" field.
- A mutating method or accessor always has 'inout self'.
- A nonmutating method or accessor never has 'inout self'.
- Only instance members can be mutating.
- Addressors are still addressors even when on static members.
Came up after reviewing another patch that confused the two as
possibly distinct concepts.
If synthesizeWitnessAccessorsForStorage() got called on a lazy
property before maybeAddAccessorsToVariable(), we would build
it as a stored property instead.
This count result in bogus diagnostics, assertions and bad runtime
behavior.
Fixes <https://bugs.swift.org/browse/SR-1825>.
Allow instance properties and methods to be referenced from
within a lazy property initializer, with or without explicit
'self.' qualification.
The old behavior in Swift 3 was an incredible combination
of odd quirks:
- If the lazy property had an explicitly-written type, it was
possible to reference instance members from the initializer
expression by explicitly prefixing 'self.'.
- However, if the lazy property type is inferred, it would
first be type checked in the initializer context, which
has no 'self' available.
- Unqualified references to instance members did not work
at all, because name lookup thought the "location" of the
lookup was outside of the body of the getter.
- Unqualified references to static properties worked, however
unqualified references to static methods did not, and
produced a bogus diagnostic, because one part of the name
lookup code thought that initializers were "instance
context" and another thought they were "static context".
This patch improves on the old behavior with the following
fixes:
- Give PatternBindingInitializers associated with lazy
properties an implicit 'self' declaration for use by
name lookup.
- In order to allow "re-parenting" the initializer after it
has been type checked into the body of the getter, "steal"
the initializer's 'self' when buiding the getter.
- Fix up name lookup and make it aware of the implicit
'self' decl of a PatternBindingInitializer.
This improves upon an earlier fix for this issue by Doug Gregor
which only worked with ASTScope enabled; the new fix is more
general and shares logic between the two name lookup
implementations.
Fixes <rdar://problem/16888679>, <https://bugs.swift.org/browse/SR-48>,
<https://bugs.swift.org/browse/SR-2203>,
<https://bugs.swift.org/browse/SR-4663>, and the countless other
dupes of this issue.
Uncovered by Slava's bcbd1d2, which infers 'dynamic' in more places,
but this was always a problem when an initializer was /explicitly/
marked 'dynamic'.
rdar://problem/32026930
This lets us serialize that decision, which means we can conceivably
/change/ the decision in later versions of the compiler without
breaking existing code. More immediately, it's groundwork that will
eventually allow us to drop decls from the AST without affecting
vtable layout.
This isn't actually a great answer; what we really want is for SIL
vtables to be serialized consistently and treated as the point of
truth. But that would be more change than we're comfortable taking in
the Swift 4 timeframe.
First part of rdar://problem/31878396.
Enums with the ns_error_domain attribute represent codes for NSError,
which means Swift developers will expect to interact with them in
terms of Error. SE-0112 improved bridging for these enums to generate
a struct with the following form:
struct MyError: Error {
@objc enum Code: RawRepresentable {
case outOfMemory
case fileNotFound
}
var userInfo: [NSObject: AnyObject] { get }
static var outOfMemory: Code { get }
static var fileNotFound: Code { get }
}
where MyError.Code corresponds to the original MyError enum defined in
Objective-C. Until recently, both the enum and the synthesized struct
were marked as having the original enum as their "Clang node", but
that leads to problems: the struct isn't really ObjC-compatible, and
the two decls have the same USR. (The latter had already been worked
around.)
This commit changes the struct to be merely considered a synthesized
"external definition", with no associated Clang node. This meant
auditing everywhere that's looking for a Clang node and seeing which
ones applied to external definitions in general.
There is one regression in quality here: the generated struct is no
longer printed as part of the Swift interface for a header file, since
it's not actually a decl with a corresponding Clang node. The previous
change to AST printing mitigates this a little by at least indicating
that the enum has become a nested "Code" type.
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>.
In the old vtable emission code, IRGen would skip addressors,
but they had entries in the SILVTable. This is still correct
behavior, so skip addressors explicitly in SILVTableVisitor.
We never call addressors dynamically, only inside a getter,
setter or materializeForSet. When a property with addressors
is overridden we provide new getters and setters (which may
or may not statically dispatch to a peer addressor).
We had some non-deterministic behavior where depending on
validation order, synthesized accessors would end up in
different places because we would sometimes just add them
at the end of the member list.
Now add the getter right after the storage, the setter
right after the getter and the materializeForSet right
after the setter.
This changes some test output where the declaration order
did not make sense before but should otherwise have no
functional effect.
In 74d979f0ac, the policy was changed
so that only value type accessors are ever marked transparent, and
not class accessors.
This was intended to fix a bug where inlining an accessor of an
Objective-C-derived class across module boundaries caused a linker
failure because the accessor referenced a field offset variable,
which has hidden visibility.
However, this also caused a performance regression for Swift native
classes. Bring back the old behavior for Swift native classes in
non-resilient modules.
Fixes <rdar://problem/29884727>.
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>.
The problem is that the derived property's materializeForSet was
being synthesized after recordOverride() was called, so the new
accessor never got setOverridenDecl() called on it.
As a result, SIL didn't know that the derived materializeForSet
should replace the vtable entry for the base class materializeForSet.
The more fundamental problem here is that even after some recent
cleanups, accessors are still sometimes type checked before
the AbstractStorageDecla and sometimes after. So things like
inferring final, dynamic and overrides have to be duplicated in
multiple places.
Fixes <https://bugs.swift.org/browse/SR-3840> and
<rdar://problem/30336146>.
The problem is that the derived property's materializeForSet was
being synthesized after recordOverride() was called, so the new
accessor never got setOverridenDecl() called on it.
As a result, SIL didn't know that the derived materializeForSet
should replace the vtable entry for the base class materializeForSet.
The more fundamental problem here is that even after some recent
cleanups, accessors are still sometimes type checked before
the AbstractStorageDecla and sometimes after. So things like
inferring final, dynamic and overrides have to be duplicated in
multiple places.
Fixes <https://bugs.swift.org/browse/SR-3840> and
<rdar://problem/30336146>.
Fixes SR-2757.
Variables in capture lists are treated as 'let' constants, which can
result in misleading, incorrect diagnostics. Mark them as such in order
to produce better diagnostics, by adding an extra parameter to the
VarDecl initializer.
Alternatively, these variables could be marked as implicit, but that
results in other diagnostic problems: capture list variables that are
never used produce warnings, but these warnings aren't normally emitted for
implicit variables. Other assertions in the compiler also misfire when
these variables are treated as implicit.
Another alternative would be to walk up the AST and determine whether
the `VarDecl`, but there doesn't appear to be a way to do so.