Native: enable lazy IR generation before running fake override builder

^KT-48816 Fixed

Native compiler uses lazy IR for declarations provided by cinterop.
The problem: `FakeOverrideBuilder` requests super types during
type checking, accessing `.owner` for them. So if a type and super type
are represented as lazy IR, and lazy IR generation is not enabled yet,
then the super type symbol won't be bound by this moment, and the access
will fail.

This happens in KT-48816: fake override builder tries to access `.owner`
for `IrClassSymbol` of `NSObject` (super type of `NSDate` and `NSUUID`).

Fix this by enabling lazy IR generation before building fake overrides.
This commit is contained in:
Svyatoslav Scherbina
2021-11-10 12:30:12 +00:00
committed by Space
parent b76e670ad5
commit ea7160947a
5 changed files with 81 additions and 2 deletions
@@ -363,8 +363,7 @@ internal class KonanIrLinker(
}
override fun postProcess() {
if (lazyIrForCaches)
stubGenerator.unboundSymbolGeneration = true
stubGenerator.unboundSymbolGeneration = true
super.postProcess()
}
@@ -4327,6 +4327,10 @@ if (PlatformInfo.isAppleTarget(project)) {
it.defFile 'interop/objc/kt42172/objclib.def'
it.headers "$projectDir/interop/objc/kt42172/objclib.h"
}
createInterop("objc_kt48816") {
it.defFile 'interop/objc/kt48816/objclib.def'
it.headers "$projectDir/interop/objc/kt48816/objclib.h"
}
}
createInterop("withSpaces") {
@@ -4952,6 +4956,20 @@ if (PlatformInfo.isAppleTarget(project)) {
}
}
interopTest("interop_objc_kt48816_without_lazy_ir_for_caches") {
// Without a fix, fails in two-stage mode.
source = "interop/objc/kt48816/main.kt"
interop = "objc_kt48816"
// The bug was accidentally fixed with lazy IR for caches, so testing it with this feature disabled:
flags = ["-Xlazy-ir-for-caches=disable"]
}
interopTest("interop_objc_kt48816_with_lazy_ir_for_caches") {
source = "interop/objc/kt48816/main.kt"
interop = "objc_kt48816"
flags = ["-Xlazy-ir-for-caches=enable"]
}
standaloneTest("objc_arc_contract") {
doBeforeBuild {
mkdir(buildDir)
@@ -0,0 +1,51 @@
import kotlin.reflect.*
import kotlin.test.*
import objclib.*
// https://youtrack.jetbrains.com/issue/KT-48816
open class Base<Ref> {
operator fun KProperty1<Ref, NSUUID>.getValue(ref: Base<Ref>, property: KProperty<*>): NSUUID? {
return null
}
operator fun KProperty1<Ref, NSDate>.getValue(ref: Base<Ref>, property: KProperty<*>): NSDate? {
return null
}
}
class Usage: Base<B>()
class B
// The compilation should fail with the above;
// but anyway try to actually use the code, just to ensure it doesn't get DCEd:
val B.uuid: NSUUID get() = fail()
val B.date: NSDate get() = fail()
fun test1() {
val uuidProperty = B::uuid
val dateProperty = B::date
val usage = Usage()
with(usage) {
assertNull(uuidProperty.getValue(usage, uuidProperty))
assertNull(dateProperty.getValue(usage, dateProperty))
}
}
// One more reproducer, just in case:
class Property<out R>
open class Base2 {
fun getValue(property: Property<MyClass1>) = null
fun getValue(property: Property<MyClass2>) = null
}
class Usage2 : Base2()
fun test2() {
val usage = Usage2()
assertNull(usage.getValue(Property<MyClass1>()))
assertNull(usage.getValue(Property<MyClass2>()))
}
fun main() {
test1()
test2()
}
@@ -0,0 +1,2 @@
language = Objective-C
headerFilter = **/objclib.h **/NSObject.h **/NSDate.h **/NSUUID.h
@@ -0,0 +1,9 @@
#import <Foundation/NSObject.h>
#import <Foundation/NSDate.h>
#import <Foundation/NSUUID.h>
@interface MyClass1 : NSObject
@end;
@interface MyClass2 : NSObject
@end;