The list of directly inherited protocols of a ProtocolDecl is already
encoded in the requirement signature, as conformance constraints where
the subject is Self. Gather the list from there rather than separately
computing/storing the list of "inherited protocols".
The root cause is that NormalProtocolConformance::forEachValueWitness()
needs to skip protocol members that are not requirements.
Otherwise we end up passing such a non-requirement member down to
NormalProtocolConformance::getWitness() and hit an assert when we
cannot find it.
It looks like this code path was only ever hit from SourceKit.
The fix moves TypeChecker::isRequirement() to a method on ValueDecl,
and calls it in the right places.
Fixes <https://bugs.swift.org/browse/SR-3815>.
This is in preparation for generic subscripts, which will also
expose methods like getGenericSignature(), and so on.
ExtensionDecl, GenericTypeDecl and AbstractFunctionDecl all share
code. Instead of copy and pasting it yet again into SubscriptDecl,
factor it out into a common base class.
There are more yaks to shave here, but this is a step in the right
direction.
Reimplement the RequirementSource class, which captures how
a particular requirement is satisfied by a generic signature. The
primary goal of this rework is to keep the complete path one follows
in a generic signature to get from some explicit requirement in the
generic signature to some derived requirement or type, e.g.,
1) Start at an explicit requirement "C: Collection"
2) Go to the inherited protocol Sequence,
3) Get the "Iterator" associated type
4) Get its conformance to "IteratorProtocol"
5) Get the "Element" associated type
We don't currently capture all of the information we want in the path,
but the basic structure is there, and should also allow us to capture
more source-location information, find the "optimal" path, etc. There are
are a number of potential uses:
* IRGen could eventually use this to dig out the witness tables and
type metadata it needs, instead of using its own fulfillment
strategy
* SubstitutionMap could use this to lookup conformances, rather than
it's egregious hacks
* The canonical generic signature builder could use this to lookup
conformances as needed, e.g., for the recursive-conformances case.
... and probably more simplifications, once we get this right.
Only those types can be de-mangled by the ObjC runtime anyway.
Also move this mangling logic into the ASTMangler class. This avoids keeping the old mangler around just for that purpose.
This addresses a crash where the compiler asks if an imported class
inherits initializers from its superclass /during the SIL passes/. In
this particular arrangement of subclasses and initializers (see test
case), this leads to us importing members of an Objective-C class for
the first time well after we've destroyed the type checker, and then
checking to see if an initializer added in a Swift extension can
prevent initializer inheritance. That initializer hasn't been
type-checked (because it's in another file and isn't supposed to
affect anything), and so the compiler chokes. A spot fix would merely
check for 'resolver' here and skip over the initializer if it doesn't
have a type, but it's not clear what the right semantics are in that
case.
The real issue here is that we don't support importing new declarations
after the type checker has been torn down, and that keeps causing us
problems, but that's a much bigger thing to fix.
https://bugs.swift.org/browse/SR-3853
ArchetypeBuilder::finalize() is needed to tie up any loose ends before
requesting a generic signature or generic environment. Make sure it
gets called consistently.
Storing this separately is unnecessary since we already
serialize the enum element's interface type. Also, this
eliminates one of the few remaining cases where we serialize
archetypes during AST serialization.
This is a generic signature that stores exactly the requirements that a
protocol decl introduces, not letting them be implied by the Self :
Protocol requirement, nor storing any requirements introduced by the
protocols requirements.
Specifically, suppose we have
protocol Foo {}
protocol Bar {}
protocol Baz {
associatedtype X : Foo
}
protocol Qux: Baz {
associatedtype X : Bar
}
The normal generic signature and (canonical) protocol requirement
signature of `Baz` will be, respectively
<Self where Self : Baz>
<Self where Self : Baz, Self.X : Foo>
And for `Qux`, they will be:
<Self where Self : Qux>
<Self where Self : Qux, Self : Baz, Self.X : Bar>
Note that the `Self.X : Foo` requirement is not listed.
For the moment, this is unused except for `-debug-generic-signatures`.
The typedef `swift::Module` was a temporary solution that allowed
`swift::Module` to be renamed to `swift::ModuleDecl` without requiring
every single callsite to be modified.
Modify all the callsites, and get rid of the typedef.
This is intended to have no functional effect, but there was a
minor change to a diagnostic in invalid code in the tests for the
unfinished ASTScope code; I hope I didn't break anything more
fundamental there.
We might allow protocols inside non-generic class/struct/enum
declarations eventually; there's no conceptual difficulty, just
some IRGen and Serialization work that has to happen first.
Also, this fixes a crasher :-)
Now, the following are both true or both false:
- AFD->getDeclContext()->isTypeContext()
- AFD->getImplicitSelfDecl() != nullptr
Also, if var->isSelfParameter() returns true, then it is also
the case that var == var->getDeclContext()->getImplicitSelfDecl().
Protocol methods returning optionals, metatypes and functions
returning 'Self' are now handled correctly in Sema when
accessed with a base of existential type, eg:
protocol Clonable {
func maybeClone() -> Self?
func cloneMetatype() -> Self.Type
func getClonerFunc() -> () -> Self
}
let c: Clonable = ...
let _: Clonable = c.maybeClone()
let _: Clonable.Type = c.cloneMetatype()
Previously, we were unable to model this properly, for
several reasons:
- When opening the function type, we replaced the return
value in openedFullType _unconditionally_ with the
existential type. This was broken if the return type
was not the 'Self' parameter, but rather an optional,
metatype or function type involving the 'Self' parameter.
- It was also broken because we lost information; if the
return type originally contained an existential, we had
no way to draw the distinction. The 'hasArchetypeSelf()'
method was a hint that the original type contained a
type parameter, but it was inaccurate in some subtle cases.
- Since we performed this replacement on both the
'openedFullType' and 'openedType', CSApply had to "undo"
it to replace the existential type with the opened
existential archetype. This is because while the formal
type of the access returns the existential type, in
reality it returns the opened type, and CSApply has to
insert the correct ErasureExpr.
This was also done unconditionally, but even if it were
done more carefully, it would do the wrong thing because
of the 'loss of information' above.
- There was something fishy going on when we were dealing
with a constructor that was declared on the Optional type
itself, as seen in the fixed type_checker_crasher.
- TypeBase::eraseOpenedExistential() would transform a
MetatypeType of an opened existential into a MetatypeType
of an existential, rather than an ExistentialMetatypeType
of the existential type.
The new logic has the following improvements:
- When opening a function type, we replace the 'Self' type
parameter with the existential type in 'openedType', but
*not* 'openedFullType'. This simplifies CSApply, since it
doesn't have to "undo" this transformation when figuring
out what coercions to perform.
- We now only use replaceCovariantResultType() when working
with Self-returning methods on *classes*, which have more
severe restrictions than protocols. For protocols, we walk
the type using Type::transform() and handle all the cases
properly.
- Not really related to the above, but there was a whole
pile of dead code here concerning associated type references.
Note that SILGen still needs support for function conversions
involving an existential erasure; in the above Clonable example,
Sema now models this properly but SILGen still crashes:
let _: () -> Clonable = c.getClonerFunc()
Fixes <rdar://problem/28048391>, progress on <rdar://problem/21391055>.
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.
This gives us much better diagnostics around things like
escaping-mismatched function parameters which would previously skip
this and produce bogus invalid conversion errors between “identical”
types.
Previously, validateDecl() would check if the declaration had an
interface type and use that as an indication not to proceed.
However for functions we can only set an interface type after
checking the generic signature, so a recursive call to validateDecl()
on a function would "steal" the outer call and complete validation.
For generic types, this meant we could have a declaration with a
valid interface type but no generic signature.
Both cases were problematic, so narrow workarounds were put in
place with additional new flags. This made the code harder to
reason about.
This patch consolidates the flags and establishes new invariants:
- If validateDecl() returns and the declaration has no interface
type and the isBeingValidated() flag is not set, it means one
of the parent contexts is being validated by an outer recursive
call.
- If validateDecl() returns and the declaration has the
isBeingValidated() flag set, it may or may not have an interface
type. In this case, the declaration itself is being validated
by an outer recursive call.
- If validateDecl() returns and the declaration has an interface
type and the isBeingValidated() flag is not set, it means the
declaration and all of its parent contexts are fully validated
and ready for use.
In general, we still want name lookup to find things that have an
interface type but are not in a valid generic context, so for this
reason nominal types and associated types get an interface type as
early as possible.
Most other code only wants to see fully formed decls, so a new
hasValidSignature() method returns true iff the interface type is
set and the isBeingValidated() flag is not set.
For example, while resolving a type, we can resolve an unqualified
reference to a nominal type without a valid signature. However, when
applying generic parameters, the hasValidSignature() flag is used
to ensure we error out instead of crashing if the generic signature
has not yet been formed.
- 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.
- 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.
When deserializing the generic environment for a generic type, only
immediately deserialize the generic signature. The generic environment
will be deserialized later, when it's needed.
When we deserialize a function that has a generic environment, set the
generic signature and a key to allow lazy creation of the generic
environment. Because most clients won't need the generic environment,
this lets us avoid creating generic environments.