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 :-)
We "fake" a conformance of UnresolvedType to any protocol.
Instead of returning a concrete conformance, return an
abstract conformance. The concrete conformance had several
problems leading to further crashes:
- The DC was set to a module, not a type declaration context,
since there is not type declaration context here.
- The conformance was marked complete even though it was missing
inherited conformances.
When inserting a new value, assert that there's no existing
value at that key, and to avoid the assert firing when
opening up UnboundGenericTypes, put those replacements in
their own map. We don't need them later.
If the 'override' attribute appears on an invalid decl,
it is removed at the start of typeCheckDecl(). However if
the decl is nested inside a multi-statement closure which
is invalid for other reasons, we may have validated it
but not type checked it, in which case we don't want to
crash in the verifier.
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().
In a generic signature like <T, U where T.A == U>, there is only
one primary archetype, 'T'. 'U' will not appear in SubstitutionMaps,
and the SubstitutionMap version of Type::subst() cannot handle an
interface type containing 'U'.
For interface types, there are two levels of canonicalization:
- The AST-level getCanonicalType() which strips away sugar
- The GenericSignature-level getCanonicalTypeInContext() which
replaces each interface type in an equivalence class with a
representative
SILFunctionTypes must be canonical with respect to a generic
signature.
When emitting re-abstraction thunks we could end up constructing
a SILFunctionType containing 'U', because we were calling
getCanonicalType() on the result of mapTypeOutOfContext().
Fix this by making sure to use getCanonicalTypeInContext() on
the result of mapTypeOutOfContext(), just as we do in capture
lowering.
Unfortunately I worry this problem will come up again in a
different form -- a more general fix would change
mapTypeOutOfContext() to always return "generic signature
canonical" types, and also fix SubstitutionMaps to understand
same type constraints better.
Fixes <https://bugs.swift.org/browse/SR-3326>.
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>.
When we have a value 'p' of type 'P.Type' for some protocol 'P',
we require the user to write 'p.init()' rather than 'p()' to
construct an instance of a concrete type conforming to 'P'.
If they write 'p()', we suggest a fixit to insert '.init',
however if there is also a subsequent member access on the
result, for example 'p().foo', we would crash.
Another invalid case that used to crash is when you construct
a protocol metatype directly and then access a member of it,
eg. 'P().foo'.
Be sure to lower the payload type of UnsafeMutablePointer and friends
before converting them, because the Clang type converter expects
optionals to have lowered payloads already.
Also, remove the FunctionType path; with the above change AST-level
function types should no longer show up here.
Fixes <https://bugs.swift.org/browse/SR-2702>.
Currently if destination is unresolved instead of trying to re-typecheck
it again and diagnose structural problems which led to such outcome, it
gets completely ignored in favor of trying to type-check source without
contextual type. That leads to missed diagnostic opportunities, which
results in problems on AST verification and SIL generation stages, and
generally missleading errors e.g. `.x = 0`.
Resolves: SR-3506.
Invalid ASTs like the one in 28625 cause Parse to generate an AST that
looks a heck of a lot like a constructor call, however this makes no
sense as the type in question is a TupleType and lookup asserts in such
cases. Guard against this so we don't crash diagnosing.
Recursive references of computed properties are allowed, but warned
about. Closures `var`s built like the one in 28396 should crash at
runtime, not crash the compiler.
This used to cause SILGen to capture and subsequently load `self` as a
constant. Then, when the super call was SILGen’d, it assumed that
`self` would be loaded Boxed. Diagnose before hitting SILGen so we
don’t have to pollute Lowering with code that handles `self` in this
odd position.
Crashers fixed are minor logic errors:
Patterns: Crash occurred when requesting the range of a created
Pattern. Validity of the range should be checked before returning it
to keep the entire range valid or invalid but never both.
ParseExpr/ParsePattern: The same fixes as the ones provided in #6319
CSDiag: The generic visitor needn’t look through TypeVarTypes either.
Marking such type variable as "must be materializable" is going to explicitly
enforce the notion that assignment destination type can only be materializable
and situations like source expression is InOutExpr are incorrect.
If T0 must be materializable and it's bound to T1, when matching T0 to
possibly optinal T1, look through optinality when setting materializability of the binding.