In the compiler, 'FirLazyDeclarationResolver' assumes
'lazyResolveToPhase()' appear only during code analysis. So there is
a check that requires calls to be wrapped with 'startResolvingPhase()'
and 'finishResolvingPhase()'. Checkers and backend are run on fully
analyzed code, so there is no need in calling 'lazyResolveToPhase()'
in the first place.
In the IDE, however, it's impossible to analyze all code in a project
before running the backend. Generally, it's not a problem as files that
are explicitly passed to the backend go through all FIR phases.
'IrBuiltInsOverFir', though, perform symbol lookups, so unresolved-yet
declarations might appear.
In the IDE, there might come declarations from other files/modules
that we link against, but not pass to the backend. As only declarations
from the compiled files end up being in the cache, the consistency check
should be relaxed.
In the IDE, it's impossible to pass classes from all modules to the
backend, so symbols for 'external' source declarations need to be
generated ad-hoc.
Such declarations do not go through the lowering phase, including one
that replaces the containing package fragment with a facade class.
In the IDE, there might come declarations from other files/modules
that we link against, but not compile. Type parameters are one of such
declaration kinds.
In the IDE, FIR declarations for libraries are built on top of binary
stubs. This helps to improve memory usage significantly, as Protobuf
metadata isn't loaded all the time. However, the containing file type
for stubs is different.
This is needed to be able to precisely distinguish different synthetic
declarations (like fields for delegates and functions for data classes)
in fir2ir
Logic that was used to complete receiver expression is no longer needed
after the `invoke receiver completion` change:
7b46c59d57
Before that change, we could have generated a new receiver expression
during resolution in case of `call() -> call.<invoke>()` resolution,
Here - `call` is newly generated qualified access that wasn't completed.
We were detecting such situations by detecting change in the receiver
between original `call()` shape and output `___.invoke()` shape in
the expression.
After that change, we always complete the receiver of invoke during
`callResolver.resolveCallAndSelectCandidate`
So the logic that detects receiver mismatch and invokes receiver
completion after it isn't needed anymore
Move language version settings, compiler configuration and different
flags there, and use this config everywhere in both backends instead of
GenerationState.
This will hopefully make GenerationState less of a "god object" and
remove the need to have it available everywhere, in particular in JVM IR
lowerings code, in the future.
Also, future refactorings will make it easier to inject backend-specific
behavior into common code, so that we would not need to handle support
of new features in the old backend.
We have `BackendKinds.IrBackend` for IR emitted by the frontend.
We need a different backend kind for IR deserialized from klibs.
We cannot use `BackendKinds.IrBackend` for that purpose, because we
cannot have two different `IrBackendInput` subclasses with the same
kind.
We need a different `IrBackendInput` subclass for deserialized IR
because the `IrBackendInput` for frontend-emitted IR contains some
properties like `sourceFiles` which don't make sense for
deserialized IR.
Since we now have two backend kinds for IR artifacts, we need to make
certain functions and classes in the test infrastructure generic
over backend kinds.
Note: the JsIrDeserializedFromKlibBackendInput class is not used
anywhere yet. We will use it in the coming commits.
Entering a `finally` block can happen from many different places:
through an exception, a jump, or normal exit from the `try` block. When
in the `finally` block, all DFA flows must be merged to have correct
smart casting. However, after the `finally` block, if exiting normally
or because of a jump, the combined flow from within the `finally` block
should not be used, but rather an alternate flow which combines the
correct flows from before the `finally` block.
```
try {
str as String // Potential cast exception
} finally {
str.length // Shouldn`t be resolved
}
str.length // Should be resolved
```
When building DFA flows, track the start of possible alternate flows,
and continue building them until they end. Both of these situations are
now marked on CFGNodes via interfaces.
When building the default DFA flow, and the source node is the end node
of alternate flows, attempt to use the alternate flow with the same edge
label instead of the default flow of the source node.
#KT-56888 Fixed
Preliminary refactor in preparation for the implementation details to
fix KT-56888. This change makes it so alternate data flows can be
created and maintained through CFGNodes. This change was separated and
created first to aid in the code review process.
Jump edge targets are maintained globally within the CFG builder and are
added indiscriminately to `finally` exit nodes. This means that a
`finally` exit node could have a jump edge added which doesn't match how
the `finally` block was entered. Make sure edges are only added to the
exit node if they also exist on the enter node.
#KT-60723 Fixed