diff --git a/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustBackend.kt b/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustBackend.kt index d1e64dc..f5c46ff 100644 --- a/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustBackend.kt +++ b/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustBackend.kt @@ -311,7 +311,7 @@ private fun MutableList.addLib( path = filePath("src", "lib.rs"), content = Rust.SourceFile( pos, - attrs = listOf(allowWarnings(pos)), + attrs = allowWarnings(pos), items = buildList { // Separate mods. declareSubmods(pos, allModKids[libraryConfiguration.libraryRoot] ?: setOf()) diff --git a/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustExt.kt b/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustExt.kt index 0e738d5..a75e854 100644 --- a/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustExt.kt +++ b/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustExt.kt @@ -43,14 +43,12 @@ import lang.temper.type2.withType * change in edition. We should investigate this more in the future, though. It would * be good to support latest expectations. */ -internal fun allowWarnings(pos: Position): Rust.AttrInner = Rust.AttrInner( - pos, - Rust.Call( - pos, - "allow".toId(pos), - listOf("dependency_on_unit_never_type_fallback", "warnings").map { it.toId(pos) }, - ), -) +internal fun allowWarnings(pos: Position) = run { + // Separate them with `warnings` first, to prevent warnings against the other on older rust. + listOf("warnings", "dependency_on_unit_never_type_fallback").map { key -> + Rust.AttrInner(pos, Rust.Call(pos, "allow".toId(pos), listOf(key.toId(pos)))) + } +} internal fun makeError(pos: Position) = Rust.Call(pos, callee = ERROR_NEW_NAME.toId(pos), args = listOf()) diff --git a/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustTranslator.kt b/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustTranslator.kt index 71d7b08..6e6d975 100644 --- a/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustTranslator.kt +++ b/be-rust/src/commonMain/kotlin/lang/temper/be/rust/RustTranslator.kt @@ -21,10 +21,12 @@ import lang.temper.be.tmpl.typeOrInvalid import lang.temper.common.compatRemoveLast import lang.temper.common.subListToEnd import lang.temper.frontend.ModuleNamingContext +import lang.temper.frontend.typestage.findOverrides import lang.temper.interp.importExport.STANDARD_LIBRARY_NAME import lang.temper.lexer.withTemperAwareExtension import lang.temper.library.LibraryConfigurations import lang.temper.log.FilePath +import lang.temper.log.LogSink import lang.temper.log.Position import lang.temper.log.last import lang.temper.name.BuiltinName @@ -38,6 +40,7 @@ import lang.temper.name.Temporary import lang.temper.type.Abstractness import lang.temper.type.MethodKind import lang.temper.type.MethodShape +import lang.temper.type.PropertyShape import lang.temper.type.TypeDefinition import lang.temper.type.TypeFormal import lang.temper.type.TypeShape @@ -51,6 +54,7 @@ import lang.temper.type2.NonNullType import lang.temper.type2.Nullity import lang.temper.type2.Signature2 import lang.temper.type2.Type2 +import lang.temper.type2.TypeContext2 import lang.temper.type2.TypeParamRef import lang.temper.type2.ValueFormalKind import lang.temper.type2.hackMapOldStyleToNew @@ -94,6 +98,7 @@ class RustTranslator( private var insideMutableType = false private val failVars = mutableSetOf() private val functionContextStack = mutableListOf() + private val logSink = LogSink.devNull // TODO what? private val loopLabels = mutableListOf() private val moduleInits = mutableListOf() private val moduleItems = mutableListOf() @@ -102,6 +107,7 @@ class RustTranslator( } private val testItems = mutableListOf() private val traitImports = mutableSetOf() + private val typeContext = TypeContext2() fun translateModule(): Backend.TranslatedFileSpecification { // Preprocess tops. @@ -137,7 +143,7 @@ class RustTranslator( path = makeSrcFilePath(relPath.withTemperAwareExtension("")), content = Rust.SourceFile( pos, - attrs = listOf(allowWarnings(module.pos)), + attrs = allowWarnings(module.pos), items = buildList { // Declare submodules, except for root that needs to declare in lib file. if (!isRoot) { @@ -310,7 +316,7 @@ class RustTranslator( // And for now, skip those with rest parameters. TODO Extract to list value? fn.parameters.restParameter != null && return // Build the builder. - // Here we make `WhateverBuilder` for requireds and/or `WhateverBuilderOptions` structs for optionals. + // Here we make `WhateverBuilder` for requireds and/or `WhateverOptions` structs for optionals. // Alternatively, could make a Java-style builder, which is common in Rust, but it takes less advantage of // standard static checking that we get with pub struct fields. val pos = fn.pos @@ -775,8 +781,8 @@ class RustTranslator( for (supMethod in supShape.methods) { maybeAddTraitForwarder( pos, - instanceMethods, - isInterface = isInterface, + decl = decl, + instanceMethods = instanceMethods, methodKind = supMethod.methodKind, methodName = supMethod.name.displayName, returnType = supMethod.descriptor.orInvalid.returnType2, @@ -788,8 +794,8 @@ class RustTranslator( if (supProperty.getter == null) { maybeAddTraitForwarder( pos, - instanceMethods, - isInterface = isInterface, + decl = decl, + instanceMethods = instanceMethods, methodKind = MethodKind.Getter, methodName = BuiltinName("get.${supProperty.symbol.text}").displayName, superShape = supProperty, @@ -798,8 +804,8 @@ class RustTranslator( if (supProperty.setter == null && supProperty.hasSetter) { maybeAddTraitForwarder( pos, - instanceMethods, - isInterface = isInterface, + decl = decl, + instanceMethods = instanceMethods, methodKind = MethodKind.Setter, methodName = BuiltinName("set.${supProperty.symbol.text}").displayName, superShape = supProperty, @@ -815,18 +821,19 @@ class RustTranslator( private fun MutableList.maybeAddTraitForwarder( pos: Position, + decl: TmpL.TypeDeclaration, instanceMethods: Map, - isInterface: Boolean, methodKind: MethodKind, methodName: String, superShape: VisibleMemberShape, returnType: Type2? = null, ) { + val isInterface = decl.kind == TmpL.TypeDeclarationKind.Interface when { - isInterface -> buildForwarderForTrait(pos, superShape, methodKind) + isInterface -> buildForwarderFromInterfaceToTrait(pos, superShape, methodKind) else -> when (val method = instanceMethods[methodName]) { - null -> listOf() - else -> buildForwarder(method, returnType = returnType) + null -> buildForwarderFromClassToTrait(pos, decl, superShape, methodKind) + else -> buildForwarder(method, returnType) } }.also { addAll(it) } // only one expected here, but meh } @@ -1073,59 +1080,112 @@ class RustTranslator( return translateMethodLike(method, block = block, forTrait = true, returnType = effectiveReturnType) } + private fun buildForwarderFromClassToTrait( + pos: Position, + decl: TmpL.TypeDeclaration, + superShape: VisibleMemberShape, + methodKind: MethodKind, + ): List = run { + // We're here because this class has no matching member, so walk its supertypes to match the super method. + // The method we inherit closest might be on a different branch. + val overrides = findOverrides(decl.typeShape, superShape, typeContext, logSink) + val override = overrides.find overrides@{ override -> + when (val foundMember = override.superTypeMember) { + is MethodShape -> !foundMember.isPureVirtual + is PropertyShape -> when (methodKind) { + MethodKind.Getter -> foundMember.getter + MethodKind.Setter -> foundMember.setter + else -> return@overrides false + }.let { foundName -> + // Interfaces can only provide property implementations with methods, so look at those. + foundMember.enclosingType.methods.any { method -> + !method.isPureVirtual && method.methodKind == methodKind && method.name == foundName + } + } + else -> false + } + } + // Having selected an override, forward to it with simple self. + val targetType = override?.superTypeMember?.enclosingType + if (targetType == superShape.enclosingType) { + // Just let the trait handle this one directly. Self-call here is infinite recursion. + return listOf() + } + buildForwarderToTrait(pos, targetType, superShape, methodKind) result@{ traitType, methodId, argIds -> + Rust.Call( + pos, + callee = traitType.extendWith(methodId.deepCopy()), + args = buildList { + add("self".toKeyId(pos)) + addAll(argIds) + }, + ) + } + } + /** * Build a forwarder from a trait wrapper to a trait method that *isn't* * overridden in the current trait. We need this to handle methods for * which we have only frontend descriptions, not tmpl. */ - private fun buildForwarderForTrait( + private fun buildForwarderFromInterfaceToTrait( + pos: Position, + shape: VisibleMemberShape, + methodKind: MethodKind, + ): List = run { + // From trait wrapper to trait, just forward the call with the unwrapped innards. + buildForwarderToTrait(pos, shape.enclosingType, shape, methodKind) result@{ traitType, methodId, argIds -> + Rust.Call( + pos, + callee = traitType.extendWith(methodId.deepCopy()), + args = buildList { + add("self".toKeyId(pos).member("0", notMethod = true).deref().ref()) + addAll(argIds) + }, + ) + } + } + + private fun buildForwarderToTrait( pos: Position, + targetType: TypeShape?, shape: VisibleMemberShape, methodKind: MethodKind, + /** Trait type, method id, and arg ids, all ready to be used. */ + buildResult: (Rust.Path, Rust.Id, List) -> Rust.Expr?, ): List = run { val selfParam = Rust.RefType(pos, "self".toKeyId(pos)) - val selfArg = "self".toKeyId(pos).member("0", notMethod = true).deref().ref() - val enclosingType = - (translateTypeDefinition(shape.enclosingType, pos) as? Rust.Path)?.suffixed(TRAIT_NAME_SUFFIX) + val traitType = targetType?.let { + (translateTypeDefinition(targetType, pos) as? Rust.Path)?.suffixed(TRAIT_NAME_SUFFIX) + } when (methodKind) { MethodKind.Normal -> { val method = shape as MethodShape val methodId = translateIdFromName(pos, method.name as ResolvedName, NameStyle.Snake) val sig = method.descriptor ?: return listOf() - val argNames = (1.. + "arg$arg".toId(pos) + } Rust.Function( pos, - id = methodId, + id = methodId.deepCopy(), params = buildList { add(selfParam) var index = 0 for (paramType in sig.requiredInputTypes.subListToEnd(1)) { - val paramName = argNames[index++].toId(pos) + val paramName = argIds[index++].deepCopy() val translatedType = translateType(paramType, pos) add(Rust.FunctionParam(pos, paramName, translatedType)) } for (paramType in sig.optionalInputTypes) { - val paramName = argNames[index++].toId(pos) + val paramName = argIds[index++].deepCopy() val translatedType = translateType(paramType, pos).option() add(Rust.FunctionParam(pos, paramName, translatedType)) } }, returnType = method.descriptor?.let { translateType(it.returnType2, pos = pos) }, - block = Rust.Block( - pos, - result = enclosingType?.let { type -> - Rust.Call( - pos, - callee = type.extendWith(methodId.deepCopy()), - args = buildList { - add(selfArg) - for (argName in argNames) { - add(argName.toId(pos)) - } - }, - ) - }, - ), + block = Rust.Block(pos, result = traitType?.let { buildResult(it, methodId, argIds) }), ) } MethodKind.Getter -> { @@ -1135,15 +1195,12 @@ class RustTranslator( is Type2 -> descriptor else -> null }?.let { translateType(it, pos = pos) } - val call = enclosingType?.let { type -> - Rust.Call(pos, type.extendWith(methodId.deepCopy()), listOf(selfArg)) - } Rust.Function( pos, - id = methodId, + id = methodId.deepCopy(), params = listOf(selfParam), returnType = returnType, - block = Rust.Block(pos, result = call), + block = Rust.Block(pos, result = traitType?.let { buildResult(it, methodId, listOf()) }), ) } MethodKind.Setter -> { @@ -1155,15 +1212,11 @@ class RustTranslator( }?.let { translateType(it, pos = pos) } // We don't have param names here, so invent one. val value = "value".toId(pos) - val call = enclosingType?.let { type -> - val args = listOf(selfArg, value.deepCopy()) - Rust.Call(pos, type.extendWith(methodId.deepCopy()), args) - } Rust.Function( pos, id = methodId, - params = listOf(selfParam, Rust.FunctionParam(pos, value, propertyType)), - block = Rust.Block(pos, result = call), + params = listOf(selfParam, Rust.FunctionParam(pos, value.deepCopy(), propertyType)), + block = Rust.Block(pos, result = traitType?.let { buildResult(it, methodId, listOf(value)) }), ) } else -> return listOf() diff --git a/be-rust/src/commonTest/kotlin/lang/temper/be/rust/RustBackendTest.kt b/be-rust/src/commonTest/kotlin/lang/temper/be/rust/RustBackendTest.kt index c812600..540e0a1 100644 --- a/be-rust/src/commonTest/kotlin/lang/temper/be/rust/RustBackendTest.kt +++ b/be-rust/src/commonTest/kotlin/lang/temper/be/rust/RustBackendTest.kt @@ -67,7 +67,8 @@ class RustBackendTest { | src: { | lib.rs: { | content: ``` - | #![allow(dependency_on_unit_never_type_fallback, warnings)] + | #![allow(warnings)] + | #![allow(dependency_on_unit_never_type_fallback)] | pub mod bar; | mod r#mod; | pub use r#mod::*; @@ -86,7 +87,8 @@ class RustBackendTest { | main.rs: "__DO_NOT_CARE__", | mod.rs: { | content: ``` - | #![allow(dependency_on_unit_never_type_fallback, warnings)] + | #![allow(warnings)] + | #![allow(dependency_on_unit_never_type_fallback)] | use temper_core::AnyValueTrait; | use temper_core::AsAnyValue; | use temper_core::Pair; @@ -124,7 +126,8 @@ class RustBackendTest { | bar: { | mod.rs: { | content: ``` - | #![allow(dependency_on_unit_never_type_fallback, warnings)] + | #![allow(warnings)] + | #![allow(dependency_on_unit_never_type_fallback)] | use temper_core::AnyValueTrait; | use temper_core::AsAnyValue; | use temper_core::Pair; @@ -1067,7 +1070,8 @@ class RustBackendTest { | src: { | lib.rs: { | content: ``` - | #![allow(dependency_on_unit_never_type_fallback, warnings)] + | #![allow(warnings)] + | #![allow(dependency_on_unit_never_type_fallback)] | pub mod bar; | pub mod bob; | mod support; @@ -1086,7 +1090,8 @@ class RustBackendTest { | bar: { | mod.rs: { | content: ``` - | #![allow(dependency_on_unit_never_type_fallback, warnings)] + | #![allow(warnings)] + | #![allow(dependency_on_unit_never_type_fallback)] | use temper_core::AnyValueTrait; | use temper_core::AsAnyValue; | use temper_core::Pair; @@ -1122,7 +1127,8 @@ class RustBackendTest { | "beth": { | "mod.rs": { | content: ``` - | #![allow(dependency_on_unit_never_type_fallback, warnings)] + | #![allow(warnings)] + | #![allow(dependency_on_unit_never_type_fallback)] | use temper_core::AnyValueTrait; | use temper_core::AsAnyValue; | use temper_core::Pair; @@ -1253,6 +1259,7 @@ class RustBackendTest { assertGenerateWanted( temper = """ |interface A { + | // Use different ways of declaring props. | public var prop: String; | public get thing(): String; | public set thing(that: String): Void; @@ -1270,6 +1277,19 @@ class RustBackendTest { | public greeting(): String { "Ha!" } | public spawn(): C> { new C>("", "") } |} + |// D provides alternate paths for override resolution. + |interface D extends A { + | public get prop(): String { "Hello!" } + | public set prop(value: String): Void {} + | public set thing(value: String): Void {} + | public whatever(): String { "sure" } + |} + |// E provides indirection on type bindings to D. + |interface E extends D {} + |// Alternate prop/thing set/get vs D above. + |class F extends B> & E { + | public get thing(): String { "Hello!" } + |} """.trimMargin(), rust = """ |pub (crate) fn init() -> temper_core::Result<()> { @@ -1434,6 +1454,9 @@ class RustBackendTest { | fn greeting(& self) -> std::sync::Arc { | self.greeting() | } + | fn whatever(& self) -> std::sync::Arc { + | BTrait::whatever(self) + | } | fn prop(& self) -> std::sync::Arc { | self.prop() | } @@ -1442,6 +1465,194 @@ class RustBackendTest { | } |} |temper_core::impl_any_value_trait!(C, [B, A] where T: ATrait); + |trait DTrait: temper_core::AsAnyValue + temper_core::AnyValueTrait + std::marker::Send + std::marker::Sync + ATrait { + | fn clone_boxed(& self) -> D; + | fn prop(& self) -> std::sync::Arc { + | return std::sync::Arc::new("Hello!".to_string()); + | } + | fn set_prop(& self, value__0: std::sync::Arc) {} + | fn thing(& self) -> std::sync::Arc; + | fn set_thing(& self, value__1: std::sync::Arc) {} + | fn whatever(& self) -> std::sync::Arc { + | return std::sync::Arc::new("sure".to_string()); + | } + |} + |#[derive(Clone)] + |struct D(std::sync::Arc>); + |impl D { + | pub fn new(selfish: impl DTrait + 'static) -> D { + | D(std::sync::Arc::new(selfish)) + | } + |} + |impl DTrait for D { + | fn clone_boxed(& self) -> D { + | DTrait::clone_boxed( & ( * self.0)) + | } + | fn prop(& self) -> std::sync::Arc { + | DTrait::prop( & ( * self.0)) + | } + | fn set_prop(& self, value: std::sync::Arc) { + | DTrait::set_prop( & ( * self.0), value) + | } + | fn set_thing(& self, value: std::sync::Arc) { + | DTrait::set_thing( & ( * self.0), value) + | } + | fn whatever(& self) -> std::sync::Arc { + | DTrait::whatever( & ( * self.0)) + | } + | fn thing(& self) -> std::sync::Arc { + | DTrait::thing( & ( * self.0)) + | } + |} + |impl ATrait for D { + | fn clone_boxed(& self) -> A { + | ATrait::clone_boxed( & ( * self.0)) + | } + | fn thing(& self) -> std::sync::Arc { + | ATrait::thing( & ( * self.0)) + | } + | fn set_thing(& self, value: std::sync::Arc) { + | ATrait::set_thing( & ( * self.0), value) + | } + | fn greeting(& self) -> std::sync::Arc { + | ATrait::greeting( & ( * self.0)) + | } + | fn whatever(& self) -> std::sync::Arc { + | ATrait::whatever( & ( * self.0)) + | } + | fn prop(& self) -> std::sync::Arc { + | ATrait::prop( & ( * self.0)) + | } + | fn set_prop(& self, value: std::sync::Arc) { + | ATrait::set_prop( & ( * self.0), value) + | } + |} + |temper_core::impl_any_value_trait_for_interface!(D); + |impl std::ops::Deref for D { + | type Target = dyn DTrait; + | fn deref(& self) -> & Self::Target { + | & ( * self.0) + | } + |} + |trait ETrait: temper_core::AsAnyValue + temper_core::AnyValueTrait + std::marker::Send + std::marker::Sync + DTrait { + | fn clone_boxed(& self) -> E; + |} + |#[derive(Clone)] + |struct E(std::sync::Arc>); + |impl E { + | pub fn new(selfish: impl ETrait + 'static) -> E { + | E(std::sync::Arc::new(selfish)) + | } + |} + |impl ETrait for E { + | fn clone_boxed(& self) -> E { + | ETrait::clone_boxed( & ( * self.0)) + | } + |} + |impl DTrait for E { + | fn clone_boxed(& self) -> D { + | DTrait::clone_boxed( & ( * self.0)) + | } + | fn prop(& self) -> std::sync::Arc { + | DTrait::prop( & ( * self.0)) + | } + | fn set_prop(& self, value: std::sync::Arc) { + | DTrait::set_prop( & ( * self.0), value) + | } + | fn set_thing(& self, value: std::sync::Arc) { + | DTrait::set_thing( & ( * self.0), value) + | } + | fn whatever(& self) -> std::sync::Arc { + | DTrait::whatever( & ( * self.0)) + | } + | fn thing(& self) -> std::sync::Arc { + | DTrait::thing( & ( * self.0)) + | } + |} + |impl ATrait for E { + | fn clone_boxed(& self) -> A { + | ATrait::clone_boxed( & ( * self.0)) + | } + | fn thing(& self) -> std::sync::Arc { + | ATrait::thing( & ( * self.0)) + | } + | fn set_thing(& self, value: std::sync::Arc) { + | ATrait::set_thing( & ( * self.0), value) + | } + | fn greeting(& self) -> std::sync::Arc { + | ATrait::greeting( & ( * self.0)) + | } + | fn whatever(& self) -> std::sync::Arc { + | ATrait::whatever( & ( * self.0)) + | } + | fn prop(& self) -> std::sync::Arc { + | ATrait::prop( & ( * self.0)) + | } + | fn set_prop(& self, value: std::sync::Arc) { + | ATrait::set_prop( & ( * self.0), value) + | } + |} + |temper_core::impl_any_value_trait_for_interface!(E); + |impl std::ops::Deref for E { + | type Target = dyn ETrait; + | fn deref(& self) -> & Self::Target { + | & ( * self.0) + | } + |} + |struct FStruct {} + |#[derive(Clone)] + |pub (crate) struct F(std::sync::Arc); + |impl F { + | pub fn thing(& self) -> std::sync::Arc { + | return std::sync::Arc::new("Hello!".to_string()); + | } + | pub fn new() -> F { + | let selfish = F(std::sync::Arc::new(FStruct {})); + | return selfish; + | } + |} + |impl BTrait> for F { + | fn clone_boxed(& self) -> B> { + | B::new(self.clone()) + | } + |} + |impl ATrait for F { + | fn clone_boxed(& self) -> A { + | A::new(self.clone()) + | } + | fn thing(& self) -> std::sync::Arc { + | self.thing() + | } + | fn set_thing(& self, value: std::sync::Arc) { + | DTrait::set_thing(self, value) + | } + | fn whatever(& self) -> std::sync::Arc { + | BTrait::whatever(self) + | } + | fn prop(& self) -> std::sync::Arc { + | DTrait::prop(self) + | } + | fn set_prop(& self, value: std::sync::Arc) { + | DTrait::set_prop(self, value) + | } + |} + |impl ETrait for F { + | fn clone_boxed(& self) -> E { + | E::new(self.clone()) + | } + |} + |impl DTrait for F { + | fn clone_boxed(& self) -> D { + | D::new(self.clone()) + | } + | fn whatever(& self) -> std::sync::Arc { + | BTrait::whatever(self) + | } + | fn thing(& self) -> std::sync::Arc { + | self.thing() + | } + |} + |temper_core::impl_any_value_trait!(F, [B>, A, E, D]); """.trimMargin(), ) } @@ -2424,7 +2635,8 @@ private fun assertGenerateWanted(modules: List) { | "mod.rs": { | "content": |``` - |#![allow(dependency_on_unit_never_type_fallback, warnings)] + |#![allow(warnings)] + |#![allow(dependency_on_unit_never_type_fallback)] |use temper_core::AnyValueTrait; |use temper_core::AsAnyValue; |use temper_core::Pair; diff --git a/frontend/src/commonMain/kotlin/lang/temper/frontend/typestage/OverrideLinker.kt b/frontend/src/commonMain/kotlin/lang/temper/frontend/typestage/OverrideLinker.kt index 866e0d5..66dd32a 100644 --- a/frontend/src/commonMain/kotlin/lang/temper/frontend/typestage/OverrideLinker.kt +++ b/frontend/src/commonMain/kotlin/lang/temper/frontend/typestage/OverrideLinker.kt @@ -29,20 +29,33 @@ import lang.temper.type2.hackMapOldStyleToNew import lang.temper.type2.mapType import kotlin.math.min +/** + * Updates [member]'s overridden members with those found from its enclosing type. + */ internal fun linkOverrides( member: VisibleMemberShape, typeContext: TypeContext2, logSink: LogSink, ) { + member.overriddenMembers = findOverrides(member.enclosingType, member, typeContext, logSink) +} + +/** + * Return overrides for the given [member] shape in the [enclosingTypeShape] context. + * Doesn't require that the member actually be defined in the given enclosing type. + */ +fun findOverrides( + enclosingTypeShape: TypeShape, + member: VisibleMemberShape, + typeContext: TypeContext2, + logSink: LogSink, +): Set { if (member.visibility == Visibility.Private || member is StaticPropertyShape) { // Private members and statics override nothing nor are overridden. // Dispatch to them is non-virtual. - member.overriddenMembers = emptySet() - return + return emptySet() } val overriddenMembers = mutableSetOf() - - val enclosingTypeShape = member.enclosingType val enclosingType = MkType.nominal( enclosingTypeShape, enclosingTypeShape.typeParameters.map { MkType.nominal(it.definition, emptyList()) }, @@ -61,8 +74,7 @@ internal fun linkOverrides( true } } - - member.overriddenMembers = overriddenMembers.toSet() + return overriddenMembers.toSet() } private fun overriddenIn(