If return expression uses closure parameters, which have/are
type variables, such means that we won't be be able to
type-check result correctly and, unfornutately,
we are going to leak type variables from the parent
constraint system through declaration types.
In `checkTopLevelErrorHandling` if apply expression did not type-check,
don't attempt walking inside of it. This accounts for the fact that we don't
erase types without type variables to enable better code complication,
so DeclRefExpr(s) or ApplyExpr with DeclRefExpr as function contained
inside would have their types preserved, which makes classification
incorrect.
There might be erroneous typealiases present which re-define literal types,
so when trying to type-check something that supposed to confirm to erroneous
redeclaration by default, ignore it.
When running diagnostics for single expression closures,
explicitly disallow to produce solutions with unresolved type variables,
because there is no auxiliary logic which would handle that and it's
better to allow failure diagnosis to run directly on the closure body.
Currently isAnyHashableType method validates only structs but
it doesn't account for situation when type is represented via type
variable with type already fixed to AnyHashable, that results in
infinite loop in the solver because restriction [hashable-to-
anyhashable] is going to add new type variable recursively.
Instead of returning empty type when RValue destination of the assignment
could not be determined, let's return it unresolved directly instead and
let it be handled by coerceToType, which is going to produce special expression
(UnresolvedTypeConversionExpression) which facilitates better diagnostics.
Obtain type of the result expression without applying solutions,
because otherwise this might result in leaking of type variables,
since we are not reseting result statement and if expression is
sucessfully type-checked its type cleanup is going to be disabled
(we are allowing unresolved types), and as a side-effect it might
also be transformed e.g. OverloadedDeclRefExpr -> DeclRefExpr.
Otherwise, overload resolution and CSDiag disagree on what a viable
candidate is, so we can end up in a situation where the OverloadDeclRefExpr
has a concrete type that doesn't match the argument list in an ApplyExpr,
which causes a crash in CSDiag.
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.
Until recently we didn't allow nested generic types at all.
In Swift 3, generic typealiases were added, and we forgot to
guard against them in witness matching, leading to a crash if
a generic typealias witnesses an associated type requirement.
Now that nested generic nominals are allowed too, add a check.
The diagnostic is not very good, but I'll revisit this later.
This catches another case where resolveType() could cause infinite
recursion. No test case, but this prevents crashers from regressing
with a subsequent patch.
Right before generating constraints for the new system,
check if there are any BindOptionalExpr in the tree which
wrap DiscardAssignmentExpr, such situation corresponds to syntax
like - `_? = <value>`, since it doesn't really make
sense to have optional assignment to discarded LValue which can
never be optional, we can remove BOE from the tree and avoid
generating any of the uncessary constraints.
When SubstFlags::UseErrorTypes was on, we would return error types
if we couldn't resolve a nested type, but a missing primary parameter
would always remain unsubstituted in the result.
Now, replace primary parameters with error types also if they're
missing.
If it turns out that this crasher still needs "REQUIRES: no_asan" then it
isn't fixed and should be moved back to validation-test/compiler_crashers/
and marked with "not --crash" + "REQUIRES: asan" :-)
- 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.
The crashes fixed appeared at first to be related to IfConfigStmt
parsing, but are in reality symptoms of being too lax in what we accept
when parsing of sub-expressions fail.
Optional type annotation parsing used to propagate failures before it
was patched to ‘recover’ with an AnyPattern. Instead, we’ll just hit
the error path for parsing in the main expressions because what is here
now isn’t a reasonable thing to return.
#selector parsing assumed that the current token it was at after
consuming up to a right-brace wasn’t bogus. Instead, if we’ve got
here, we may as well just return a loc we know is valid: PreviousLoc.
When type-checking decls, we would ensure they don't reference
existential types formed from protocols with associated types
or 'Self' requirements. However this check was done in both
'stage 1' and 'stage 2', which meant it would be called
recursively from validateDecl().
Fix this by performing the check only once at the end of
type checking a source file.
Since retired constraints are re-added back to the circulation in LIFO
order, make sure that all of the constraints are added to the front of
SolverScope::retiredConstraints list.
This leads to some bad recursion through validateDecl(), even
when called from the ITC. We already had machinery to add
implicit constructors later, it just had to be extended to
do it for the superclass as well.
- In functions called from resolveType(), consistently
use a Type() return value to indicate 'unsatisfied
dependency', and ErrorType to indicate failure.
- Plumb the unsatisfiedDependency callback through the
resolution of the arguments of BoundGenericTypes, and
also pass down the options.
- Before doing a conformance check on the argument of a
BoundGenericType, kick off a TypeCheckSuperclass request
if the type in question is a class. This ensures we don't
recurse through NominalTypeDecl::prepareConformanceTable(),
which wants to see a class with a valid superclass.
- The ResolveTypeOfDecl request was assuming that
the request was satisfied after calling validateDecl().
This is not the case when the ITC is invoked from a
recursive call to validateDecl(), hack this up by returning
*true* from isResolveTypeDeclSatisfied(); otherwise we
assert in satisfy(), and we can't make forward progress
in this case anyway.
- Fix a bug in cycle breaking; it seems if we don't invoke
the cycle break callback on all pending requests, we end
up looping forever in an outer call to satisfy().
- Remove unused TR_GlobalTypeAlias option.