AllOpen plugin makes the properties all-open, but the annotation class
is left closed, because allopen for k2 literally checks
`classKind == CLASS`.
Since the properties are open, a
`NON_FINAL_MEMBER_IN_FINAL_CLASS` diagnostic is reported for them. It's
positioning strategy seeks for the explicit `open` modifier which is
not present.
The added test should not crash the compiler.
^KT-54260 Fixed
This is needed not only as optimization, but also for cases, when
inferred type of function may differ from type of single expression.
Such situation may occur after next commit, which adds approximation
of return type of all declarations:
```
interface A
interface B
interface C : A, B
interface D : A, B
class Inv<T>(val x: T, val y: T)
fun foo(c: C, d: D) /* : Inv<Any> */ = Inv(c, d) /*: Inv<A & B> */
// Inv<A & B> /<: Inv<Any>
// but there should be no error
```
Also remove incorrect subtype check checkers
Test unsafeVarianceInAliasedFunctionalType.kt started to fail because
of KT-54894. This bug existed before, changes from this commit just
unhided it (previously it was hidden because incorrect subtype check
in `isSubtypeForTypeMismatch` which is used by FirFunctionReturnTypeMismatchChecker
`x?.y != null` does not imply that `x != null` if e.g. an argument to
`y` has reassigned `x` in the meantime.
The same is true for `x == y` and `functionWithContract(x, y)`, but
those are somewhat harder to implement since there is no easy way to
find the last node of a certain argument.
^KT-55096
Thinking of monomorphizing `Flow` (= `PersistentFlow`) and instead
adding a completely separate `MutableFlow` version; then `joinFlow`
would produce a mutable one, data flow analysis would add some
statements, convert to a persistent `Flow` and proceed to the next
node.
The code was already duplicated between FirDataFlowAnalyzer and
FirReturnsImpliesAnalyzer, so might as well use the latter to slightly
speed up the former.
This makes the `returns() implies` checker slightly cleaner, and also
fixes the case that I've missed where in RHS of `x ?:` type of `x` was
not set to `Nothing?`.
If a variable does not yet exist, then it should only be created if it
is a real variable and the implication or statement we're about to add
is about its type or nullability (which is also about the type).
Otherwise, the statement/implication will have no effect because there
are currently no implications referencing that variable, and if it's
synthetic then there will never be because we won't visit it again.
Hopefully this reduces the performance impact of flow forks.
This also fixes some returnsNotNull contracts because the old code added
an implication that `== true` => `!= null` then promptly removed any
statement that this could've affected if the argument was a synthetic
variable.
^KT-26612 tag fixed-in-k2
If the right-hand side is evaluated at all, then in its flow those
statements were already approved. Re-approving them erases the effect of
reassignments.
^KT-28369 tag fixed-in-k2
In theory, forking persistent flows should be cheap because of object
reuse, so the proposal here is to start from scratch and prove
redundancy of forks on a case-by-case basis. Something something better
safe than sorry.
^KT-28333 tag fixed-in-k2
^KT-28489 tag fixed-in-k2
By necessity, type statements underapproximate. Therefore, inverting
doesn't always produce an equal result. It's best to propagate negations
inwards to preserve precision as much as possible.
And use them less in boolean expression analysis. This uncovers a fun
new case that doesn't work:
interface I { val x: String }
class C(override val x: String) : I
class D(override val x: String) : I
fun foo(x: Any?) {
if (x is D || (x as C).x != "") {
println(x.x.length) // actually OK (x is D || x is C => x is I)
}
}
I don't even know if this affects any real code, but it did uncover
some deeper issues, like the fact that `!is` did not add any statements
when `true`.
callBothLambdas({ x = "..." }, { x is Int })
// the assignment always executes, so x is String | (String & Int);
// the latter is always a subtype of the former so it can be ignored
val c = C("...")
val d = c
if (c.x == null) return
c.x.length // c.x has type String
d.x.length // d.x -> c.x through d -> c
c = C(null) // remove alias d -> c
d.x.length // info from c.x moved to d.x
^KT-54824 Fixed
Second step for KT-52615
Get rid of PsiHandlingMode
Get rid of source in FirLazyBlock
Refactor lazy creation
Merge-request: KT-MR-7753
Merged-by: Egor Kulikov <Egor.Kulikov@jetbrains.com>