Require explicit extern members in extern class/object and update docs

This commit is contained in:
sergeych committed 2026-03-15 03:27:50 +03:00
1 parent e447c778ed
commit 979e6ea9b7
13 files changed
+105 -53

No files matched your search

@@ -7727,6 +7727,7 @@ class Compiler(
val annotation = lastAnnotation
val parentContext = codeContexts.last()
val parentClassCtx = parentContext as? CodeContext.ClassBody
// Is extension?
if (looksLikeExtensionReceiver()) {
@@ -7760,6 +7761,9 @@ class Compiler(
name = t.value
nameStartPos = t.pos
}
if (parentClassCtx?.isExtern == true && !isExtern) {
throw ScriptError(nameStartPos, "members of extern classes/objects must be marked extern")
}
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
@@ -8782,6 +8786,10 @@ class Compiler(
name = nameToken.value
nameStartPos = nameToken.pos
}
val parentClassCtx = codeContexts.lastOrNull() as? CodeContext.ClassBody
if (parentClassCtx?.isExtern == true && !isExtern) {
throw ScriptError(nameStartPos, "members of extern classes/objects must be marked extern")
}
val receiverNormalization = normalizeReceiverTypeDecl(receiverTypeDecl, emptySet())
val implicitTypeParams = receiverNormalization.second
@@ -24,46 +24,46 @@ package lyng.observable
extern class ChangeRejectionException : Exception
extern class Subscription {
fun cancel(): Void
extern fun cancel(): Void
}
extern class Observable<Change> {
fun beforeChange(listener: (Change)->Void): Subscription
fun onChange(listener: (Change)->Void): Subscription
fun changes(): Flow<Change>
extern fun beforeChange(listener: (Change)->Void): Subscription
extern fun onChange(listener: (Change)->Void): Subscription
extern fun changes(): Flow<Change>
}
extern class ListChange<T>
extern class ListSet<T> : ListChange<T> {
val index: Int
val oldValue: Object
val newValue: Object
extern val index: Int
extern val oldValue: Object
extern val newValue: Object
}
extern class ListInsert<T> : ListChange<T> {
val index: Int
val values: List<T>
extern val index: Int
extern val values: List<T>
}
extern class ListRemove<T> : ListChange<T> {
val index: Int
val oldValue: Object
extern val index: Int
extern val oldValue: Object
}
extern class ListClear<T> : ListChange<T> {
val oldValues: List<T>
extern val oldValues: List<T>
}
extern class ListReorder<T> : ListChange<T> {
val oldValues: List<T>
val newValues: Object
extern val oldValues: List<T>
extern val newValues: Object
}
extern class ObservableList<T> : List<T> {
fun beforeChange(listener: (ListChange<T>)->Void): Subscription
fun onChange(listener: (ListChange<T>)->Void): Subscription
fun changes(): Flow<ListChange<T>>
extern fun beforeChange(listener: (ListChange<T>)->Void): Subscription
extern fun onChange(listener: (ListChange<T>)->Void): Subscription
extern fun changes(): Flow<ListChange<T>>
}
fun List<T>.observable(): ObservableList<T> {
+1 -2
View File
@@ -164,7 +164,7 @@ class BindingTest {
val ms = Script.newScope()
ms.eval("""
extern class A {
fun get1(): String
extern fun get1(): String
}
extern fun getA(): A
@@ -184,4 +184,3 @@ class BindingTest {
}
}
@@ -231,7 +231,7 @@ class BridgeBindingTest {
val ms = Script.newScope()
ms.eval("""
extern class A {
val field: Int
extern val field: Int
}
fun test(a: A) = a.field
+2 -2
View File
@@ -249,13 +249,13 @@ class MiniAstTest {
// Doc2
extern class C1 {
// Doc3
fun m1()
extern fun m1()
}
// Doc4
extern object O1 {
// Doc5
val v1: String
extern val v1: String
}
// Doc6
+16 -3
View File
@@ -3080,11 +3080,11 @@ class ScriptTest {
"""
extern fun hostFunction(a: Int, b: String): String
extern class HostClass(name: String) {
fun doSomething(): Int
val status: String
extern fun doSomething(): Int
extern val status: String
}
extern object HostObject {
fun getInstance(): HostClass
extern fun getInstance(): HostClass
}
extern enum HostEnum {
VALUE1, VALUE2
@@ -3097,6 +3097,19 @@ class ScriptTest {
)
}
@Test
fun testExternClassMembersMustBeExplicitlyExtern() = runTest {
assertFailsWith<ScriptError> {
eval(
"""
extern class HostClass {
fun doSomething(): Int
}
""".trimIndent()
)
}
}
@Test
fun testExternExtension() = runTest {
eval(
@@ -209,7 +209,7 @@ class CompletionEngineLightTest {
fun inferredTypeFromMemberCall() = runBlocking {
val code = """
extern class MyClass {
fun getList(): List<String>
extern fun getList(): List<String>
}
extern val c: MyClass
val x = c.getList()
+27 -27
View File
@@ -8,22 +8,22 @@ extern class IllegalArgumentException
extern class NotImplementedException
extern class Delegate
extern class Iterable<T> {
fun iterator(): Iterator<T>
fun forEach(action: (T)->void): void
fun map<R>(transform: (T)->R): List<R>
fun toList(): List<T>
fun toImmutableList(): ImmutableList<T>
val toSet: Set<T>
val toImmutableSet: ImmutableSet<T>
val toMap: Map<Object,Object>
val toImmutableMap: ImmutableMap<Object,Object>
extern fun iterator(): Iterator<T>
extern fun forEach(action: (T)->void): void
extern fun map<R>(transform: (T)->R): List<R>
extern fun toList(): List<T>
extern fun toImmutableList(): ImmutableList<T>
extern val toSet: Set<T>
extern val toImmutableSet: ImmutableSet<T>
extern val toMap: Map<Object,Object>
extern val toImmutableMap: ImmutableMap<Object,Object>
}
extern class Iterator<T> {
fun hasNext(): Bool
fun next(): T
fun cancelIteration(): void
fun toList(): List<T>
extern fun hasNext(): Bool
extern fun next(): T
extern fun cancelIteration(): void
extern fun toList(): List<T>
}
// Host-provided iterator wrapper for Kotlin collections.
@@ -33,47 +33,47 @@ class KotlinIterator<T> : Iterator<T> {
}
extern class Collection<T> : Iterable<T> {
val size: Int
extern val size: Int
}
extern class Array<T> : Collection<T> {
}
extern class ImmutableList<T> : Array<T> {
fun toMutable(): List<T>
extern fun toMutable(): List<T>
}
extern class List<T> : Array<T> {
fun add(value: T, more...): void
fun toImmutable(): ImmutableList<T>
extern fun add(value: T, more...): void
extern fun toImmutable(): ImmutableList<T>
}
extern class RingBuffer<T> : Iterable<T> {
val size: Int
fun first(): T
fun add(value: T): void
extern val size: Int
extern fun first(): T
extern fun add(value: T): void
}
extern class Set<T> : Collection<T> {
fun toImmutable(): ImmutableSet<T>
extern fun toImmutable(): ImmutableSet<T>
}
extern class ImmutableSet<T> : Collection<T> {
fun toMutable(): Set<T>
extern fun toMutable(): Set<T>
}
extern class Map<K,V> : Collection<MapEntry<K,V>> {
fun toImmutable(): ImmutableMap<K,V>
extern fun toImmutable(): ImmutableMap<K,V>
}
extern class ImmutableMap<K,V> : Collection<MapEntry<K,V>> {
fun getOrNull(key: K): V?
fun toMutable(): Map<K,V>
extern fun getOrNull(key: K): V?
extern fun toMutable(): Map<K,V>
}
extern class MapEntry<K,V> : Array<Object> {
val key: K
val value: V
extern val key: K
extern val value: V
}
// Built-in math helpers (implemented in host runtime).