Using these in declaration position has been deprecated and
removed in Swift 3. These attributes were not being parsed and
contained deadweight diagnostics that should have been moved
when these attributes became type attributes.
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.
The outside representation already went to a flat set of requirements;
make the internal representation match so we aren't tempted to use the
requirement signature as inputs to a generic signature.
Rather than pretend that the requirement signature of a protocol is a
full, well-formed generic signature that one can meaningfully query,
treat it as a flat set of requirements. Nearly all clients already did
this, but make it official. NFC
With the introduction of special decl names, `Identifier getName()` on
`ValueDecl` will be removed and pushed down to nominal declarations
whose name is guaranteed not to be special. Prepare for this by calling
to `DeclBaseName getBaseName()` instead where appropriate.
Printing a declaration's name using `<<` and `getBaseName()` is be
independent of the return type of `getBaseName()` which will change in
the future from `Identifier` to `DeclBaseName`
Layout for an enum depends very intimately on its cases---both their
existence and what their payload types are. That means there's no way
to "partly" recover from failure to deserialize an individual case's
payload type, the way we can partly recover from failing to
deserialize an initializer in a class. Add deserialization recovery
to enums by validating all of their payload types up front, and
dropping the enum if we can't import all of the cases.
This is the first time where we're trying to do deserialization
recovery for a /type/, and that could have many more ripple effects
than for a var/func/subscript/init. A better answer here might be to
still import the enum but mark it as unavailable, but in that case
we'd have to make sure to propagate that unavailability to anything
that /used/ the enum as well. (In Swift, availability is checked based
on use of the name, so if someone manages to refer to an enum using
inferred types we'd be in trouble.)
There is one case here that's not covered: if an enum case has a
payload that references a type declaration nested within the enum, but
then that nested type /itself/ can't be loaded for some reason, we
have no way to check that up front, because we can't even try to load
the nested type without loading its parent DeclContext (the enum). I
can't think of an easy solution for this right now.
(In the future, we'll be able to support dropping a single case for
resilient enums. But we're not there right now.)
rdar://problem/31920901
Previously we recorded the canonical type of the declaration and made
sure we could deserialize that, but that's a lot of extra work
building up intermediate types that we mostly don't need. Instead,
record smaller types that represent the possible points of failure---
right now, just the nominal types that are referenced by the value
(function, variable/constant, subscript, or initializer). I chose to
use types instead of declarations here because types can potentially
encode more complicated constraints later (such as generic types
checking that their arguments still conform).
This gains us back 20% of type-checking time on a compile-time
microbenchmark: `let _ = [1, 2]`. I expect the effect is less dramatic
the more expressions you have, since we only need to deserialize
things once.
Fixes a class of deserialization issues in the merge-modules
step.
The setup was the following:
- File A defines a typealias A whose underlying type is a nested
type S of a type T, defined in a different module.
- File B defines an extension of T, and the extension member's
type references A.
When deserializing A, we would proceed to deserialize the
underlying type, which references T.S. This would first deserialize
T and perform a name lookup to find S, which would deserialize all
members, including pulling in extensions. Deserialization of the
extension defined in file B would then fail, because the declaration
for A is not yet available.
We had a previous fix for these problems in the single-module case;
a per-file lookup table mapping mangled nested type names to
declarations, allowing a nested type to be deserialized without
pulling in all members and extensions of its parent type.
This patch generalizes the nested type lookup table allowing it to
be used to resolve cross-module references as well. Also, we were
only writing out the nested type table when serializing a partial
swiftmodule corresponding to a source file. Removing this check
allows the nested type table to be serialized for modules built
with WMO enabled as well, such as the standard library.
Fixes <rdar://problem/30976604> and
<https://bugs.swift.org/browse/SR-4208>.
Make generic environment deserialization lazy, which eliminates a
significant amount of up-front work. Most clients only need the
generic signature, not the full generic environment.
This isn't an inherent limitation of the language---in fact, it would
be a problem for library evolution if you had to know a superclass's
full vtable contents to generate the vtable for a subclass. However,
that's exactly where we are today, and that's not going to change for
Swift 4.
One small hole in the Swift 3 / Swift 4 story.
More rdar://problem/31878396
This means both not crashing when we deserialize the protocol but
also emitting correct offsets for dynamic dispatch through the
protocol's witness table.
Also fix a bug with vtable and witness table slots for
materializeForSet accessors for properties that can't be
imported. Because materializeForSet doesn't have the type of the
property in its signature, it was taking a different failure path from
everything else, and that failure path didn't properly set the name or
flags for the missing member.
Finishes rdar://problem/31878396
As such, we no longer insert two placeholders for initializers that
need two vtable slots; instead we record that in the
MissingMemberDecl. I can see MissingMemberDecl growing to be something
we'd actually show to users, that can be used for other kinds of
declarations that don't have vtable entries, but for now I'm not going
to worry about any of that.
That is, whether an initializer is 'required', and either does not
override anything or overrides a non-required initializer. We don't
use this for anything now, but it'll show up in the next commit.
Deserializing a witness record in a conformance may fail if either of the requirement or witness changed name or type, most likely due to SDK modernization changes across Swift versions. When this happens, leave an opaque placeholder in the conformance to indicate that the witness exists but we don't get to see it. For expedience, right now this just witnesses the requirement to itself, so that code in the type checker or elsewhere that tries to ad-hoc devirtualize references to the requirement just gets the requirement back. Arguably, we shouldn't include the witness at all in imported conformances, since they should be an implementation detail, but that's a bigger, riskier change. This patch as is should be enough to address rdar://problem/31185053.
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.
A cross-reference in a module cannot refer to a parsed entity, because the parsed entity couldn’t have been seen when the module was built. Filter these out, which prevents a crash in the subsequent commit.
Finishes up the "big four" non-type decl kinds. Unfortunately,
indiscriminately dropping members from a class affects the layout
of its vtable. That issue is tracked by rdar://problem/31878396.
If there's an error deserializing part of a type, just propagate it
out. Also add support for bound generic types. This isn't meant to be
full coverage of possible failures, just ones that are likely to come
up through the C/ObjC importer.
Still to do:
- Generic function types (only show up on functions)
- Unbound generic types (only show up on typealiases, which I may not
even tackle)
Proof-of-concept for the above. This shouldn't be common---renames are
far more likely, and those we can track---but occurs when the
swift_wrapper attribute (the implementation of NS_STRING_ENUM) is
active in Swift 4 but not in Swift 3.
Note that this only checks the canonical interface type of the
declaration, because the non-canonical type may contain references to
the declaration's generic parameters.
The next commits will need access from ModuleFile.cpp.
Also stop pretending we care what kind of error we got back, or that
we might get back random other errors that weren't accounted
for. That's good for crash logs, but not actually interesting here.
(Nearly every place that previously looked for OverrideError will
also accept the upcoming TypeError.)
No effective functionality change.
This keeps us from showing Swift 3 names in Swift 4 code;
unfortunately, as the test case shows, we still have a few cases where
Swift /4/ names will leak into Swift /3/ code. I'm considering this an
acceptable state of events for now.
This is the same as the last few commits, but with the additional
complication of designated initializers affecting other behavior
around the type. In particular, convenience initializers cannot be
invoked on subclasses if the designated initializers are not all
present on the subclass. If a designated initializer is dropped, it's
not possible to satisfy that.
It would be nice to do better here, since a class's initializers are
mostly independent of the superclass's initializers. Unfortunately, it
still affects whether /this/ class can inherit convenience
initializers, as well as vtable layout. This is conservative, at
least.
In order to accomplish this, cross-module references to typealiases
are now banned except from within conformances and NameAliasTypes, the
latter of which records the canonical type to determine if the
typealias has changed. For conformances, we don't have a good way to
check if the typealias has changed without trying to map it into
context, but that's all right---the rest of the compiler can already
fall back to the canonical type.
Add a 'hasExplicitAnyObject()' bit to ProtocolCompositionType
to represent canonical composition types containing '& AnyObject'.
Serialize this bit and take it into account when building
ExistentialLayouts.
Rename ProtocolCompositionType::getProtocols() to getMembers()
since it can contain classes now, and update a few usages that
need further attention with FIXMEs or asserts.
For now, nothing actually constructs these types, and they will
trigger arounds asserts. Upcoming patches will introduce support
for this.
This is a step further from gracefully handling structural changes
to the module format, but we're nowhere near that anyway. At least
avoid the silly mistakes.
Like the previous commit, but with added trickiness because we also
serialize the form of the PatternBindingDecl a property came from.
Make getPattern handle a failure in the simple case that overrides
use, and pass that up to the PatternBindingDecl initialization. (This
can result in zero-element PatternBindingDecls, but that's fine.)
'getPattern' is also a change from 'maybeGetPattern', but every caller
knows how many patterns it expects, so accomodating the "maybe" case
is no longer important.
That is, a Swift 3 target imported into a Swift 4 context or vice
versa. This requires serializing the compatibility mode explicitly,
instead of including it in the textual version string that's only
for debugging.
Protocols can't have methods marked 'override'. Class contexts should
always be fine to drop a method that's an override (once the rest of
the world can handle it).