more types tests and fixes

This commit is contained in:
Sergey Chernov 2026-03-09 12:32:37 +03:00
parent 90e586b5d2
commit 32a7adf56e
2 changed files with 49 additions and 2 deletions

View File

@ -4335,15 +4335,39 @@ class Compiler(
else -> null else -> null
} }
private fun seedTypeDeclByName(name: String): TypeDecl? {
seedScope?.getLocalRecordDirect(name)?.typeDecl?.let { return it }
seedScope?.get(name)?.typeDecl?.let { return it }
importManager.rootScope.getLocalRecordDirect(name)?.typeDecl?.let { return it }
importManager.rootScope.get(name)?.typeDecl?.let { return it }
for (module in importedModules.asReversed()) {
module.scope.get(name)?.typeDecl?.let { return it }
}
return null
}
private fun resolveReceiverTypeDecl(ref: ObjRef): TypeDecl? { private fun resolveReceiverTypeDecl(ref: ObjRef): TypeDecl? {
return when (ref) { return when (ref) {
is LocalSlotRef -> { is LocalSlotRef -> {
val ownerScopeId = ref.captureOwnerScopeId ?: ref.scopeId val ownerScopeId = ref.captureOwnerScopeId ?: ref.scopeId
val ownerSlot = ref.captureOwnerSlot ?: ref.slot val ownerSlot = ref.captureOwnerSlot ?: ref.slot
slotTypeDeclByScopeId[ownerScopeId]?.get(ownerSlot) slotTypeDeclByScopeId[ownerScopeId]?.get(ownerSlot)
?: nameTypeDecl[ref.name]
?: seedTypeDeclByName(ref.name)
}
is LocalVarRef -> nameTypeDecl[ref.name] ?: seedTypeDeclByName(ref.name)
is FastLocalVarRef -> nameTypeDecl[ref.name] ?: seedTypeDeclByName(ref.name)
is FieldRef -> {
val targetDecl = resolveReceiverTypeDecl(ref.target) ?: return null
val targetClass = resolveTypeDeclObjClass(targetDecl)
targetClass?.getInstanceMemberOrNull(ref.name, includeAbstract = true)?.typeDecl?.let { return it }
classFieldTypesByName[targetClass?.className]?.get(ref.name)
?.let { return TypeDecl.Simple(it.className, false) }
when (targetDecl) {
TypeDecl.TypeAny, TypeDecl.TypeNullableAny -> null
else -> TypeDecl.TypeVar("${typeDeclName(targetDecl)}.${ref.name}", false)
}
} }
is LocalVarRef -> nameTypeDecl[ref.name]
is FastLocalVarRef -> nameTypeDecl[ref.name]
is MethodCallRef -> methodReturnTypeDeclByRef[ref] is MethodCallRef -> methodReturnTypeDeclByRef[ref]
is StatementRef -> (ref.statement as? ExpressionStatement)?.let { resolveReceiverTypeDecl(it.ref) } is StatementRef -> (ref.statement as? ExpressionStatement)?.let { resolveReceiverTypeDecl(it.ref) }
else -> null else -> null
@ -4361,6 +4385,8 @@ class Compiler(
} else { } else {
slotTypeByScopeId[ownerScopeId]?.get(ownerSlot) slotTypeByScopeId[ownerScopeId]?.get(ownerSlot)
?: slotTypeDeclByScopeId[ownerScopeId]?.get(ownerSlot)?.let { resolveTypeDeclObjClass(it) } ?: slotTypeDeclByScopeId[ownerScopeId]?.get(ownerSlot)?.let { resolveTypeDeclObjClass(it) }
?: nameTypeDecl[ref.name]?.let { resolveTypeDeclObjClass(it) }
?: seedTypeDeclByName(ref.name)?.let { resolveTypeDeclObjClass(it) }
?: knownClass ?: knownClass
} }
?: resolveClassByName(ref.name) ?: resolveClassByName(ref.name)
@ -4567,6 +4593,18 @@ class Compiler(
if (targetClass == null) return null if (targetClass == null) return null
if (targetClass == ObjDynamic.type) return ObjDynamic.type if (targetClass == ObjDynamic.type) return ObjDynamic.type
classFieldTypesByName[targetClass.className]?.get(name)?.let { return it } classFieldTypesByName[targetClass.className]?.get(name)?.let { return it }
var hasUntypedMember = false
targetClass.getInstanceMemberOrNull(name, includeAbstract = true)?.let { member ->
member.typeDecl?.let { declaredType ->
when (declaredType) {
TypeDecl.TypeAny, TypeDecl.TypeNullableAny -> return Obj.rootObjectType
else -> {
resolveTypeDeclObjClass(declaredType)?.let { return it }
}
}
}
hasUntypedMember = true
}
enumEntriesByName[targetClass.className]?.let { entries -> enumEntriesByName[targetClass.className]?.let { entries ->
return when { return when {
name == "entries" -> ObjList.type name == "entries" -> ObjList.type
@ -4653,6 +4691,9 @@ class Compiler(
if (targetClass == ObjRegex.type && name == "pattern") { if (targetClass == ObjRegex.type && name == "pattern") {
return ObjString.type return ObjString.type
} }
if (hasUntypedMember) {
return ObjDynamic.type
}
return null return null
} }
@ -4666,6 +4707,10 @@ class Compiler(
if (left is LocalSlotRef && left.name == "scope") return if (left is LocalSlotRef && left.name == "scope") return
val receiverClass = resolveReceiverClassForMember(left) val receiverClass = resolveReceiverClassForMember(left)
if (receiverClass == null) { if (receiverClass == null) {
val receiverDecl = resolveReceiverTypeDecl(left)
if (receiverDecl != null && receiverDecl != TypeDecl.TypeAny && receiverDecl != TypeDecl.TypeNullableAny) {
return
}
if (isAllowedObjectMember(memberName)) return if (isAllowedObjectMember(memberName)) return
throw ScriptError(pos, "member access requires compile-time receiver type: $memberName") throw ScriptError(pos, "member access requires compile-time receiver type: $memberName")
} }

View File

@ -187,10 +187,12 @@ class TypesTest {
eval( eval(
""" """
class Ctx { class Ctx {
val contract = null
fun println(msg: String) = msg fun println(msg: String) = msg
} }
fun use(callContext) { fun use(callContext) {
assert(callContext is Ctx) assert(callContext is Ctx)
assert(callContext.contract == null)
callContext.println("hello") callContext.println("hello")
} }
assertEquals("hello", use(Ctx())) assertEquals("hello", use(Ctx()))