Skip to content

Commit 927f73d

Browse files
authored
Various fixes for generics handling (#3185)
1 parent 4fab260 commit 927f73d

File tree

1 file changed

+118
-65
lines changed

1 file changed

+118
-65
lines changed

src/CLR/Core/TypeSystem.cpp

Lines changed: 118 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,32 +1266,55 @@ bool CLR_RT_MethodDef_Instance::InitializeFromIndex(
12661266
{
12671267
NATIVE_PROFILE_CLR_CORE();
12681268

1269-
// Look up the TypeSpec's cross‐reference to find the *open* generic definition and its assembly
1270-
CLR_INDEX tsAsmIdx = typeSpec.Assembly();
1271-
if (tsAsmIdx == 0 || tsAsmIdx > (int)g_CLR_RT_TypeSystem.c_MaxAssemblies)
1269+
CLR_RT_TypeSpec_Instance tsInst;
1270+
1271+
if (!tsInst.InitializeFromIndex(typeSpec))
12721272
{
12731273
return false;
12741274
}
1275-
CLR_RT_Assembly *tsAsm = g_CLR_RT_TypeSystem.m_assemblies[tsAsmIdx - 1];
12761275

1277-
int tsRow = (int)typeSpec.TypeSpec();
1278-
const auto &xref = tsAsm->crossReferenceTypeSpec[tsRow];
1276+
// parse the signature to get to the GENERICINST and then the definition token
1277+
CLR_RT_Assembly *tsAsm = tsInst.assembly;
1278+
auto tsRec = tsAsm->GetTypeSpec(typeSpec.TypeSpec());
1279+
CLR_RT_SignatureParser parser;
1280+
parser.Initialize_TypeSpec(tsAsm, tsRec);
12791281

1280-
// xref.ownerType is the open‐generic TypeDef_Index of Span`1, List`1, etc.
1281-
CLR_RT_TypeDef_Index ownerType = xref.ownerType;
1282+
CLR_RT_SignatureParser::Element elem;
1283+
if (FAILED(parser.Advance(elem)))
1284+
{
1285+
return false;
1286+
}
12821287

1283-
// Compute the MethodDef_Index bound to the owner’s assembly
1288+
CLR_RT_TypeDef_Index ownerTypeIdx;
12841289
CLR_RT_MethodDef_Index mdRebound;
12851290

1286-
// pack the new assembly index (ownerType.Assembly()) with the original row
1287-
mdRebound.data = (ownerType.Assembly() << 24) | md.Method();
1291+
if (elem.DataType == DATATYPE_VAR)
1292+
{
1293+
CLR_RT_TypeDef_Index realOwner;
1294+
NanoCLRDataType dummyDT;
1295+
1296+
if (!tsAsm->FindGenericParamAtTypeSpec(typeSpec.TypeSpec(), elem.GenericParamPosition, realOwner, dummyDT))
1297+
{
1298+
return false;
1299+
}
1300+
1301+
ownerTypeIdx = realOwner;
1302+
}
1303+
else
1304+
{
1305+
// elem.Class.data now contains the TypeDef/TypeRef token for the generic definition
1306+
ownerTypeIdx.data = elem.Class.data;
1307+
}
1308+
1309+
// rebind the method onto the *declaring* assembly of the generic
1310+
mdRebound.data = (ownerTypeIdx.Assembly() << 24) | md.Method();
12881311

12891312
if (!InitializeFromIndex(mdRebound))
12901313
{
12911314
return false;
12921315
}
12931316

1294-
// set the generic‐type context *before* we lose it
1317+
// remember the TypeSpec so this is available when needed
12951318
this->genericType = &typeSpec;
12961319

12971320
return true;
@@ -1401,7 +1424,7 @@ bool CLR_RT_MethodDef_Instance::ResolveToken(
14011424
return false;
14021425
}
14031426

1404-
Set(assemblyIndex - 1, methodIndex.Method());
1427+
Set(assemblyIndex, methodIndex.Method());
14051428
assembly = g_CLR_RT_TypeSystem.m_assemblies[assemblyIndex - 1];
14061429
target = assembly->GetMethodDef(methodIndex.Method());
14071430
}
@@ -3278,7 +3301,7 @@ HRESULT CLR_RT_Assembly::ResolveMethodRef()
32783301
#endif
32793302
}
32803303

3281-
CLR_UINT32 dummyAssemblyIndex = 0xffff;
3304+
CLR_UINT32 dummyAssemblyIndex = 0xffffffff;
32823305

32833306
if (typeSpecInstance.assembly->FindMethodDef(
32843307
typeSpecInstance.target,
@@ -4770,6 +4793,7 @@ bool CLR_RT_Assembly::FindGenericParamAtTypeSpec(
47704793
// element.Class was filled from the VAR position
47714794
typeDef = element.Class;
47724795
dataType = element.DataType;
4796+
47734797
return true;
47744798
}
47754799

@@ -5002,15 +5026,24 @@ bool CLR_RT_Assembly::FindMethodDef(
50025026

50035027
// switch to the assembly that declared this TypeSpec
50045028
CLR_RT_Assembly *declAssm = tsInstance.assembly;
5005-
const CLR_RECORD_TYPEDEF *td =
5006-
(const CLR_RECORD_TYPEDEF *)declAssm->GetTable(TBL_TypeDef) + tsInstance.typeDefIndex;
50075029

5008-
if (declAssm->FindMethodDef(td, methodName, base, sig, index))
5030+
CLR_INDEX typeDefIdx = tsInstance.typeDefIndex;
5031+
5032+
// validate that it really is in-range
5033+
if (typeDefIdx >= declAssm->tablesSize[TBL_TypeDef])
5034+
{
5035+
// doesn't seem to be, jump to TypeSpec parsing
5036+
goto try_typespec;
5037+
}
5038+
5039+
if (declAssm->FindMethodDef(declAssm->GetTypeDef(typeDefIdx), methodName, base, sig, index))
50095040
{
50105041
assmIndex = declAssm->assemblyIndex;
50115042
return true;
50125043
}
50135044

5045+
try_typespec:
5046+
50145047
// parse the TypeSpec signature to get the *definition* token of the generic type:
50155048
CLR_RT_SignatureParser parser{};
50165049
parser.Initialize_TypeSpec(this, ts);
@@ -6233,18 +6266,41 @@ HRESULT CLR_RT_TypeSystem::BuildTypeName(const CLR_RT_TypeSpec_Index &typeIndex,
62336266

62346267
for (int i = 0; i < parser.GenParamCount; i++)
62356268
{
6269+
// read the next element (should be either VAR, MVAR, or a concrete type)
62366270
parser.Advance(element);
62376271

6238-
#if defined(VIRTUAL_DEVICE)
6239-
NANOCLR_CHECK_HRESULT(QueueStringToBuffer(szBuffer, iBuffer, c_CLR_RT_DataTypeLookup[element.DataType].m_name));
6240-
#endif
6272+
if (element.DataType == DATATYPE_VAR)
6273+
{
6274+
// resolve the !T against our *closed* typeIndex
6275+
CLR_RT_TypeDef_Index realTd;
6276+
NanoCLRDataType realDt;
6277+
6278+
// this will bind !T→System.Int32, etc.
6279+
instance.assembly->FindGenericParamAtTypeSpec(
6280+
typeIndex.TypeSpec(), // closed instantiation row
6281+
element.GenericParamPosition, // the !N slot
6282+
realTd,
6283+
realDt);
6284+
6285+
// now print the *actual* type name
6286+
BuildTypeName(realTd, szBuffer, iBuffer);
6287+
}
6288+
else
6289+
{
6290+
// concrete type (e.g. a nested generic, a value type, another class...)
6291+
CLR_RT_TypeDef_Index td;
6292+
td.data = element.Class.data;
6293+
6294+
BuildTypeName(td, szBuffer, iBuffer);
6295+
}
6296+
62416297
if (i + 1 < parser.GenParamCount)
62426298
{
62436299
NANOCLR_CHECK_HRESULT(QueueStringToBuffer(szBuffer, iBuffer, ","));
62446300
}
62456301
}
62466302

6247-
CLR_SafeSprintf(szBuffer, iBuffer, ">");
6303+
NANOCLR_CHECK_HRESULT(QueueStringToBuffer(szBuffer, iBuffer, ">"));
62486304

62496305
NANOCLR_NOCLEANUP();
62506306
}
@@ -6320,69 +6376,66 @@ HRESULT CLR_RT_TypeSystem::BuildMethodName(
63206376
NATIVE_PROFILE_CLR_CORE();
63216377
NANOCLR_HEADER();
63226378

6379+
CLR_RT_TypeDef_Instance declTypeInst{};
6380+
CLR_RT_MethodDef_Instance tempMD{};
63236381
CLR_RT_MethodDef_Instance inst{};
6382+
CLR_RT_TypeDef_Index declTypeIdx;
6383+
CLR_RT_TypeDef_Instance instOwner{};
6384+
bool useGeneric = false;
63246385

6325-
if (genericType == nullptr)
6386+
// find out which type declares this method
6387+
if (!tempMD.InitializeFromIndex(md))
63266388
{
6327-
if (inst.InitializeFromIndex(md) == false)
6328-
{
6329-
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
6330-
}
6331-
6332-
CLR_RT_TypeDef_Instance instOwner{};
6333-
if (instOwner.InitializeFromMethod(inst) == false)
6334-
{
6335-
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
6336-
}
6337-
6338-
NANOCLR_CHECK_HRESULT(BuildTypeName(instOwner, szBuffer, iBuffer));
6339-
6340-
CLR_SafeSprintf(szBuffer, iBuffer, "::%s", inst.assembly->GetString(inst.target->name));
6389+
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
63416390
}
6342-
else
6343-
{
6344-
CLR_INDEX tsAsmIdx = genericType->Assembly();
6345-
CLR_RT_Assembly *genericTypeAssembly = g_CLR_RT_TypeSystem.m_assemblies[tsAsmIdx - 1];
63466391

6347-
CLR_RT_SignatureParser parser;
6348-
parser.Initialize_TypeSpec(genericTypeAssembly, genericTypeAssembly->GetTypeSpec(genericType->TypeSpec()));
6349-
6350-
CLR_RT_SignatureParser::Element element;
6351-
6352-
// get type
6353-
parser.Advance(element);
6354-
6355-
CLR_RT_TypeDef_Index typeDef;
6356-
typeDef.data = element.Class.data;
6392+
if (!declTypeInst.InitializeFromMethod(tempMD))
6393+
{
6394+
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
6395+
}
63576396

6358-
BuildTypeName(typeDef, szBuffer, iBuffer);
6397+
declTypeIdx.Set(md.Assembly(), declTypeInst.assembly->crossReferenceMethodDef[md.Method()].GetOwner());
63596398

6360-
NANOCLR_CHECK_HRESULT(QueueStringToBuffer(szBuffer, iBuffer, "<"));
6399+
if (genericType != nullptr && genericType->data != 0xffffffff)
6400+
{
6401+
// parse TypeSpec to get its TypeDef
6402+
CLR_RT_TypeSpec_Instance tsInst = {};
63616403

6362-
for (int i = 0; i < parser.GenParamCount; i++)
6404+
if (tsInst.InitializeFromIndex(*genericType))
63636405
{
6364-
parser.Advance(element);
6365-
6366-
#if defined(VIRTUAL_DEVICE)
6367-
NANOCLR_CHECK_HRESULT(
6368-
QueueStringToBuffer(szBuffer, iBuffer, c_CLR_RT_DataTypeLookup[element.DataType].m_name));
6369-
#endif
6370-
if (i + 1 < parser.GenParamCount)
6406+
if (tsInst.typeDefIndex == declTypeIdx.Type())
63716407
{
6372-
NANOCLR_CHECK_HRESULT(QueueStringToBuffer(szBuffer, iBuffer, ","));
6408+
useGeneric = true;
63736409
}
63746410
}
6411+
}
63756412

6376-
if (inst.InitializeFromIndex(md, *genericType) == false)
6413+
if (!useGeneric)
6414+
{
6415+
// fallback: non generic method or a different type
6416+
if (!inst.InitializeFromIndex(md))
6417+
{
6418+
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
6419+
}
6420+
}
6421+
else
6422+
{
6423+
// method belong to a closed generic type, so bind it to the appropriate TypeSpec
6424+
if (!inst.InitializeFromIndex(md, *genericType))
63776425
{
6378-
// this is a MethodDef for a generic type, but the generic type is not bound to an assembly
6379-
// so we cannot build the name of the method.
63806426
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
63816427
}
6428+
}
63826429

6383-
CLR_SafeSprintf(szBuffer, iBuffer, ">::%s", genericTypeAssembly->GetString(inst.target->name));
6430+
if (instOwner.InitializeFromMethod(inst) == false)
6431+
{
6432+
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
63846433
}
63856434

6435+
NANOCLR_CHECK_HRESULT(BuildTypeName(instOwner, szBuffer, iBuffer));
6436+
6437+
CLR_SafeSprintf(szBuffer, iBuffer, "::%s", inst.assembly->GetString(inst.target->name));
6438+
63866439
NANOCLR_NOCLEANUP();
63876440
}
63886441

0 commit comments

Comments
 (0)