@@ -100,8 +100,8 @@ public nanoTypeSpecificationsTable(
100100
101101 _idByTypeSpecifications = new Dictionary < TypeReference , ushort > ( new TypeReferenceEqualityComparer ( context ) ) ;
102102
103+ AddTypeLevelGenericParameters ( ) ;
103104 FillTypeSpecsFromTypes ( ) ;
104-
105105 FillTypeSpecsFromMemberReferences ( ) ;
106106 }
107107
@@ -124,14 +124,52 @@ public bool TryGetTypeReferenceId(
124124
125125 return false ;
126126 }
127-
128127 public TypeReference TryGetTypeSpecification ( MetadataToken token )
129128 {
130- return _idByTypeSpecifications . FirstOrDefault ( typeEntry => typeEntry . Key . MetadataToken == token ) . Key ;
129+ // try a direct match on the TypeReference itself
130+ TypeReference direct = _idByTypeSpecifications . Keys . FirstOrDefault ( t => t . MetadataToken == token ) ;
131+
132+ if ( direct != null )
133+ {
134+ return direct ;
135+ }
136+
137+ // Look among the generic-instances already seeded
138+ GenericInstanceType genericInst = _idByTypeSpecifications . Keys
139+ . OfType < GenericInstanceType > ( )
140+ . FirstOrDefault ( git => git . ElementType . MetadataToken == token ) ;
141+
142+ if ( genericInst != null )
143+ {
144+ return genericInst ;
145+ }
146+
147+ // maybe this instanced type is in TypeReferencesTable
148+ GenericInstanceType external = _context . TypeReferencesTable . Items
149+ . OfType < GenericInstanceType > ( )
150+ . FirstOrDefault ( git => git . ElementType . MetadataToken == token ) ;
151+
152+ if ( external != null )
153+ {
154+ // seed it now so future lookups find it immediately
155+ ushort sigId = _context . SignaturesTable . GetOrCreateSignatureId ( external ) ;
156+
157+ AddIfNew ( external , sigId ) ;
158+
159+ // and pull in its nested specs (generic arguments, element types, etc.)
160+ ExpandNestedTypeSpecs ( external ) ;
161+
162+ return external ;
163+ }
164+
165+ // some edge case not being handled...
166+ // default to null
167+ return null ;
131168 }
132169
170+
133171 /// <summary>
134- /// Tries to find type reference by the index on the TypeSpec list.
172+ /// Tries to find type reference by the index on the <see cref=" TypeSpec"/> list.
135173 /// </summary>
136174 /// <param name="index">Index of the type reference in the list.</param>
137175 /// <returns>Returns the type reference if found, otherwise returns <c>null</c>.</returns>
@@ -197,44 +235,162 @@ private void FillTypeSpecsFromMemberReferences()
197235 }
198236 }
199237 }
238+
239+ // make sure we pick up *all* GenericInstanceType entries
240+ // that may have come in via the TypeReferencesTable.
241+ foreach ( GenericInstanceType genericInstanceType in _context . TypeReferencesTable . Items . OfType < GenericInstanceType > ( ) )
242+ {
243+ if ( ! _idByTypeSpecifications . ContainsKey ( genericInstanceType ) )
244+ {
245+ // create or get the signature ID for this instanced type
246+ ushort sigId = _context . SignaturesTable . GetOrCreateSignatureId ( genericInstanceType ) ;
247+ _idByTypeSpecifications . Add ( genericInstanceType , sigId ) ;
248+
249+ // (and don’t forget to pull in any nested generic-parameter args)
250+ foreach ( GenericParameter arg in genericInstanceType . GenericArguments . OfType < GenericParameter > ( ) )
251+ {
252+ if ( ! _idByTypeSpecifications . ContainsKey ( arg ) )
253+ {
254+ ushort argSig = _context . SignaturesTable . GetOrCreateSignatureId ( arg ) ;
255+ _idByTypeSpecifications . Add ( arg , argSig ) ;
256+ }
257+ }
258+ }
259+ }
200260 }
201261
202262 private void FillTypeSpecsFromTypes ( )
203263 {
204- foreach ( TypeDefinition t in _context . TypeDefinitionTable . Items )
264+ foreach ( TypeDefinition td in _context . TypeDefinitionTable . Items )
205265 {
206- foreach ( MethodDefinition m in t . Methods . Where ( method => method . HasBody ) )
266+ foreach ( MethodDefinition m in td . Methods . Where ( m => m . HasBody ) )
207267 {
208- foreach ( Instruction instruction in m . Body . Instructions )
268+ foreach ( Instruction instr in m . Body . Instructions )
209269 {
210- if ( instruction . Operand is GenericParameter genericParameter )
270+ if ( instr . Operand is GenericParameter gp )
211271 {
212- ushort signatureId = _context . SignaturesTable . GetOrCreateSignatureId ( genericParameter ) ;
213-
214- if ( ! _idByTypeSpecifications . ContainsKey ( genericParameter ) )
215- {
216- _idByTypeSpecifications . Add ( genericParameter , signatureId ) ;
217- }
272+ AddIfNew ( gp , _context . SignaturesTable . GetOrCreateSignatureId ( gp ) ) ;
218273 }
219- else if ( instruction . Operand is TypeReference typeReference )
274+ else if ( instr . Operand is TypeReference tr )
220275 {
221- // Optional: Check additional conditions if needed,
222- // for example, if the operand type should be an array.
223- if ( instruction . OpCode . OperandType == OperandType . InlineType && ! typeReference . IsArray )
276+ // refuse multi-dimensional arrays
277+ // we only support jagged arrays
278+ if ( tr . IsArray )
224279 {
225- continue ;
280+ var at = ( ArrayType ) tr ;
281+
282+ if ( at . Rank > 1 )
283+ {
284+ throw new ArgumentException (
285+ $ ".NET nanoFramework only supports jagged arrays: { tr . FullName } ") ;
286+ }
226287 }
227288
228- ushort signatureId = _context . SignaturesTable . GetOrCreateSignatureId ( typeReference ) ;
289+ // register the type reference itself...
290+ ushort sigId = _context . SignaturesTable . GetOrCreateSignatureId ( tr ) ;
291+ AddIfNew ( tr , sigId ) ;
229292
230- if ( ! _idByTypeSpecifications . ContainsKey ( typeReference ) )
231- {
232- _idByTypeSpecifications . Add ( typeReference , signatureId ) ;
233- }
293+ // ... then walk *into* any nested TypeSpecifications it might contain
294+ ExpandNestedTypeSpecs ( tr ) ;
234295 }
235296 }
236297 }
237298 }
238299 }
300+
301+ /// <summary>
302+ /// Recursively finds any TypeSpecification bits of 't' and adds them
303+ /// (element types, generic arguments, declaring types, by/ref, pointers, etc.)
304+ /// </summary>
305+ private void ExpandNestedTypeSpecs ( TypeReference t )
306+ {
307+ if ( ! ( t is TypeSpecification ts ) )
308+ {
309+ return ;
310+ }
311+
312+ // element type of pointers, by-refs, modifiers, arrays, & generic definitions
313+ TypeReference inner = null ;
314+ switch ( ts )
315+ {
316+ case GenericInstanceType git :
317+ inner = git . ElementType ;
318+ foreach ( var arg in git . GenericArguments )
319+ ExpandNestedTypeSpecs ( arg ) ;
320+ break ;
321+
322+ case ArrayType at :
323+ inner = at . ElementType ;
324+ break ;
325+
326+ case ByReferenceType br :
327+ inner = br . ElementType ;
328+ break ;
329+
330+ case PointerType pt :
331+ inner = pt . ElementType ;
332+ break ;
333+
334+ case OptionalModifierType om :
335+ inner = om . ElementType ;
336+ break ;
337+
338+ case RequiredModifierType rm :
339+ inner = rm . ElementType ;
340+ break ;
341+ }
342+
343+ if ( inner != null )
344+ {
345+ ushort innerId = _context . SignaturesTable . GetOrCreateSignatureId ( inner ) ;
346+ AddIfNew ( inner , innerId ) ;
347+ ExpandNestedTypeSpecs ( inner ) ;
348+ }
349+
350+ // nested/declaring types
351+ if ( ts . DeclaringType != null )
352+ {
353+ TypeReference decl = ts . DeclaringType ;
354+ ushort declId = _context . SignaturesTable . GetOrCreateSignatureId ( decl ) ;
355+ AddIfNew ( decl , declId ) ;
356+ ExpandNestedTypeSpecs ( decl ) ;
357+ }
358+ }
359+
360+ /// <summary>
361+ /// Helper to add to `_idByTypeSpecifications` only if we haven’t already seen it
362+ /// </summary>
363+ private void AddIfNew (
364+ TypeReference tr ,
365+ ushort sigId )
366+ {
367+ if ( ! _idByTypeSpecifications . ContainsKey ( tr ) )
368+ {
369+ _idByTypeSpecifications . Add ( tr , sigId ) ;
370+ }
371+ }
372+
373+ private void AddTypeLevelGenericParameters ( )
374+ {
375+ foreach ( TypeDefinition td in _context . TypeDefinitionTable . Items . Where ( t => t . HasGenericParameters ) )
376+ {
377+ // register each generic parameter (T)
378+ foreach ( GenericParameter gp in td . GenericParameters )
379+ {
380+ ushort gpSig = _context . SignaturesTable . GetOrCreateSignatureId ( gp ) ;
381+ AddIfNew ( gp , gpSig ) ;
382+ }
383+
384+ // seed the *open* GenericInstanceType (e.g. Action`1<T>)
385+ var openGeneric = new GenericInstanceType ( td ) ;
386+ foreach ( GenericParameter gp in td . GenericParameters )
387+ {
388+ openGeneric . GenericArguments . Add ( gp ) ;
389+ }
390+
391+ ushort openSig = _context . SignaturesTable . GetOrCreateSignatureId ( openGeneric ) ;
392+ AddIfNew ( openGeneric , openSig ) ;
393+ }
394+ }
239395 }
240396}
0 commit comments