Compiler check for 'when' exhaustiveness requires that module
descriptors of a sealed class and its inheritors are the same (reference
identity matters). Prior to this commit and under some conditions they
were not. Details follow below.
Resolution related data structures (resolution facades) are organized
into trees (sdks, libs, and modules have their own nodes/facades,
module/class descriptors are stored inside). And the trees themselves
are put into a map associating so called PlatformAnalysisSettings and
GlobalFacades (plays a role of a root). PlatformAnalysisSettings is an
abstraction describing target platform and sdk of a module. The more
combinations exist for a project the more facades are used. Please, see
KotlinCacheService for more details.
So why a module can have multiple ModuleDescriptor-s?
Every tree mentioned above is an isolated resolution environment
containing its own instances of the outer world descriptors. Say, if a
project has modules X, Y, Z and we consider X then all three might have
their own vision of X, i.e. 3 descriptors exist at a time.
What descriptor instance does compiler get?
The path starts when the user opens a file in the editor and
highlighting pass starts (see usages of
ResolutionUtils#analyzeWithAllCompilerChecks). Module descriptor stored
in the resolution tree of the file's module gets injected into the
compiler's context. Starting from this moment compiler sees other
modules through the prism of a single resolution facade (tree).
Descriptors residing outside are alien.
This commit allows IdeSealedClassInheritorsProvider to figure out what
PlatformAnalysisSettings are associated with the resolution facade (read
ModuleDescriptor) seen by the compiler. Later on the same facade is used
to provide correct instances of sealed inheritors back to the compiler.
Note that LazyClassMemberScope actually has a separate field for
KotlinTypeRefiner, and it might be actually different from the one in
c.kotlinTypeChecker.
The one in c.kotlinTypeChecker is the refiner of *owner* module, i.e. a
module in which the class has been declared. If we have a class Foo :
Expect in common, then the refiner will be from common, and thus it
won't be able to refine supertypes to their platform-dependent values.
The one passed in constructor is actual refiner of dependant-module.
Say, if we're looking at Foo from the point of view of jvmMain, then
we'll create a (view-dependent) LCMS for that, and it will contain
refiner for jvmMain.
It is important to use proper refiner, otherwise the idea of having
"module-dependent view" breaks, and we might suddenly mismatch some
overrides with expect-classes in their signatures.
^KT-44898 Fixed
Extract a service interface out of ControlFlowInformationProviderImpl
and register its implementation in two "leaf" modules: 'cli',
'idea-core'.
This improves parallel build, since a lot of modules depend on
'frontend' but only these two modules reference the implementation and
thus depend on the full CFA implementation now.
Do not use default parameter value for functions with only 1 or 2 call
sites, since it doesn't add much value but provides a dangerous
possibility to forget to pass the real implementation.
This is needed in order to have a single convenient place where to
register frontend services implemented _outside_ of the 'frontend'
module, such as the control flow analysis, extracted to a separate
module in a subsequent commit.
These utilties are used not only within CFG, but from the frontend and
idea as well. Therefore upon extraction of CFG into another module,
these two new files will remain in 'frontend'.
Also changed FE1.0 checker and all related fix factories to report error
on the declaration instead of the lateinit modifier. This is consistent
with the direction of all checkers in FIR (no reporting on modifiers).
This commit introduces partial support of descriptorKindFilter in
`AbstractPsiBasedDeclarationProvider`. Without it there may be an error
in following case:
```
sealed class Base
class Derived : Base()
class Test<out V>(val x: Base) {
private val y = when (x) {
is Derived -> null
}
}
```
Here we start to resolve type of `y`, then go to computation of inheritors
of sealed class Base, which also may be inside Test, so we need get all
nested classifiers in Test. But without this filtration we will start
computing descriptor for `y` again, which leads to ReenteringLazyComputationException
#KT-44316 Fixed
Add -X flag to report extra compiler diagnostics which migth break compatibility.
Use the flag to unconditionally check constructors without fear of
prematurely evaluating lazy supertypes.
KT-19234
KT-42404
KT-44583
Using "JVM_1_8" always resulted in incorrect mapping of Kotlin
annotation targets to Java element types.
The change in AbstractKotlinRenderLogTest is needed because while
CliTraceHolder.module is technically a descriptor leak, it was never
detected by this test accidentally, because of the depth cutoff equal to
10, which started to not be enough after the minor refactoring of
replacing `Delegates.notNull` with `lateinit`.
Do not report same set of diagnostics for variable call if actual
error was happened with a function candidate. Here the candidate is
invoke function on DeepRecursiveFunction
^KT-40991 Fixed
^KT-41491 Fixed
^KT-40926 In Progress