Until now, only indirect fields that didn't belong to a C union (somewhere
between the field declaration and the type in which it is indirectly
exposed) were imported in swift. This patch tries to provide an approach
that allows all those fields to be exposed in swift. However, the downside
is that we introduce new intermediate fields and types, some of the fields
may already have been manually defined in type extension (as seen with the
GLKit overlay).
The main idea here is that we can simply expose the anonymous
struct/unions from which the indirect types are taken and then use swift
computed properties to access the content of those anonymous
struct/unions. As a consequence, each time we encounter an anonymous
struct or union, we actually expose it at __Anonymous_field<id> (where id
is the index of the field in the structure). At this point, we use the
existing mechanism to expose the type as
__Unnamed_<struct|union>_<fieldname>. Then, each indirect field is exposed
as a computed property.
The C object:
typedef union foo_t {
struct {
int a;
int b;
};
int c;
} foo_t;
Is imported as
struct foo_t {
struct __Unnamed_struct___Anonymous_field1 {
var a : Int32
var b : Int32
}
var __Anonymous_field1 : foo_t.__Unnamed_struct___Anonymous_field1
var a : Int32 {
get {
return __Anonymous_field1.a
}
set(newValue) {
__Anonymous_field1.a = newValue
}
}
var b : Int32 {
get {
return __Anonymous_field1.b
}
set(newValue) {
__Anonymous_field1.b = newValue
}
}
var c : Int32
}
This has the advantage to work for both struct and union, even in case we
have several nested anonymous struct/unions. This does not require to know
the size and/or the offset of the fields in the structures and thus can be
properly implemented using front-end data.
Signed-off-by: Florent Bruneau <florent.bruneau@intersec.com>
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.
There's really not that much code shared between the accessor and
non-accessor cases in importMethodType, so split them up.
The one change here is that previously a method could /think/ it was
an accessor, but not be treated as one if the property decl has a
different getter or setter. Now such a method is just dropped by the
importer completely. It's intended that this is not a behavioral
change in that no real code should have such an AST.
This is building towards always having a consistent type for property
setters added in handlePropertyRedeclaration, which is
rdar://problem/29422993.
Once upon a time this was agnostic of the declaration being imported
(and possibly even still merged with importFunctionType) but that
hasn't been true for a while. If we're passing the ObjCMethodDecl
and ImportedName anyway, we don't need to separately pass the result
type, whether it's noreturn, and the Swift name as separate arguments.
No intended functionality change.
- The DeclContext versions of these methods have equivalents
on the DeclContext class; use them instead.
- The GenericEnvironment versions of these methods are now
static methods on the GenericEnvironment class. Note that
these are not made redundant by the instance methods on
GenericEnvironment, since the static methods can also be
called with a null GenericEnvironment, in which case they
just assert that the type is fully concrete.
- Remove some unnecessary #includes of ArchetypeBuilder.h
and GenericEnvironment.h. Now changes to these files
result in a lot less recompilation.
Changes:
* Terminate all namespaces with the correct closing comment.
* Make sure argument names in comments match the corresponding parameter name.
* Remove redundant get() calls on smart pointers.
* Prefer using "override" or "final" instead of "virtual". Remove "virtual" where appropriate.
- TypeAliasDecl::getAliasType() is gone. Now, getDeclaredInterfaceType()
always returns the NameAliasType.
- NameAliasTypes now always desugar to the underlying type as an
interface type.
- The NameAliasType of a generic type alias no longer desugars to an
UnboundGenericType; call TypeAliasDecl::getUnboundGenericType() if you
want that.
- The "lazy mapTypeOutOfContext()" hack for deserialized TypeAliasDecls
is gone.
- The process of constructing a synthesized TypeAliasDecl is much simpler
now; instead of calling computeType(), setInterfaceType() and then
setting the recursive properties in the right order, just call
setUnderlyingType(), passing it either an interface type or a
contextual type.
In particular, many places weren't setting the recursive properties,
such as the ClangImporter and deserialization. This meant that queries
such as hasArchetype() or hasTypeParameter() would return incorrect
results on NameAliasTypes, which caused various subtle problems.
- Finally, add some more tests for generic typealiases, most of which
fail because they're still pretty broken.
So when sorting, don't just jump directly to the Clang decl and get
its name, because there might not be a Clang decl; instead, use the
'objc' attribute if there is one and the protocol's base name if
not. We're not using ProtocolType::compareProtocols because we'd
rather not depend on knowing for sure which Clang module a protocol
lives in.
This wasn't caught until now because it required adopting a protocol
in Objective-C that itself adopted (directly or indirectly) at least
two protocols, at least one of which originally came from Swift.
rdar://problem/26232085
Objective-C classes that originally came from Swift use swift_name to
map /back/ to Swift, and of course lookup to resolve the native
declaration needs to use this. However, we're /already/ using this due
to the name coming from the general name-importing logic. Once upon a
time looking for a native decl probably ran before general
name-importing, but that's no longer true, so we can just delete this
with no expected change in behavior.
Remove all occurrences of a "useSwift2Name" bool, and replace it with
version plumbing. This means that ImportDecl is now entirely
version-based, and the importer Impl knows versions. This will be
needed for marking Swift 3 names as deprecated, when there is a new
Swift 4 name.
NFC.
In the case of the nullability change, this snuck all the way past the
type checker to result in an assertion failure in SILGen; if
assertions were turned off, it continued all the way through IRGen
before the LLVM verifier caught it.
We get in this situation because ObjCPropertyDecls in Clang aren't
considered "redeclared" like most other entities. Instead, they're
just matched up by name in a few places. At first I considered trying
to handle such canonicalization post hoc in Swift's importer, but that
would have turned into plenty of work for something that rarely comes
up at all. Instead, this patch just drops the setter from such a
redeclared property if it doesn't match up.
Clang itself should diagnose these kinds of mismatches; that's been
filed as rdar://problem/29536751 for nullability and a similar
rdar://problem/29222912 for changing types in general.
rdar://problem/29422993
Change the interfaces to ImportedName to be method based, rather than
direct struct field accesses. We're going to be changing how these are
used in the future. Also, we will be storing large quantities of
these, so we will soon want to crunch down on their size.
First, ensure all ParamDecls that are synthesized from scratch are given
both a contextual type and an interface type.
For ParamDecls written in source, add a new recordParamType() method to
GenericTypeResolver. This calls setType() or setInterfaceType() as
appropriate.
Interestingly enough a handful of diagnostics in the test suite have
improved. I'm not sure why, but I'll take it.
The ParamDecl::createUnboundSelf() method is now only used in the parser,
and no longer sets the type of the self parameter to the unbound generic
type. This was wrong anyway, since the type was always being overwritten.
This allows us to remove DeclContext::getSelfTypeOfContext().
Also, ensure that FuncDecl::getBodyResultTypeLoc() always has an interface
type for synthesized declarations, eliminating a mapTypeOutOfContext()
call when computing the function interface type in configureInterfaceType().
Finally, clean up the logic for resolving the DynamicSelfType. We now
get the interface or contextual type of 'Self' via the resolver, instead
of always getting the contextual type and patching it up inside
configureInterfaceType().
Rather than use importName using a set of options of what to choose,
phrase the API in terms of language version. Be explicit about what
version is being requested at the call site, as it's a necessary
consideration for the client.
After recent changes, this asserts on all decls that are not VarDecls,
so we can just enforce that statically now. Interestingly, this turns
up some dead code which would have asserted immediately if called.
Also, replace AnyFunctionRef::getType() with
AnyFunctionRef::getInterfaceType(), since the old
AnyFunctionRef::getType() would just assert when called on
a Decl.
Previously, for an Objective-C class method declaration that could be
imported as init, we were making 4 decls:
1) The Swift 2 init
2) The Swift 2 class method decl (suppressing init formation)
3) The Swift 3 init (omitting needless words)
4) The Swift 3 class method decl (suppressing init formation and
omitting needless words)
Decls 1), 2), and 4) exist for diagnostics and redirect the user at
3). But, 4) does not correspond to any actual Swift version name and
producing it correctly would require the user to understand how
omit-needless-words and other importer magic operates. It provides
very limited value and more importantly gets in the way of future
Clang importer refactoring. We’d like to turn Decl importing into
something that is simpler and language-version parameterized, but
there is no real Swift version to correspond to decl 4).
Therefore we will be making the following decls:
1) The "raw" decl, the name as it would appear to the user if they
copy-pasted Objective-C code
2) The name as it appeared in Swift 2 (which could be an init)
3) The name as it appeared in Swift 3 (which could be an init and omit
needless words)
This aligns with the language versions we want to import as in the
future: raw, swift2, swift3, …, and current.
Note that swift-ide-test prunes decls that are unavailable in the
current Swift version, so the Swift 2 non-init decls are not printed
out, though they are still present. Tests were updated and expanded to
ensure this was still the case.
ImportDecl has an alternate decl quasi-escape-hatch where it can
create alternative declarations for the same original Clang node. But,
it was limited at one, which worked accidentally in the case of
VisitObjCMethodDecl's attempts at importing a factory-init-suppressed
root-class method that points to the imported-as-init Swift
declaration.
This commit changes that to a TinyPtrVector, to support the upcoming
occasional case where we have more.
A pointless use of polymorphism -- the result values are not
interchangeable in any practical sense:
- For GenericTypeParamDecls, this returned getDeclaredInterfaceType(),
which is an interface type.
- For AssociatedTypeDecls, this returned the sugared AssociatedTypeType,
which desugars to an archetype.
- For TypeAliasDecls, this returned TypeAliasDecl::getAliasType(),
which desugars to a type containing archetypes.
- For NominalTypeDecls, this returned NominalTypeDecl::getDeclaredType(),
which is the unbound generic type, a special case used for inferring
generic arguments when they're not written in source.
Previously, getInterfaceType() would return getType() if no
interface type was set. Instead, always set an interface type
explicitly.
Eventually we want to remove getType() altogether, and this
brings us one step closer to this goal.
Note that ParamDecls are excempt from this treatment, because
they don't have a proper interface type yet. Cleaning this up
requires more effort.
Previously, getInterfaceType() would return getType() if no
interface type was set. Instead, always set an interface type
explicitly.
Eventually we want to remove getType() altogether, and this
brings us one step closer to this goal.
Note that ParamDecls are excempt from this treatment, because
they don't have a proper interface type yet. Cleaning this up
requires more effort.
Swift side of this new flag. This allows Objective-C framework authors
to replace a pair of methods by properties without breaking source
compatibility. This is especially important for class properties,
which were only introduced last year.
Still to come: importing the accessors even when this flag isn't set,
in order to provide better QoI when migrating from a method interface
to a property interface.
Part of rdar://problem/28455962