It looks like migration fixits are done, and this doesn't
expose any new bugs that were not possible before, because
you could already define typealiases inside protocol
extensions.
To prevent some compiler_crasher regressions, add a simple
circularity-breaking hack. I'll need to do a sweep to clean
these up some day soon.
The IterativeTypeChecker now use loops instead of recursion to help keep the stack size low
We diagnose circular dependencies for protocols in a more efficient manner and also prevent the possibility of infinite loops
(in preparation for the private/fileprivate split)
An "access scope" is the outermost DeclContext where a particular
declaration may be referenced: for a 'fileprivate' declaration it's
the enclosing file, and for an 'internal' declaration it's the module.
'public' corresponds to a scope of "everything", represented by a null
DeclContext.
This model extends naturally to the (not-yet-implemented) SE-0025
notion of 'private', where the access scope is a declaration's
immediately enclosing DeclContext.
Complicating this model is the revised rules that allow, e.g., a public
declaration to be declared within an internal type. The access scope
for this declaration is still just the module, not "everything".
This commit reworks formal access control checking in terms of this
model, including tightening up some of the handling for '@testable'.
This implements the rule that you must be able to access a declaration's
type everywhere you can reference the declaration.
This was not intended to change compiler behavior, but in practice it
has made cross-file dependency tracking a bit more conservative
(unnecessarily), caught a mistake in diagnosing access violations,
and fixed a fuzzer-based crasher (see test changes).
Progress on SE-0025 ('private' and 'fileprivate')
Rather than synthesizing a global operator '==' for Equatable enums,
synthesize a member operator, which is more idiomatic and much
cleaner.
To make sure that these synthesized operators can actually be found,
start considering operator requirements in protocols
more generally in the type checker, so that, e.g., "myEnum == myEnum"
will type-check against Equatable.== and, on successful type-check,
will call the (newly-synthesized) witness for '=='. This both makes it
easier to make sure we find the operators in, e.g., complex multi-file
and lazy-type checking scenarios, and is a step toward the
type-checking improvements described in SE-0091.
Allow 'static' (or, in classes, final 'class') operators to be
declared within types and extensions thereof. Within protocols,
require operators to be marked 'static'. Use a warning with a Fix-It
to stage this in, so we don't break the world's code.
Protocol conformance checking already seems to work, so add some tests
for that. Update a pile of tests and the standard library to include
the required 'static' keywords.
There is an amusing name-mangling change here. Global operators were
getting marked as 'static' (for silly reasons), so their mangled names
had the 'Z' modifier for static methods, even though this doesn't make
sense. Now, operators within types and extensions need to be 'static'
as written.
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.
Previously getInterfaceType() would punt to getType() if no
interface type was set. This patch changes getInterfaceType()
to assert if no interface type is set, and updates various
places to set the interface type explicitly.
This brings us a step closer to removing PolymorphicFunctionType.
Rather than using a specialized matching rule in the type checker that
depends on having default arguments in types, use call argument
matching consistently.
Note #1: This (correctly) breaks some existing code that depends on
inferring a parameter type of () for a single-argument parameter from
a no-argument function type().
Note #2: This pessimizes a code completion test, where the code
completion engine seems to depend on some quirks of argument
matching. The "type relationship" matching needs non-trivial work.
The underlying type can now refer to generic parameters from an
outer context, and we allow qualified and unqualified access to
such typealiases.
One problem remains, with specializations of generic typealiases
in expression parsing context, marked with FIXME in the test.
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.
Another pre-emptive compiler_crasher regression fix.
I have an idea for consolidating some of these hacky circularity
checks in a nice way, but not now.
Every call to validateGenericTypeSignature() had the same
boilerplate following; move the common logic into that
function.
As one might expect, each callsite had slight variants on
the same underlying logic -- this makes them consistent.
Also, this slightly widens the scope during which
GenericTypeDecl::isValidatingGenericSignature() returns
true.
Interesting, that change introduces a diagnostic in an
existing testcase where previously there was none:
protocol P {
associatedtype T
}
struct S<A: P where A.T == S<A>> {}
While it looks like this generic signature was built
correctly, in fact I think we weren't computing
conformances for the substitution of 'A' in 'S<A>'.
After trying small variations on the above testcase,
I quickly ran into SILGen crashes, which the diagnostic
now prevents. A few interesting cases still crash.
See test/decl/protocol/req/recursion.swift for the
gory details.
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.
Mostly NFC, but note that DeclContext::getDeclaredInterfaceType()
returns Type() for invalid extensions, whereas the older way
of going through getAsNominalTypeOrNominalTypeExtensionContext()
would crash because we'd call getDeclaredInterfaceType() on a
null decl.
The old check was problematic because it would sometimes return
ErrorType from accessing the generic parameters of a type that was
in the process of having its generic signature validated.
Instead fix the root cause of the circularity, which was recursion
through resolveType() when resolving a type's inheritance clause.
To fix it, let's just not walk adopted protocols when looking up
the superclass of a class. Inheriting from an associated type does
not seem very useful, and will probably be hard to get right in
the general case.
I wasn't able to reduce a useful test case, but this patch prevents
compiler_crashers regressions with some other changes I'm working on.
This now fails with the infamous 'Assertion failed: ((conforms ||
replacement->is<ErrorType>() || firstArchetype->getIsRecursive() ||
isOpenedAnyObject(replacement) || replacement->is<GenericTypeParamType>())
&& "Constraint system missed a conformance?")' error.
The actual problem is something with unbound generics and inference
of generic parameters. Here's a minimal test case:
protocol A {}
struct B<f> {}
func a<T:A>() {
class AA {
var t:B=B()
}
}
I'll fix it soon.
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.
Goes back to Swift 2.2 behavior of treating the 'typealias' keyword inside a protocol as a deprecated form of an associatedtype. To get the newer (but still partly buggy) behavior of treating it as an actual typealias, add "-Xfrontend -enable-protocol-typealiases" to the compile invocation. 'decl/typealias/typealias.swift' now uses this flag to continue testing the enabled behavior.
Since there still are some holes in this feature, and I haven't had time to
fill them lately: Go back to the 2.2 behavior of treating 'typealias' keyword
in protocols as an associated type, and emit a deprecation warning.
Commented out tests specifically for typealiases in protocols for now, and
random validation tests that crash or not based on whether keyword is interpreted as associatedtype or typealias updated.