In the condition expressions of if, while and guard statements we were
throwing away the AST if there was a parse error in the condition, or
the brace statement was missing. This led to poor code-completion for
unresolved members (enums, options sets) because we couldn't find the
parent expression to type-check.
There are a few minor diagnostic changes because we now do more
type-checking of these conditions, particularly if they end up
containing an unused closure.
SR-2001
Consider this code:
struct A<T> {
struct B {}
struct C<U> {}
}
Previously:
- getDeclaredType() of 'A.B' would give 'A<T>.B'
- getDeclaredTypeInContext() of 'A.B' would give 'A<T>.B'
- getDeclaredType() of 'A.C' would give 'A<T>.C'
- getDeclaredTypeInContext() of 'A.C' would give 'A<T>.C<U>'
This was causing problems for nested generics. Now, with this change,
- getDeclaredType() of 'A.B' gives 'A.B' (*)
- getDeclaredTypeInContext() of 'A.B' gives 'A<T>.B'
- getDeclaredType() of 'A.C' gives 'A.C' (*)
- getDeclaredTypeInContext() of 'A.C' gives 'A<T>.C<U>'
(Differences marked with (*)).
Also, this change makes these accessors fully lazy. Previously,
only getDeclaredTypeInContext() and getDeclaredIterfaceType()
were lazy, whereas getDeclaredType() was built from validateDecl().
Fix a few spots where the return value wasn't being checked
properly.
These functions return ErrorType if a circularity was detected via
the generic parameter list, or if the extension did not resolve.
They return Type() if the extension cannot be resolved *yet*.
This is pretty subtle, and I'll need to do another pass over
callers of these functions at some point. Many of them should be
moved over to use getSelfInContext(), getSelfOfContext() and
getSelfInterfaceType() instead.
Finally, this patch consolidates logic for diagnosting invalid
nesting of types.
The parser had some code for protocols in bad places and bad things
inside protocols, and Sema had several different bail-outs for
bad things in protocols, nested generic types, and stuff nested
inside protocol extensions.
Combine all of these into a single set of checks in Sema. Note
that we no longer give up early if we find invalid nesting.
Leaving decls unvalidated and un-type-checked only leads to
further problems. Now that all the preliminary crap has been
fixed, we can go ahead and start validating these funny nested
decls, actually fixing some crashers in the process.
There was a weirdness with ProtocolType::get() that was causing me grief
while trying to refactor getDeclaredType() and related code in another
patch.
Instead of caching the result like we do elsewhere, this would directly
store the new type into the ProtocolDecl. This is smelly, so let's not
do that.
There was a weird corner case with nested generic functions that
would fail in the SIL verifier with some nonsense about archetypes
out of context.
Fix this the "right" way, by re-working Sema function declaration
validation to assign generic signatures in a more principled way.
Previously, nested functions did not get an interface type unless
they themselves had generic parameters.
This was inconsistent with methods nested inside generic types,
which did get an interface type even if they themselves did not
have a generic parameter list.
There's some spill-over in SILGen from this change. Mostly it
makes things more consistent and fixes some corner cases.
With the previous resolveTypeInContext() patch, a few compiler
crashers regressed with this problem, presumably because we were now
performing lookups in more contexts than before.
This is a class of problems where we would attempt a recursive
validation:
1) Generic signature validation begins for type T
2) Name lookup in type context finds a non-type declaration D nested in T
3) Generic signature validation begins for D
4) The outer generic context of D is T, but T doesn't have a generic
signature yet
The right way to break such cycles is to implement the iterative
decl checker design. However when the recursion is via name lookup,
we can try to avoid the problem in the first place by not validating
non-type declarations if the client requested a type-only lookup.
Note that there is a small semantic change here, where programs that
were previously rejected as invalid because of name clashes are
now valid. It is arguable if we want to allow stuff like this or not:
class A {
func A(a: A) {}
}
or
class Case {}
enum Foo {
case Case(Case)
}
However at the very least, the new behavior is better because it
gives us an opportunity to add a diagnostic in the right place
later. The old diagnostics were not very good, for example the
second example just yields "use of undeclared type 'Case'".
In other examples, the undeclared type diagnostic would come up
multiple times, or we would generate a cryptic "type 'A' used within
its own definition".
As far as I understand, this should not change behavior of any existing
valid code.
This is a big refactoring of resolveTypeInContext() which makes
the function clearer to understand by merging various special
cases and generalizing the logic for walking parent and superclass
contexts to cover more cases.
This improves typealiases in protocols a bit:
1) Previously a typealias in a protocol either had to be concrete,
or consist of a single path of member types from Self, eg
Self.A.B. Lift this restriction, so we can now write things like
protocol Fireworks {
associatedtype Exploding
typealias Exploder = Exploding -> [Exploding]
}
2) Protocol typealiases can now be accessed via qualified lookup
on concrete types. Getting this working for unqualified lookup
requires further refactorings which will be in a subsequent
patch.
This reverts commit 586288312c. It broke
tests:
Swift :: IDE/complete_override_access_control.swift
Swift :: IDE/complete_value_expr.swift
Swift :: SourceKit/DocSupport/doc_swift_module.swift
Swift :: decl/typealias/associated_types.swift
Swift :: decl/typealias/typealias.swift
Previously a typealias in a protocol either had to be concrete,
or consist of a single path of member types from Self, eg
Self.A.B. Lift this restriction.
Fix a few other corner cases that came up in the validation
suite, and clean up the function in general.
Now that we have ArchetypeBuilder::mapTypeOutOfContext(), we can
delete some tricky hand-crafted logic for getting the depth and
index of archetypes.
Notice that the depth of an archetype is now the same as generic
parameters, where depth 0 is the outermost generic context.
Previously it was backwards.
Mostly NFC, except that a few IDE crashers are now fixed because
of asserts firing in removed code, and also the change to depth
mangling (which I think makes sense, and it matches what's written
in docs/ABI.rst).
We don't actually want to skip non-type contexts here, since we should
only be showing override completions in the type context itself. This
was pretty obscure to hit in practice, but I noticed it while fixing the
crasher.
This allows us to get override completions correct when
* There are multiple decls on one line
* The preceding attributes/keywords span multiple lines
Resolving a longstanding FIXME.
Expand the "skip" functions in the parser to be more careful about
not skipping passed a #endif or a code completion token, since they
are synchronization points for the parser.
The fix was to change Parser::delayParseFromBeginningToHere to use
a manual loop instead of skipUntil (which can stop early for non-EOF
tokens).
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().
A literal in a sub-expression of the right-most expression in a sequence
could accidentally still have an error-type when going through CSApply.
rdar://problem/23488528