Use canonical class identity for delegate checks
This commit is contained in:
parent
7c059b4741
commit
4269310beb
@ -583,7 +583,7 @@ class Compiler(
|
|||||||
val baseNames = cls.directParents.map { it.className }
|
val baseNames = cls.directParents.map { it.className }
|
||||||
val nextFieldId = (fieldIds.values.maxOrNull() ?: -1) + 1
|
val nextFieldId = (fieldIds.values.maxOrNull() ?: -1) + 1
|
||||||
val nextMethodId = (methodIds.values.maxOrNull() ?: -1) + 1
|
val nextMethodId = (methodIds.values.maxOrNull() ?: -1) + 1
|
||||||
return CompileClassInfo(name, fieldIds, methodIds, nextFieldId, nextMethodId, baseNames)
|
return CompileClassInfo(name, cls.logicalPackageName, fieldIds, methodIds, nextFieldId, nextMethodId, baseNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class BaseMemberIds(
|
private data class BaseMemberIds(
|
||||||
@ -1553,6 +1553,7 @@ class Compiler(
|
|||||||
|
|
||||||
private data class CompileClassInfo(
|
private data class CompileClassInfo(
|
||||||
val name: String,
|
val name: String,
|
||||||
|
val packageName: String?,
|
||||||
val fieldIds: Map<String, Int>,
|
val fieldIds: Map<String, Int>,
|
||||||
val methodIds: Map<String, Int>,
|
val methodIds: Map<String, Int>,
|
||||||
val nextFieldId: Int,
|
val nextFieldId: Int,
|
||||||
@ -6710,6 +6711,7 @@ class Compiler(
|
|||||||
)
|
)
|
||||||
compileClassInfos[qualifiedName] = CompileClassInfo(
|
compileClassInfos[qualifiedName] = CompileClassInfo(
|
||||||
name = qualifiedName,
|
name = qualifiedName,
|
||||||
|
packageName = packageName,
|
||||||
fieldIds = fieldIds,
|
fieldIds = fieldIds,
|
||||||
methodIds = methodIds,
|
methodIds = methodIds,
|
||||||
nextFieldId = fieldIds.size,
|
nextFieldId = fieldIds.size,
|
||||||
@ -6832,6 +6834,7 @@ class Compiler(
|
|||||||
classCtx?.let { ctx ->
|
classCtx?.let { ctx ->
|
||||||
compileClassInfos[className] = CompileClassInfo(
|
compileClassInfos[className] = CompileClassInfo(
|
||||||
name = className,
|
name = className,
|
||||||
|
packageName = packageName,
|
||||||
fieldIds = ctx.memberFieldIds.toMap(),
|
fieldIds = ctx.memberFieldIds.toMap(),
|
||||||
methodIds = ctx.memberMethodIds.toMap(),
|
methodIds = ctx.memberMethodIds.toMap(),
|
||||||
nextFieldId = ctx.nextFieldId,
|
nextFieldId = ctx.nextFieldId,
|
||||||
@ -6873,6 +6876,7 @@ class Compiler(
|
|||||||
val baseIds = collectBaseMemberIds(baseSpecs.map { it.name })
|
val baseIds = collectBaseMemberIds(baseSpecs.map { it.name })
|
||||||
compileClassInfos[className] = CompileClassInfo(
|
compileClassInfos[className] = CompileClassInfo(
|
||||||
name = className,
|
name = className,
|
||||||
|
packageName = packageName,
|
||||||
fieldIds = baseIds.fieldIds,
|
fieldIds = baseIds.fieldIds,
|
||||||
methodIds = baseIds.methodIds,
|
methodIds = baseIds.methodIds,
|
||||||
nextFieldId = baseIds.nextFieldId,
|
nextFieldId = baseIds.nextFieldId,
|
||||||
@ -7121,6 +7125,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
compileClassInfos[qualifiedName] = CompileClassInfo(
|
compileClassInfos[qualifiedName] = CompileClassInfo(
|
||||||
name = qualifiedName,
|
name = qualifiedName,
|
||||||
|
packageName = packageName,
|
||||||
fieldIds = ctx.memberFieldIds.toMap(),
|
fieldIds = ctx.memberFieldIds.toMap(),
|
||||||
methodIds = ctx.memberMethodIds.toMap(),
|
methodIds = ctx.memberMethodIds.toMap(),
|
||||||
nextFieldId = ctx.nextFieldId,
|
nextFieldId = ctx.nextFieldId,
|
||||||
@ -7136,6 +7141,7 @@ class Compiler(
|
|||||||
classCtx?.let { ctx ->
|
classCtx?.let { ctx ->
|
||||||
compileClassInfos[qualifiedName] = CompileClassInfo(
|
compileClassInfos[qualifiedName] = CompileClassInfo(
|
||||||
name = qualifiedName,
|
name = qualifiedName,
|
||||||
|
packageName = packageName,
|
||||||
fieldIds = ctx.memberFieldIds.toMap(),
|
fieldIds = ctx.memberFieldIds.toMap(),
|
||||||
methodIds = ctx.memberMethodIds.toMap(),
|
methodIds = ctx.memberMethodIds.toMap(),
|
||||||
nextFieldId = ctx.nextFieldId,
|
nextFieldId = ctx.nextFieldId,
|
||||||
@ -7222,6 +7228,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
compileClassInfos[qualifiedName] = CompileClassInfo(
|
compileClassInfos[qualifiedName] = CompileClassInfo(
|
||||||
name = qualifiedName,
|
name = qualifiedName,
|
||||||
|
packageName = packageName,
|
||||||
fieldIds = ctx.memberFieldIds.toMap(),
|
fieldIds = ctx.memberFieldIds.toMap(),
|
||||||
methodIds = ctx.memberMethodIds.toMap(),
|
methodIds = ctx.memberMethodIds.toMap(),
|
||||||
nextFieldId = ctx.nextFieldId,
|
nextFieldId = ctx.nextFieldId,
|
||||||
@ -8470,9 +8477,9 @@ class Compiler(
|
|||||||
?: unwrapDirectRef(initializer)?.let { inferObjClassFromRef(it) }
|
?: unwrapDirectRef(initializer)?.let { inferObjClassFromRef(it) }
|
||||||
?: throw ScriptError(initializer.pos, "Delegate type must be known at compile time")
|
?: throw ScriptError(initializer.pos, "Delegate type must be known at compile time")
|
||||||
if (initClass !== delegateClass &&
|
if (initClass !== delegateClass &&
|
||||||
initClass.className != delegateClass.className &&
|
initClass.logicalName != delegateClass.logicalName &&
|
||||||
!initClass.allParentsSet.contains(delegateClass) &&
|
!initClass.allParentsSet.contains(delegateClass) &&
|
||||||
!initClass.allParentsSet.any { it.className == delegateClass.className } &&
|
!initClass.allParentsSet.any { it.logicalName == delegateClass.logicalName } &&
|
||||||
!initClass.allImplementingNames.contains(delegateClass.className)
|
!initClass.allImplementingNames.contains(delegateClass.className)
|
||||||
) {
|
) {
|
||||||
throw ScriptError(
|
throw ScriptError(
|
||||||
@ -8562,7 +8569,9 @@ class Compiler(
|
|||||||
if (closedParent != null) {
|
if (closedParent != null) {
|
||||||
throw ScriptError(Pos.builtIn, "can't inherit from closed class ${closedParent.className}")
|
throw ScriptError(Pos.builtIn, "can't inherit from closed class ${closedParent.className}")
|
||||||
}
|
}
|
||||||
ObjInstanceClass(info.name, *parents.toTypedArray())
|
ObjInstanceClass(info.name, *parents.toTypedArray()).apply {
|
||||||
|
logicalPackageNameOverride = info.packageName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (stub is ObjInstanceClass) {
|
if (stub is ObjInstanceClass) {
|
||||||
for ((fieldName, fieldId) in info.fieldIds) {
|
for ((fieldName, fieldId) in info.fieldIds) {
|
||||||
@ -8982,7 +8991,11 @@ class Compiler(
|
|||||||
|
|
||||||
if (isDelegate && initialExpression != null) {
|
if (isDelegate && initialExpression != null) {
|
||||||
ensureDelegateType(initialExpression)
|
ensureDelegateType(initialExpression)
|
||||||
if (isMutable && resolveInitializerObjClass(initialExpression)?.className == "lazy") {
|
val lazyClass = resolveClassByName("lazy")
|
||||||
|
if (isMutable &&
|
||||||
|
lazyClass != null &&
|
||||||
|
resolveInitializerObjClass(initialExpression)?.logicalName == lazyClass.logicalName
|
||||||
|
) {
|
||||||
throw ScriptError(initialExpression.pos, "lazy delegate is read-only")
|
throw ScriptError(initialExpression.pos, "lazy delegate is read-only")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,10 +106,20 @@ open class ObjClass(
|
|||||||
vararg parents: ObjClass,
|
vararg parents: ObjClass,
|
||||||
) : Obj() {
|
) : Obj() {
|
||||||
|
|
||||||
|
private fun declaringModulePackageName(scope: Scope?): String? {
|
||||||
|
var current = scope
|
||||||
|
while (current != null) {
|
||||||
|
if (current is ModuleScope) return current.packageName
|
||||||
|
current = current.parent
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
var isAnonymous: Boolean = false
|
var isAnonymous: Boolean = false
|
||||||
|
|
||||||
var isAbstract: Boolean = false
|
var isAbstract: Boolean = false
|
||||||
var isClosed: Boolean = false
|
var isClosed: Boolean = false
|
||||||
|
var logicalPackageNameOverride: String? = null
|
||||||
|
|
||||||
// Stable identity and simple structural version for PICs
|
// Stable identity and simple structural version for PICs
|
||||||
val classId: Long = ClassIdGen.nextId()
|
val classId: Long = ClassIdGen.nextId()
|
||||||
@ -169,6 +179,16 @@ open class ObjClass(
|
|||||||
*/
|
*/
|
||||||
var classScope: Scope? = null
|
var classScope: Scope? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stable logical identity for class matching across separately instantiated modules.
|
||||||
|
* Uses declaring module package plus class name when available.
|
||||||
|
*/
|
||||||
|
val logicalPackageName: String?
|
||||||
|
get() = logicalPackageNameOverride ?: declaringModulePackageName(classScope)
|
||||||
|
|
||||||
|
val logicalName: String
|
||||||
|
get() = logicalPackageName?.let { "$it::$className" } ?: className
|
||||||
|
|
||||||
/** Direct parents in declaration order (kept deterministic). */
|
/** Direct parents in declaration order (kept deterministic). */
|
||||||
val directParents: List<ObjClass> = parents.toList()
|
val directParents: List<ObjClass> = parents.toList()
|
||||||
|
|
||||||
|
|||||||
@ -129,6 +129,7 @@ open class ObjDynamic(var readCallback: Obj? = null, var writeCallback: Obj? = n
|
|||||||
}
|
}
|
||||||
|
|
||||||
val type = object : ObjClass("Delegate") {}.apply {
|
val type = object : ObjClass("Delegate") {}.apply {
|
||||||
|
logicalPackageNameOverride = "lyng.stdlib"
|
||||||
addFn("getValue") { raiseError("Delegate.getValue is not implemented") }
|
addFn("getValue") { raiseError("Delegate.getValue is not implemented") }
|
||||||
addFn("setValue") { raiseError("Delegate.setValue is not implemented") }
|
addFn("setValue") { raiseError("Delegate.setValue is not implemented") }
|
||||||
addFn("invoke") { raiseError("Delegate.invoke is not implemented") }
|
addFn("invoke") { raiseError("Delegate.invoke is not implemented") }
|
||||||
|
|||||||
@ -421,7 +421,6 @@ fun with<T,R>(self: T, block: T.()->R): R {
|
|||||||
Can only be used with 'val' properties.
|
Can only be used with 'val' properties.
|
||||||
*/
|
*/
|
||||||
class lazy<T,ThisRefType=Object>(creatorParam: ThisRefType.()->T) : Delegate<T,ThisRefType> {
|
class lazy<T,ThisRefType=Object>(creatorParam: ThisRefType.()->T) : Delegate<T,ThisRefType> {
|
||||||
private val creator: ThisRefType.()->T = creatorParam
|
|
||||||
private var value = Unset
|
private var value = Unset
|
||||||
|
|
||||||
override fun bind(name: String, access: DelegateAccess, thisRef: ThisRefType): Object {
|
override fun bind(name: String, access: DelegateAccess, thisRef: ThisRefType): Object {
|
||||||
@ -431,7 +430,7 @@ class lazy<T,ThisRefType=Object>(creatorParam: ThisRefType.()->T) : Delegate<T,T
|
|||||||
|
|
||||||
override fun getValue(thisRef: ThisRefType, name: String): T {
|
override fun getValue(thisRef: ThisRefType, name: String): T {
|
||||||
if (value == Unset)
|
if (value == Unset)
|
||||||
value = with(thisRef, creator)
|
value = with(thisRef, creatorParam)
|
||||||
value as T
|
value as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user