extern generics classes fix, documentation on extern classes updated
This commit is contained in:
1 parent
74eb8ff082
commit
8e0442670d
10 files changed
+28
-58
No files matched your search
@@ -7727,7 +7727,6 @@ class Compiler(
|
||||
|
||||
val annotation = lastAnnotation
|
||||
val parentContext = codeContexts.last()
|
||||
val parentClassCtx = parentContext as? CodeContext.ClassBody
|
||||
|
||||
// Is extension?
|
||||
if (looksLikeExtensionReceiver()) {
|
||||
@@ -7761,13 +7760,6 @@ class Compiler(
|
||||
name = t.value
|
||||
nameStartPos = t.pos
|
||||
}
|
||||
if (parentClassCtx?.isExtern == true && !isExtern) {
|
||||
val owner = parentClassCtx.name
|
||||
throw ScriptError(
|
||||
nameStartPos,
|
||||
"member '$name' in extern class/object '$owner' must be declared extern (use `extern fun $name(...)`)"
|
||||
)
|
||||
}
|
||||
val extensionWrapperName = extTypeName?.let { extensionCallableName(it, name) }
|
||||
val classCtx = codeContexts.asReversed().firstOrNull { it is CodeContext.ClassBody } as? CodeContext.ClassBody
|
||||
var memberMethodId = if (extTypeName == null) classCtx?.memberMethodIds?.get(name) else null
|
||||
@@ -8790,16 +8782,6 @@ class Compiler(
|
||||
name = nameToken.value
|
||||
nameStartPos = nameToken.pos
|
||||
}
|
||||
val parentClassCtx = codeContexts.lastOrNull() as? CodeContext.ClassBody
|
||||
if (parentClassCtx?.isExtern == true && !isExtern) {
|
||||
val owner = parentClassCtx.name
|
||||
val kind = if (isMutable) "var" else "val"
|
||||
throw ScriptError(
|
||||
nameStartPos,
|
||||
"member '$name' in extern class/object '$owner' must be declared extern (use `extern $kind $name: ...`)"
|
||||
)
|
||||
}
|
||||
|
||||
val receiverNormalization = normalizeReceiverTypeDecl(receiverTypeDecl, emptySet())
|
||||
val implicitTypeParams = receiverNormalization.second
|
||||
if (implicitTypeParams.isNotEmpty()) pendingTypeParamStack.add(implicitTypeParams)
|
||||
|
||||
@@ -51,8 +51,9 @@ interface BridgeInstanceContext {
|
||||
* Use [LyngClassBridge.bind] to obtain a binder and register implementations.
|
||||
* Bindings must happen before the first instance of the class is created.
|
||||
*
|
||||
* Important: members you bind here must be declared as `extern` in Lyng so the
|
||||
* compiler emits the ABI slots that Kotlin bindings attach to.
|
||||
* Important: members you bind here must be extern in Lyng (explicitly, or
|
||||
* implicitly by being inside `extern class` / `extern object`) so the compiler
|
||||
* emits the ABI slots that Kotlin bindings attach to.
|
||||
*/
|
||||
interface ClassBridgeBinder {
|
||||
/** Arbitrary Kotlin-side data attached to the class. */
|
||||
@@ -70,7 +71,7 @@ interface ClassBridgeBinder {
|
||||
replaceWith = ReplaceWith("initWithInstance { block(this, thisObj) }")
|
||||
)
|
||||
fun initWithInstance(block: suspend (ScopeFacade, Obj) -> Unit)
|
||||
/** Bind a Lyng function/member to a Kotlin implementation (requires `extern` in Lyng). */
|
||||
/** Bind a Lyng function/member to a Kotlin implementation (requires extern member in Lyng). */
|
||||
fun addFun(name: String, impl: suspend ScopeFacade.() -> Obj)
|
||||
/**
|
||||
* Legacy addFun form.
|
||||
@@ -81,7 +82,7 @@ interface ClassBridgeBinder {
|
||||
replaceWith = ReplaceWith("addFun(name) { impl(this, thisObj, args) }")
|
||||
)
|
||||
fun addFun(name: String, impl: suspend (ScopeFacade, Obj, Arguments) -> Obj)
|
||||
/** Bind a read-only member (val/property getter) declared as `extern`. */
|
||||
/** Bind a read-only member (val/property getter) declared extern in Lyng. */
|
||||
fun addVal(name: String, impl: suspend ScopeFacade.() -> Obj)
|
||||
/**
|
||||
* Legacy addVal form.
|
||||
@@ -92,7 +93,7 @@ interface ClassBridgeBinder {
|
||||
replaceWith = ReplaceWith("addVal(name) { impl(this, thisObj) }")
|
||||
)
|
||||
fun addVal(name: String, impl: suspend (ScopeFacade, Obj) -> Obj)
|
||||
/** Bind a mutable member (var/property getter/setter) declared as `extern`. */
|
||||
/** Bind a mutable member (var/property getter/setter) declared extern in Lyng. */
|
||||
fun addVar(
|
||||
name: String,
|
||||
get: suspend ScopeFacade.() -> Obj,
|
||||
@@ -119,8 +120,9 @@ interface ClassBridgeBinder {
|
||||
* Entry point for Kotlin bindings to declared Lyng classes.
|
||||
*
|
||||
* The workflow is Lyng-first: declare the class and its members in Lyng,
|
||||
* then bind the implementations from Kotlin. Bound members must be marked
|
||||
* `extern` so the compiler emits the ABI slots for Kotlin to attach to.
|
||||
* then bind the implementations from Kotlin. Bound members must be extern
|
||||
* (explicitly or by enclosing `extern class` / `extern object`) so the compiler
|
||||
* emits the ABI slots for Kotlin to attach to.
|
||||
*/
|
||||
object LyngClassBridge {
|
||||
/**
|
||||
@@ -212,7 +214,7 @@ object LyngObjectBridge {
|
||||
/**
|
||||
* Sugar for [LyngClassBridge.bind] on a module scope.
|
||||
*
|
||||
* Bound members must be declared as `extern` in Lyng.
|
||||
* Bound members must be extern in Lyng (explicitly or via enclosing extern class/object).
|
||||
*/
|
||||
suspend fun ModuleScope.bind(
|
||||
className: String,
|
||||
@@ -222,7 +224,7 @@ suspend fun ModuleScope.bind(
|
||||
/**
|
||||
* Sugar for [LyngObjectBridge.bind] on a module scope.
|
||||
*
|
||||
* Bound members must be declared as `extern` in Lyng.
|
||||
* Bound members must be extern in Lyng (explicitly or via enclosing extern class/object).
|
||||
*/
|
||||
suspend fun ModuleScope.bindObject(
|
||||
objectName: String,
|
||||
|
||||
@@ -30,8 +30,8 @@ import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.encodeToJsonElement
|
||||
import net.sergeych.lyng.*
|
||||
import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lyng.thisAs
|
||||
import net.sergeych.lyng.pacman.InlineSourcesImportProvider
|
||||
import net.sergeych.lyng.thisAs
|
||||
import net.sergeych.mp_tools.globalDefer
|
||||
import net.sergeych.tools.bm
|
||||
import kotlin.test.*
|
||||
@@ -3097,19 +3097,6 @@ class ScriptTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExternClassMembersMustBeExplicitlyExtern() = runTest {
|
||||
assertFailsWith<ScriptError> {
|
||||
eval(
|
||||
"""
|
||||
extern class HostClass {
|
||||
fun doSomething(): Int
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExternExtension() = runTest {
|
||||
eval(
|
||||
|
||||
@@ -621,24 +621,23 @@ class TypesTest {
|
||||
eval("""
|
||||
extern fun f<T>(x: T): T
|
||||
extern class Cell<T> {
|
||||
extern var value: T
|
||||
var value: T
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExternClassMemberMustBeExternMessage() = runTest {
|
||||
fun testExternClassMemberInitializerStillFailsWithoutExplicitExtern() = runTest {
|
||||
val e = assertFailsWith<ScriptError> {
|
||||
eval(
|
||||
"""
|
||||
extern class Cell<T> {
|
||||
var value: T
|
||||
var value: T = 1
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
assertTrue(e.message?.contains("must be declared extern") == true)
|
||||
assertTrue(e.message?.contains("extern var value") == true)
|
||||
assertTrue(e.message?.contains("extern variable value cannot have an initializer or delegate") == true)
|
||||
}
|
||||
|
||||
// @Test fun nonTrivialOperatorsTest() = runTest {
|
||||
|
||||
Reference in new issue
Block a user