SIL type lowering uses ReplaceOpaqueTypesWithUnderlyingTypes to lower away
opaque result types when the current context can "see" the underlying type
of the opaque result type.
To determine if an opaque result type could be replaced with its
underlying type, we check if every nominal type declaration appearing
in the "fully substituted" underlying type is visible from the current
context.
To form the "fully substituted" type, we first apply the substitution map
stored in the opaque type decl, which replaces the 'Self' generic parameter
with the actual concrete result type.
Then, we apply the substitution map stored in the archetype itself.
However, calling subst() on an opaque archetype modifies the substitution
map stored in the archetype.
What this means in practice is that if I have an opaque type declaration
that depends on its outer generic parameters, the fully-substituted type
that I see here depends on whether subst() has been performed or not.
For example, suppose I have the following:
protocol P {}
struct S : P {}
extension P {
func foo() -> some Any { return [self] }
}
The opaque result decl for P.foo() maps 'Self' to 'Array<Self>'. Now,
imagine someone calls foo() with the substitution 'Self := S'. The
fully-substituted underlying type is 'Array<S>'. If 'S' is private, we
will decide that we cannot replace the opaque result type with its
underlying type. However, if we had performed the opaque type replacement
_before_ substituting 'Self := S', then we will end up replacing the
opaque result type.
To re-state this in yet another form, we want the following identity to
hold here:
getLoweredType(opaqueType).subst(subMap) == getLoweredType(opaqueType.subst(subMap))
We can ensure that this holds by only applying the archetype's
substitutions _after_ we check visibility.
Fixes rdar://problem/76556368.
At the moment, if there is an error in the `switch` statement expression or if the `{` is missing, we return `nullptr` from `parseStmtSwitch`, but we consume tokens while trying to parse the `switch` statement. This causes the AST to not contain any nodes for the tokens that were consumed while trying to parse the `switch` statement.
While this doesn’t cause any issues during compilation (compiling fails anyway so not having the `switch` statement in the AST is not a problem) this causes issues when trying to complete inside an expression that was consumed while trying to parse the `switch` statement but doesn’t have a representation in the AST. The solver-based completion approach can’t find the expression that contains the completion token (because it’s not part of the AST) and thus return empty results.
To fix this, make sure we are always creating a `SwitchStmt` when consuming tokens for it.
Previously, one could always assume that a `SwitchStmt` had a valid `LBraceLoc` and `RBraceLoc`. This is no longer the case because of the recovery. In order to form the `SwitchStmt`’s `SourceRange`, I needed to add a `EndLoc` property to `SwitchStmt` that keeps track of the last token in the `SwitchStmt`. Theoretically we should be able to compute this location by traversing the right brace, case stmts, subject expression, … in reverse order until we find something that’s not missing. But if the `SubjectExpr` is an `ErrorExpr`, representing a missing expression, it might have a source range that points to one after the last token in the statement (this is due to the way the `ErrorExpr` is being constructed), therefore returning an invalid range. So overall I thought it was easier and safer to add another property.
Fixes rdar://76688441 [SR-14490]
The diagnosticc engine is keeping track of state which might modify parsing/typechecking behaviour. In the added test case the `fatalErrorOccurred` flag was during the first completion. The flag was still `true` for the second completion, causing parsing/typechecking to behave slightly differently. Because of this, the ExprRewriter failed when applying a constraint system solution, not properly cleaning up its `ExprStack`.
This PR tackles both issues:
1) Reset the `hadError` flags in the diagnostics engine
2) Clean up the `ExprRewriter`’s `ExprStack` when rewriting a target fails.
Either of these changes fixes the crash in the test case but I think both could manifest through different code paths in different scenarios.
Fixes rdar://76051976 [SR-14430]
Extensions redeclare all generic parameters of their extended type to add their additional restrictions. There are two issues with this model for indexing:
- The generic paramter declarations of the extension are implicit so we wouldn't report them in the index. Any usage of the generic param in the extension references this implicit declaration so we don't include it in the index either.
- The implicit re-declarations have their own USRs so any usage of a generic parameter inside an extension would use a different USR than declaration of the param in the extended type.
To fix these issues, we replace the reference to the implicit generic parameter defined in the extension by a reference to the generic paramter defined in the extended type.
Restrict filtering in `simplifyAppliedOverloadsImpl` to disable
overload set for operators only, because other calls e.g. regular
functions or subscripts could be filtered on labels and are less
overloaded.
Filtering non-operator calls could also lead to incorrect diagnostics
because first choice could have all sorts of different issues e.g.
incorrect labels and number of parameters.
Resolves: rdar://55369704
Instead, put the archetype->instrution map into SIlModule.
SILOpenedArchetypesTracker tried to maintain and reconstruct the mapping locally, e.g. during a use of SILBuilder.
Having a "global" map in SILModule makes the whole logic _much_ simpler.
I'm wondering why we didn't do this in the first place.
This requires that opened archetypes must be unique in a module - which makes sense. This was the case anyway, except for keypath accessors (which I fixed in the previous commit) and in some sil test files.