IsFirstPass is going away soon, but in the meantime, the next
patch regresses matters slightly and causes us to emit
duplicate diagnostics in more cases, so let's fix it.
Existential types don't support nested types so let's not
allow the lookup to make such access, with only exception
for typealias or associated types without type parameters,
they are currently allowed.
Resolves: rdar://problem/38505436
There was a path through associated type inference where we would end
up recording a type witness that contained an error, but for which we
had not reported that error, which would lead to downstream
crashes. Make sure that we reject such inferences.
And because it triggers once we fix this issue... make sure break
recursion when trying to resolve type witnesses lazily.
Fixes the crash in SR-6609 / rdar://problem/36038033, but we're still
failing to infer in those cases.
Eg, if both Foo and Bar are generic, Foo.Bar<Int> would crash.
This was introduced when I refactored the code a bit to combine
the code path for nominal types and generic typealiases. I was
a little too eager in merging them, because in fact the
substitution-based approach doesn't work when the parent type
is an unbound generic, which can occur in the nominal type case.
Note that we skip validation of generic parameters when the
parent type is an unbound generic. This is because there may
be requirements relating the generic arguments of the parent
type with the generic arguments of the nested type, and unless
all arguments are known, we cannot check these requirements.
For example:
struct Outer<T : Collection> {
struct Inner<U : Collection> where T.Element == U.Element { }
}
When Sema opens the unbound generic type by creating new type
variables for each generic argument, it will also introduce
constraints corresponding to each generic requirement. Therefore
constraint system will eventually fail if the arguments are
wrong.
Fixes <https://bugs.swift.org/browse/SR-5600>,
<rdar://problem/33655028>.
(...is constrained to be a subtype of another)
Previously the compiler would just mark the entry in the inheritance
clause invalid and move on without emitting any errors; in certain
circumstances in no-asserts builds this could actually lead to
everything working "correctly" if all conforming types happened to
pick the same concrete type for both associated types. In Swift 4 this
can actually be enforced with a same-type requirement, which will
guarantee that the two associated types are the same even in generic
contexts.
This fix avoids assertions and crashes, but the diagnostic is still
incorrect, and in the simple case of the inheritance clause it's
redundant. Doing something better and possibly even downgrading it to
a warning in Swift 3 mode is tracked by rdar://problem/32409449.
Initial patch by Slava, fixed up by me.
This was added at some point with the associated type where
clause work, but it appears to be unnecessary, because all
the tests passed with this removed.
It also introduced a source compatibility issue where we
stopped accepting typealiases to protocol compositions in
protocol inheritance clauses.
Add a test for this case too, since it wasn't tested before.
Fixes <https://bugs.swift.org/browse/SR-4855>.
When performing a name lookup from inside of a protocol
or extension, skip directly to the source file context
when we are done visiting the protocol or extension.
Otherwise, if we have invalid code where the protocol
or extension is nested inside another type, we might
find a member whose type contains generic parameters
of the outer type; these parameters will not resolve,
since we do not model protocols or extensions nested
inside generic contexts (yet?).
This supercedes an earlier workaround for a similar
issue; the new workaround fixes more crashes.
This is needed to avoid crasher regressions with an
upcoming patch.
In an extension of a nested type, the extended type must be
fully qualified.
Also clean up the diagnostic logic a little bit and centralize
it in diagnoseUnknownType().
Fixes <https://bugs.swift.org/browse/SR-4379>.
Previously we prohibited unbound generics in the underlying
type of a typealias, but due to an oversight the check was
not performed when resolving a nested type.
So this worked:
struct Outer { struct Inner<T> {} }
typealias OuterInner = Outer.Inner
let _: OuterInner<Int> = Outer.Inner<Int>()
However it was easy to cause a crash this way by stating an
unbound generic type where one was not expected. Also,
unqualified types in a typealias did not get this treatment,
so the following did not work:
typealias MyOptional = Optional
Formalize the old behavior by allowing unbound generic types
in the underlying type of a typealias, while otherwise
prohibiting unbound references to nested types.
Normally name lookup from a where clause walks up to the parent
DeclContext, so it does not need to handle outer generic parameters
specially. But with an extension of a nested type, the outer
DeclContext is the source file, and the extension itself has a
chain of GenericParamLists linked by the OuterParameters field.
We would misreport a cast from G<T> to G<Int> or vice versa
as always failing, because we were checking for an exact
subtype relationship instead of archetype binding.
Fixes <https://bugs.swift.org/browse/SR-3609>.
If the nested type itself has generic constraints, we would
hit an assertion in requirement inference. Refactor some code
so that we can make the assertion more accurate.
Fixes <rdar://problem/30353095>.
Within an extension, references to other members of the extended type
are permitted without qualification. This is intended to work even
when the extended type was a nested type, although members of the
enclosing type are /not/ visible in this case. In order to implement
this, the type checker pre-checks to see if there are /any/ members
with this name and then rewrites the unqualified reference to a
qualified one, based on an unresolved TypeExpr with the name of the
enclosing type. Unfortunately, if the enclosing type is a nested type,
that isn't going to work very well---we find the correct declaration,
but fail to map it into context by virtue of not realizing where it
came from. Fix this by explicitly checking for this case.
https://bugs.swift.org/browse/SR-3847
Neither of the following is supported:
func g<T>(_: T) {
_ = {
struct S {}
}
}
struct G<T> {
let fn = {
struct S {}
}
}
Even though nested generic types are supported, the second example
is more like a type inside a function than a type inside a type,
because 'S' has no parent type.
Technically this is source-breaking but since neither SILGen nor
IRGen knew how to generate code for these I doubt anything worked.
There's no need to walk up from a function or type context -- if
no generic signature (or environment) is set, the parent won't have
one, either, and if we're in the middle of validating the child
context, using the parent's signature or environment to resolve
dependent types is just wrong.
If one of the associated types is witnessed by a generic parameter
from the function's scope, make sure it maps down to an ErrorType
instead of leaving it as a type parameter, which triggers an
assertion.
Eventually we'll plumb it through properly.
We would falsely diagnose the occurrence of the protocol
_in the inheritance clause_ as a "bad" usage of an
existential type, because the UnsupportedProtocolVisitor
was too eager in walking into nested Decls and Stmts.
Note that in one case we don't emit a diagnostic where we
did before, but this doesn't matter; the VarDecl in
question becomes invalid later, and only the order in
which the decls are visited changes.
This patch contains several intertwined changes:
- Remove some unnecessary complexity and duplication.
- Adds a new TypeChecker::lookupUnqualifiedType() which bypasses most of
the logic in TypeChecker::lookupUnqualified(), such as the
LookupResultBuilder. Use this when resolving unqualified references
to types.
- Fixes for generic typealiases to better preserve the type parameters of
the parent type, and clean up the logic for applying the inner generic
arguments. Some uses of generic typealiases that used to crash now work,
and those tests have been uncommented.
- Avoid an unnecessary desugaring of TypeAliasDecls which map directly
to GenericTypeParamTypes. Once again this perturbs the source-stability
test.
- When looking up a nested type of a base class with a derived class base,
always use the base class as the parent of the nested type. This fixes
a recent regression where in some cases we were using the wrong parent.
Fixes <rdar://problem/29782186>.
and provide a fix-it to move it to the new location as referenced
in SE-0081.
Fix up a few stray places in the standard library that is still using
the old syntax.
Update any ./test files that aren't expecting the new warning/fix-it
in -verify mode.
While investigating what I thought was a new crash due to this new
diagnostic, I discovered two sources of quite a few compiler crashers
related to unterminated generic parameter lists, where the right
angle bracket source location was getting unconditionally set to
the current token, even though it wasn't actually a '>'.
trying to set the superclass on classes in such situations by setting the superclass of an invalid decl to the error type.
This fixes a bunch of compiler crashes, and also changes some errors in other tests where the main error is the invalid declaration and now the
downstream errors can be a bit different because the decl has been invalidated.
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.