Introduce documentation for PCLA implementation
^KT-65637 Fixed
This commit is contained in:
committed by
Space Team
parent
41cc926953
commit
cabf7e4fae
@@ -1,6 +1,8 @@
|
||||
## FIR/Delegated property inference
|
||||
See also: [Kotlin Spec: Delegated property declaration](https://kotlinlang.org/spec/declarations.html#delegated-property-declaration) and some [Common inference terms definition](inference.md)
|
||||
|
||||
In many ways, delegated property inference works as a simpler version of PCLA, so it's worth beginning with [pcla.md](pcla.md).
|
||||
|
||||
### Glossary
|
||||
#### Delegation related operator calls
|
||||
Synthetically generated by Raw FIR builder calls to `getValue`, `setValue` or `provideDelegate` functions.
|
||||
@@ -8,12 +10,14 @@ Synthetically generated by Raw FIR builder calls to `getValue`, `setValue` or `p
|
||||
*NB:* They might be differentiated from regular calls by comparing origin to `FirFunctionCallOrigin.Operator`
|
||||
|
||||
#### Outer CS
|
||||
A constraint system that defines type variables with their constraints not brought by the call itself or its arguments.
|
||||
A constraint system that defines type variables with their constraints is not brought by the call itself or its arguments.
|
||||
The general idea is that before running resolution of a specific "inner" candidate, we copy all the outer variables to its own CS in the very
|
||||
beginning, and after some successful candidate is chosen, we apply the "relevant" changes to the outer CS.
|
||||
|
||||
By "apply" operation currently we mean literally replacement of the old CS with the new one.
|
||||
|
||||
See `FirDelegatedPropertyInferenceSession.parentConstraintSystem`.
|
||||
|
||||
### Desugaring at Raw FIR building stage
|
||||
The code like this
|
||||
```kotlin
|
||||
@@ -37,20 +41,28 @@ val prop = propertyNode {
|
||||
Even in case the property type is specified, all the content types are set as implicit.
|
||||
|
||||
### Delegated property inference algorithm
|
||||
#### Initiation
|
||||
At first, we set up a delegate inference session that is necessary to preserve the common CS and partially completed calls that need to be
|
||||
fully completed in the end.
|
||||
|
||||
For reference, see `org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.BodyResolveContext.forPropertyDelegateAccessors`.
|
||||
|
||||
#### Delegate expression inference
|
||||
At first, we resolve delegate expression with `ContextDependent.Delegate` resolution mode that behaves just like the regular `ContextDependent`
|
||||
but it makes DelegateInferenceSession to remember resulting incomplete CS from the call.
|
||||
At first, we resolve delegate expression with `Delegate` resolution mode that behaves just like the regular `ContextDependent`
|
||||
but it has some small differences (see usages of the relevant enum entry):
|
||||
- If the delegate expression is a lambda, we would resolve it as it was an independent expression
|
||||
- We treat it specially inside [PCLA](pcla.md).
|
||||
|
||||
Note that we do that outside delegate inference session (it's not created yet), so if delegated property inside a PCLA lambda, the delegate
|
||||
expression would be analyzed under PCLA session.
|
||||
|
||||
*NB:* If the delegate expression is simple enough, i.e., it does not contain type parameters, or they might be inferred from the call itself,
|
||||
we just run FULL completion on it as for regular `ContextDependent` and don't store its CS.
|
||||
|
||||
For reference, see `org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer.transformWrappedDelegateExpression`.
|
||||
For reference, see `FirDeclarationsResolveTransformer.transformPropertyAccessorsWithDelegate`.
|
||||
|
||||
#### Session introduction
|
||||
After delegate expression is analyzed, we create `FirDelegatedPropertyInferenceSession` and use it as an inference session for resolving
|
||||
operator calls.
|
||||
|
||||
As an outer/parent CS we use either:
|
||||
- A constraint system of the delegate expression if it's a `FirResolvable` (under PCLA, it would have *shared CS*)
|
||||
- Otherwise, if delegate is some simple/non-call-like expression, obtain shared CS if PCLA is present, or just create the empty one
|
||||
|
||||
#### provideDelegate resolution
|
||||
After delegate expression is resolved, we start regular resolution of `provideDelegate()` call stored at `FirWrappedDelegateExpression::delegateProvider`.
|
||||
@@ -58,13 +70,13 @@ After delegate expression is resolved, we start regular resolution of `provideDe
|
||||
Note that as explicit receiver it uses just the same instance of `delegateExpression` we've just resolved on the previous step.
|
||||
As the receiver still might contain some type variables, we use CS of it as [Outer CS](#outer-cs) for all the `provideDelegate` candidates.
|
||||
|
||||
If there is no most specific successful candidate, then we just drop and forget the call.
|
||||
If there is no single most specific successful candidate, then we just drop and forget the call.
|
||||
|
||||
Otherwise, after the resulting candidate is chosen, it has some state of CS that contains both "inner" type variables of the candidate itself and some
|
||||
global ones brought by Outer CS.
|
||||
|
||||
Note that we don't force FULL completion (unlike K1 did), thus potentially leaving some of the type variables not fixed.
|
||||
The most problematic part with that approach is that in some cases the return type of `provideDelegate` is a type variable _and_ we
|
||||
The most problematic part with that approach is that in some cases the return type of `provideDelegate` is a type variable, _and_ we
|
||||
might need to look into its member scope to find `getValue` call there.
|
||||
|
||||
```kotlin
|
||||
@@ -140,3 +152,6 @@ Some of the final candidates might be obtained from member scopes of types with
|
||||
scopes with substituted type arguments.
|
||||
|
||||
See `FirCallCompletionResultsWriterTransformer.updateSubstitutedMemberIfReceiverContainsTypeVariable` for details.
|
||||
|
||||
#### Delegation inside PCLA
|
||||
See the relevant part inside the [document](pcla.md) on PCLA.
|
||||
|
||||
Reference in New Issue
Block a user