diff --git a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp index 59514fa169..23d6d80070 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp @@ -1,4 +1,4 @@ -// +// // Copyright (c) .NET Foundation and Contributors // Portions Copyright (c) Microsoft Corporation. All rights reserved. // See LICENSE file in the project root for full license information. @@ -144,7 +144,18 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( CLR_RT_ReflectionDef_Index reflex{}; reflex.kind = REFLECTION_TYPE; reflex.levels = tsInst.levels; - reflex.data.type = tsInst.cachedElementType; + + // For generic instantiation TypeSpecs (e.g. Pair), genericTypeDef holds + // the open generic typedef (e.g. Pair<,>). cachedElementType is only set for + // non-generic TypeSpecs resolved via VAR/MVAR, so prefer genericTypeDef when valid. + if (NANOCLR_INDEX_IS_VALID(tsInst.genericTypeDef)) + { + reflex.data.type = tsInst.genericTypeDef; + } + else + { + reflex.data.type = tsInst.cachedElementType; + } NANOCLR_CHECK_HRESULT(ref.SetReflection(reflex)); } diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 10fbab98f9..5c0210d7b7 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2083,7 +2083,8 @@ static HRESULT ResolveGenericTypeParameter( HRESULT CLR_RT_ExecutionEngine::InitializeReference( CLR_RT_HeapBlock &ref, CLR_RT_SignatureParser &parser, - const CLR_RT_TypeSpec_Instance *genericInstance) + const CLR_RT_TypeSpec_Instance *genericInstance, + bool allowUnresolvedVarFallback) { NATIVE_PROFILE_CLR_CORE(); // @@ -2117,13 +2118,26 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference( { if (genericInstance == nullptr || !NANOCLR_INDEX_IS_VALID(*genericInstance)) { - NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); + if (allowUnresolvedVarFallback) + { + // VAR cannot be resolved without a closed generic context (e.g. when + // pre-allocating array element structs for an open generic type). + // Treat as an object reference (null) so field initialization proceeds; + // subsequent stfld instructions will overwrite with the correct type. + dt = DATATYPE_OBJECT; + } + else + { + NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); + } } + else + { + NANOCLR_CHECK_HRESULT( + ResolveGenericTypeParameter(*genericInstance, res.GenericParamPosition, realTypeDef, dt)); - NANOCLR_CHECK_HRESULT( - ResolveGenericTypeParameter(*genericInstance, res.GenericParamPosition, realTypeDef, dt)); - - goto process_datatype; + goto process_datatype; + } } else if (dt == DATATYPE_MVAR) { @@ -2201,7 +2215,8 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference( CLR_RT_HeapBlock &ref, const CLR_RECORD_FIELDDEF *target, CLR_RT_Assembly *assm, - const CLR_RT_TypeSpec_Instance *genericInstance) + const CLR_RT_TypeSpec_Instance *genericInstance, + bool allowUnresolvedVarFallback) { NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); @@ -2209,7 +2224,7 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference( CLR_RT_SignatureParser parser{}; parser.Initialize_FieldDef(assm, target); - NANOCLR_SET_AND_LEAVE(InitializeReference(ref, parser, genericInstance)); + NANOCLR_SET_AND_LEAVE(InitializeReference(ref, parser, genericInstance, allowUnresolvedVarFallback)); NANOCLR_NOCLEANUP(); } @@ -2635,7 +2650,7 @@ HRESULT CLR_RT_ExecutionEngine::NewObject( const char *fieldName = assm->GetString(target->name); #endif - NANOCLR_CHECK_HRESULT(InitializeReference(*obj, target, assm, genericInstance)); + NANOCLR_CHECK_HRESULT(InitializeReference(*obj, target, assm, genericInstance, true)); } } diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 28568c1f2a..ac43ca9fc9 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1,4 +1,4 @@ -// +// // Copyright (c) .NET Foundation and Contributors // Portions Copyright (c) Microsoft Corporation. All rights reserved. // See LICENSE file in the project root for full license information. @@ -1269,38 +1269,29 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( { if (elem.DataType == DATATYPE_GENERICINST) { + // Advance past the open generic type token. + // After this call elem.Class holds the open generic typedef (e.g. Pair<,>). + // The parser has already consumed the arg-count byte inside Advance, + // so there is no further element to skip. Return the typedef directly + // for NEWARR / STELEM / ISINST / CASTCLASS with a GENERICINST token. if (FAILED(parser.Advance(elem))) { return false; } - if (elem.DataType == DATATYPE_CLASS || elem.DataType == DATATYPE_VALUETYPE) + if ((elem.DataType == DATATYPE_CLASS || elem.DataType == DATATYPE_VALUETYPE) && + NANOCLR_INDEX_IS_VALID(elem.Class)) { - // consume the CLASS/VALUETYPE marker - if (FAILED(parser.Advance(elem))) - { - return false; - } - // consume the generic‐definition token itself - if (FAILED(parser.Advance(elem))) - { - return false; - } - // consume the count of generic arguments - if (FAILED(parser.Advance(elem))) - { - return false; - } + data = elem.Class.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[elem.Class.Assembly() - 1]; + target = assembly->GetTypeDef(elem.Class.Type()); +#if defined(NANOCLR_INSTANCE_NAMES) + name = assembly->GetString(target->name); +#endif + return true; } - // walk forward until a VAR (type‐generic) or MVAR (method‐generic) is hit - while (elem.DataType != DATATYPE_VAR && elem.DataType != DATATYPE_MVAR) - { - if (FAILED(parser.Advance(elem))) - { - return false; - } - } + return false; } genericPosition = elem.GenericParamPosition; diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index 4e65c59566..d9cf06d894 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -4222,12 +4222,14 @@ struct CLR_RT_ExecutionEngine HRESULT InitializeReference( CLR_RT_HeapBlock &ref, CLR_RT_SignatureParser &parser, - const CLR_RT_TypeSpec_Instance *genericInstance = nullptr); + const CLR_RT_TypeSpec_Instance *genericInstance = nullptr, + bool allowUnresolvedVarFallback = false); HRESULT InitializeReference( CLR_RT_HeapBlock &ref, const CLR_RECORD_FIELDDEF *target, CLR_RT_Assembly *assm, - const CLR_RT_TypeSpec_Instance *genericInstance = nullptr); + const CLR_RT_TypeSpec_Instance *genericInstance = nullptr, + bool allowUnresolvedVarFallback = false); HRESULT InitializeLocals(CLR_RT_HeapBlock *locals, const CLR_RT_MethodDef_Instance &methodDefInstance);