@@ -774,6 +774,137 @@ HRESULT CLR_RT_HeapBlock::Reassign(const CLR_RT_HeapBlock &value)
774774 NANOCLR_NOCLEANUP ();
775775}
776776
777+ HRESULT CLR_RT_HeapBlock::Reassign (CLR_RT_HeapBlock &rhs, const CLR_RT_TypeDef_Instance &expectedType)
778+ {
779+ NATIVE_PROFILE_CLR_CORE ();
780+ NANOCLR_HEADER ();
781+
782+ // Build a TypeDescriptor for the *expected* type (the IL TypeSpec/TypeDef)
783+ CLR_RT_TypeDescriptor descExpected;
784+ NANOCLR_CHECK_HRESULT (descExpected.InitializeFromTypeDef (expectedType));
785+
786+ // Build a TypeDescriptor for the *actual* runtime object in rhs
787+ CLR_RT_TypeDescriptor descActual;
788+ NANOCLR_CHECK_HRESULT (descActual.InitializeFromObject (rhs));
789+
790+ // Compare them (including generics, arrays, value-types, etc.)
791+ if (!TypeDescriptorsMatch (descExpected, descActual))
792+ {
793+ NANOCLR_SET_AND_LEAVE (CLR_E_WRONG_TYPE);
794+ }
795+
796+ // They match: now do the actual copy
797+ // - reference types & arrays: copy the object reference
798+ // - value-types & primitives: copy the raw data
799+ switch (descActual.GetDataType ())
800+ {
801+ case DATATYPE_CLASS:
802+ case DATATYPE_SZARRAY:
803+ {
804+ // object reference or single-dim array
805+ this ->Assign (rhs);
806+ break ;
807+ }
808+
809+ default :
810+ {
811+ // value-type, primitive, struct, etc.
812+ // this->CopyFrom(rhs);
813+ break ;
814+ }
815+ }
816+
817+ NANOCLR_NOCLEANUP ();
818+ }
819+
820+ bool CLR_RT_HeapBlock::TypeDescriptorsMatch (
821+ const CLR_RT_TypeDescriptor &expectedType,
822+ const CLR_RT_TypeDescriptor &actualType)
823+ {
824+ // Figure out logical DataTypes, promoting ACTUAL CLASS ---> GENERICINST
825+ NanoCLRDataType expectedDataType = expectedType.GetDataType ();
826+ NanoCLRDataType actualDataType = actualType.GetDataType ();
827+
828+ // If the *actual* object is a closed-generic (even though boxed as CLASS),
829+ // it will have m_handlerGenericType set. Promote it to GENERICINST.
830+ if (actualDataType == DATATYPE_CLASS && actualType.m_handlerGenericType .data != CLR_EmptyToken)
831+ {
832+ actualDataType = DATATYPE_GENERICINST;
833+ }
834+
835+ // If either side is GENERICINST, we do generic-inst matching
836+ if (expectedDataType == DATATYPE_GENERICINST || actualDataType == DATATYPE_GENERICINST)
837+ {
838+ auto &eSpec = expectedType.m_handlerGenericType ;
839+ auto &aSpec = actualType.m_handlerGenericType ;
840+
841+ return eSpec.Assembly () == aSpec.Assembly () && eSpec.typeDefIndex == aSpec.typeDefIndex ;
842+ }
843+
844+ if (actualDataType <= DATATYPE_LAST_PRIMITIVE_TO_PRESERVE)
845+ {
846+ // If they declared a true valuetype, match directly:
847+ if (expectedDataType == DATATYPE_VALUETYPE)
848+ {
849+ const auto &dtl = c_CLR_RT_DataTypeLookup[actualDataType];
850+ if (dtl.m_cls && dtl.m_cls ->data == expectedType.m_handlerCls .data )
851+ {
852+ return true ;
853+ }
854+ }
855+ // if they declared a boxed struct (CLASS whose TypeDef is a struct),
856+ // need to match that too:
857+ else if (expectedDataType == DATATYPE_CLASS && expectedType.m_handlerGenericType .data == 0 )
858+ {
859+ // Look up the TypeDef record flags to see if it's a VALUE-TYPE.
860+ CLR_RT_TypeDef_Index clsIdx = expectedType.m_handlerCls ;
861+
862+ // fetch the owning assembly
863+ CLR_RT_Assembly *ownerAsm = g_CLR_RT_TypeSystem.m_assemblies [clsIdx.Assembly () - 1 ];
864+ const CLR_RECORD_TYPEDEF *rec = ownerAsm->GetTypeDef (clsIdx.Type ());
865+
866+ if (rec &&
867+ ((rec->flags & CLR_RECORD_TYPEDEF::TD_Semantics_Mask) == CLR_RECORD_TYPEDEF::TD_Semantics_ValueType))
868+ {
869+ const auto &dtl = c_CLR_RT_DataTypeLookup[actualDataType];
870+ if (dtl.m_cls && dtl.m_cls ->data == clsIdx.data )
871+ {
872+ return true ;
873+ }
874+ }
875+ }
876+ }
877+
878+ // For everything else, DataTypes must line up exactly
879+ if (expectedDataType != actualDataType)
880+ {
881+ return false ;
882+ }
883+
884+ // Dispatch on the remaining kinds
885+ switch (expectedDataType)
886+ {
887+ case DATATYPE_CLASS:
888+ case DATATYPE_VALUETYPE:
889+ {
890+ // compare TypeDef indices
891+ auto &eCls = expectedType.m_handlerCls ;
892+ auto &aCls = actualType.m_handlerCls ;
893+ return eCls.data == aCls.data ;
894+ }
895+
896+ case DATATYPE_SZARRAY:
897+ {
898+ // compare outer dims (always 1) then element types
899+ return TypeDescriptorsMatch (expectedType, actualType);
900+ }
901+
902+ // primitives and other leaf types match on the DataType alone
903+ default :
904+ return true ;
905+ }
906+ }
907+
777908void CLR_RT_HeapBlock::AssignAndPinReferencedObject (const CLR_RT_HeapBlock &value)
778909{
779910 // This is very special case that we have local variable with pinned attribute in metadata.
@@ -787,7 +918,7 @@ void CLR_RT_HeapBlock::AssignAndPinReferencedObject(const CLR_RT_HeapBlock &valu
787918 m_data.objectReference .ptr ->Unpin ();
788919 }
789920
790- // Move the data.
921+ // Move the data
791922 m_data = value.m_data ;
792923
793924 // Leave the same logic as in AssignAndPreserveType
0 commit comments