The moment you've all been waiting for...
Define InterfaceTypeRequest and use it to, well, compute the interface
type. This naturally widens the few cycles that we pick up with the
request evaluator.
There is still a lot of work to get done here, mostly around scaling
back all of the ad-hoc circularity checks around the interface type
computation. It would also be great to improve the circularity
diagnostics.
Switch most callers to explicit indices. The exceptions lie in things that needs to manipulate the parsed output directly including the Parser and components of the ASTScope. These are included as friend class exceptions.
Use it to provide an idealized API for the VarDecl case in validateDecl.
In reality, a lot of work is needed to rationalize the dependency
structure of this request. To start, the callers of
typeCheckPatternBinding must be eliminated piecemeal. Once that is
done, the AST should introduce pattern binding decls along all the
places where getParentStmt() used to apply.
When Decl::getLoc() is called upon a serialized AST and the
serialized source location is available, we lazily open the
external buffer and return a valid SourceLoc instance pointing
into the buffer.
Inline the interface type reset into its callers and make sure they're
also setting the invalid bit - which this was not doing before.
Unfortunately, this is not enough to be able to simplify any part of var
decl validation.
This is an amalgam of simplifications to the way VarDecls are checked
and assigned interface types.
First, remove TypeCheckPattern's ability to assign the interface and
contextual types for a given var decl. Instead, replace it with the
notion of a "naming pattern". This is the pattern that semantically
binds a given VarDecl into scope, and whose type will be used to compute
the interface type. Note that not all VarDecls have a naming pattern
because they may not be canonical.
Second, remove VarDecl's separate contextual type member, and force the
contextual type to be computed the way it always was: by mapping the
interface type into the parent decl context.
Third, introduce a catch-all diagnostic to properly handle the change in
the way that circularity checking occurs. This is also motivated by
TypeCheckPattern not being principled about which parts of the AST it
chooses to invalidate, especially the parent pattern and naming patterns
for a given VarDecl. Once VarDecls are invalidated along with their
parent patterns, a large amount of this diagnostic churn can disappear.
Unfortunately, if this isn't here, we will fail to catch a number of
obviously circular cases and fail to emit a diagnostic.
VarDecls inherit their TypeRepr from their enclosing pattern, if any.
To retrieve the TypeRepr attached to a VarDecl or a ParamDecl in
a uniform way, the getTypeReprOrParentPatternTypeRepr API has been
provided.
TypeCheckPattern used to splat the interface type into this, and
different parts of the compiler would check one or the other. There is
now one source of truth: The interface type. The type repr is now just
a signal that the user has written an explicit type annotation on
a parameter. For variables, we will eventually be able to just grab
this information from the parent pattern.
validateDecl() no longer explicitly validates the result TypeLoc.
Instead, the request is triggered via validateDecl() calling
computeType() on the FuncDecl or SubscriptDecl.
In preparation for landing the ResultTypeRequest, let's compute
the result type directly from the declaration. For now, this still
forces getInterfaceType() to be computed, but that will go away
next.
Since getSpecifier() now kicks off a request instead of always
returning what was previously set, we can't pass a ParamSpecifier
to the ParamDecl constructor anymore. Instead, callers either
call setSpecifier() if the ParamDecl is synthesized, or they
rely on the request, which can compute the specifier in three
specific cases:
- Ordinary parsed parameters get their specifier from the TypeRepr.
- The 'self' parameter's specifier is based on the self access kind.
- Accessor parameters are either the 'newValue' parameter of a
setter, or a cloned subscript parameter.
For closure parameters with inferred types, we still end up
calling setSpecifier() twice, once to set the initial defalut
value and a second time when applying the solution in the
case that we inferred an 'inout' specifier. In practice this
should not be a big problem because expression type checking
walks the AST in a pre-determined order anyway.
When an EnumElementDecl is parsed, we create the parameter list before
creating the EnumElementDecl itself, so we have to re-parent those
ParamDecls just like we do for functions and subscripts.
Remove the early return in the case where one of our parent contexts was
being validated, and replace it with a simpler check that is only
performed in some callers related to associated type inference; we want
to bail out in one specific case only, which is that the declaration
is inside an extension whose generic signature is in the process of
being computed.
This will be used as a transitional aid in refactoring getInterfaceType()
to always return a valid type, instead of silently returning Type() when
there is circularity.