2 Copyright (C) 2009-2010 Jeroen Frijters
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
25 using System.Collections.Generic;
26 using System.Diagnostics;
29 using CallingConvention = System.Runtime.InteropServices.CallingConvention;
30 using IKVM.Reflection.Reader;
31 using IKVM.Reflection.Emit;
32 using IKVM.Reflection.Writer;
33 using IKVM.Reflection.Metadata;
35 namespace IKVM.Reflection
37 abstract class Signature
39 internal const byte DEFAULT = 0x00;
40 internal const byte VARARG = 0x05;
41 internal const byte GENERIC = 0x10;
42 internal const byte HASTHIS = 0x20;
43 internal const byte EXPLICITTHIS = 0x40;
44 internal const byte FIELD = 0x06;
45 internal const byte LOCAL_SIG = 0x07;
46 internal const byte PROPERTY = 0x08;
47 internal const byte GENERICINST = 0x0A;
48 internal const byte SENTINEL = 0x41;
49 internal const byte ELEMENT_TYPE_VOID = 0x01;
50 internal const byte ELEMENT_TYPE_BOOLEAN = 0x02;
51 internal const byte ELEMENT_TYPE_CHAR = 0x03;
52 internal const byte ELEMENT_TYPE_I1 = 0x04;
53 internal const byte ELEMENT_TYPE_U1 = 0x05;
54 internal const byte ELEMENT_TYPE_I2 = 0x06;
55 internal const byte ELEMENT_TYPE_U2 = 0x07;
56 internal const byte ELEMENT_TYPE_I4 = 0x08;
57 internal const byte ELEMENT_TYPE_U4 = 0x09;
58 internal const byte ELEMENT_TYPE_I8 = 0x0a;
59 internal const byte ELEMENT_TYPE_U8 = 0x0b;
60 internal const byte ELEMENT_TYPE_R4 = 0x0c;
61 internal const byte ELEMENT_TYPE_R8 = 0x0d;
62 internal const byte ELEMENT_TYPE_STRING = 0x0e;
63 internal const byte ELEMENT_TYPE_PTR = 0x0f;
64 internal const byte ELEMENT_TYPE_BYREF = 0x10;
65 internal const byte ELEMENT_TYPE_VALUETYPE = 0x11;
66 internal const byte ELEMENT_TYPE_CLASS = 0x12;
67 internal const byte ELEMENT_TYPE_VAR = 0x13;
68 internal const byte ELEMENT_TYPE_ARRAY = 0x14;
69 internal const byte ELEMENT_TYPE_GENERICINST = 0x15;
70 internal const byte ELEMENT_TYPE_TYPEDBYREF = 0x16;
71 internal const byte ELEMENT_TYPE_I = 0x18;
72 internal const byte ELEMENT_TYPE_U = 0x19;
73 internal const byte ELEMENT_TYPE_FNPTR = 0x1b;
74 internal const byte ELEMENT_TYPE_OBJECT = 0x1c;
75 internal const byte ELEMENT_TYPE_SZARRAY = 0x1d;
76 internal const byte ELEMENT_TYPE_MVAR = 0x1e;
77 internal const byte ELEMENT_TYPE_CMOD_REQD = 0x1f;
78 internal const byte ELEMENT_TYPE_CMOD_OPT = 0x20;
79 internal const byte ELEMENT_TYPE_PINNED = 0x45;
81 internal abstract void WriteSig(ModuleBuilder module, ByteBuffer bb);
83 private static Type ReadGenericInst(ModuleReader module, ByteReader br, IGenericContext context)
85 switch (br.ReadByte())
87 case ELEMENT_TYPE_CLASS:
88 case ELEMENT_TYPE_VALUETYPE:
91 throw new BadImageFormatException();
93 Type type = ReadTypeDefOrRefEncoded(module, br, context);
94 if (!type.IsGenericTypeDefinition)
96 throw new BadImageFormatException();
98 int genArgCount = br.ReadCompressedInt();
99 Type[] args = new Type[genArgCount];
100 Type[][] reqmod = null;
101 Type[][] optmod = null;
102 for (int i = 0; i < genArgCount; i++)
104 // LAMESPEC the Type production (23.2.12) doesn't include CustomMod* for genericinst, but C++ uses it, the verifier allows it and ildasm also supports it
105 CustomModifiers mods = ReadCustomModifiers(module, br, context);
106 if (mods.required != null || mods.optional != null)
110 reqmod = new Type[genArgCount][];
111 optmod = new Type[genArgCount][];
113 reqmod[i] = mods.required;
114 optmod[i] = mods.optional;
116 args[i] = ReadType(module, br, context);
118 return GenericTypeInstance.Make(type, args, reqmod, optmod);
121 internal static Type ReadTypeSpec(ModuleReader module, ByteReader br, IGenericContext context)
123 // LAMESPEC a TypeSpec can contain custom modifiers (C++/CLI generates "newarr (TypeSpec with custom modifiers)")
124 SkipCustomModifiers(br);
125 // LAMESPEC anything can be adorned by (useless) custom modifiers
126 // also, VAR and MVAR are also used in TypeSpec (contrary to what the spec says)
127 return ReadType(module, br, context);
130 private static Type ReadFunctionPointer(ModuleReader module, ByteReader br, IGenericContext context)
132 // TODO like .NET we return System.IntPtr here, but ideally we should fire an event in Universe that
133 // the user can hook to provide a custom type (or we simply should build in full support for function pointer types)
134 MethodSignature.ReadStandAloneMethodSig(module, br, context);
135 return module.universe.System_IntPtr;
138 internal static Type[] ReadMethodSpec(ModuleReader module, ByteReader br, IGenericContext context)
140 if (br.ReadByte() != GENERICINST)
142 throw new BadImageFormatException();
144 Type[] args = new Type[br.ReadCompressedInt()];
145 for (int i = 0; i < args.Length; i++)
147 args[i] = ReadType(module, br, context);
152 private static int ReadArrayShape(ByteReader br)
154 int rank = br.ReadCompressedInt();
155 int numSizes = br.ReadCompressedInt();
156 for (int i = 0; i < numSizes; i++)
158 br.ReadCompressedInt();
160 int numLoBounds = br.ReadCompressedInt();
161 for (int i = 0; i < numLoBounds; i++)
163 br.ReadCompressedInt();
168 private static Type ReadTypeOrVoid(ModuleReader module, ByteReader br, IGenericContext context)
170 if (br.PeekByte() == ELEMENT_TYPE_VOID)
173 return module.universe.System_Void;
177 return ReadType(module, br, context);
181 // see ECMA 335 CLI spec June 2006 section 23.2.12 for this production
182 protected static Type ReadType(ModuleReader module, ByteReader br, IGenericContext context)
184 CustomModifiers mods;
185 switch (br.ReadByte())
187 case ELEMENT_TYPE_CLASS:
188 case ELEMENT_TYPE_VALUETYPE:
189 return ReadTypeDefOrRefEncoded(module, br, context);
190 case ELEMENT_TYPE_BOOLEAN:
191 return module.universe.System_Boolean;
192 case ELEMENT_TYPE_CHAR:
193 return module.universe.System_Char;
194 case ELEMENT_TYPE_I1:
195 return module.universe.System_SByte;
196 case ELEMENT_TYPE_U1:
197 return module.universe.System_Byte;
198 case ELEMENT_TYPE_I2:
199 return module.universe.System_Int16;
200 case ELEMENT_TYPE_U2:
201 return module.universe.System_UInt16;
202 case ELEMENT_TYPE_I4:
203 return module.universe.System_Int32;
204 case ELEMENT_TYPE_U4:
205 return module.universe.System_UInt32;
206 case ELEMENT_TYPE_I8:
207 return module.universe.System_Int64;
208 case ELEMENT_TYPE_U8:
209 return module.universe.System_UInt64;
210 case ELEMENT_TYPE_R4:
211 return module.universe.System_Single;
212 case ELEMENT_TYPE_R8:
213 return module.universe.System_Double;
215 return module.universe.System_IntPtr;
217 return module.universe.System_UIntPtr;
218 case ELEMENT_TYPE_STRING:
219 return module.universe.System_String;
220 case ELEMENT_TYPE_OBJECT:
221 return module.universe.System_Object;
222 case ELEMENT_TYPE_VAR:
223 return context.GetGenericTypeArgument(br.ReadCompressedInt());
224 case ELEMENT_TYPE_MVAR:
225 return context.GetGenericMethodArgument(br.ReadCompressedInt());
226 case ELEMENT_TYPE_GENERICINST:
227 return ReadGenericInst(module, br, context);
228 case ELEMENT_TYPE_SZARRAY:
229 mods = ReadCustomModifiers(module, br, context);
230 return ReadType(module, br, context).__MakeArrayType(mods.required, mods.optional);
231 case ELEMENT_TYPE_ARRAY:
232 mods = ReadCustomModifiers(module, br, context);
233 return ReadType(module, br, context).__MakeArrayType(ReadArrayShape(br), mods.required, mods.optional);
234 case ELEMENT_TYPE_PTR:
235 mods = ReadCustomModifiers(module, br, context);
236 return ReadTypeOrVoid(module, br, context).__MakePointerType(mods.required, mods.optional);
237 case ELEMENT_TYPE_FNPTR:
238 return ReadFunctionPointer(module, br, context);
240 throw new BadImageFormatException();
244 internal static void ReadLocalVarSig(ModuleReader module, ByteReader br, IGenericContext context, List<LocalVariableInfo> list)
246 if (br.Length < 2 || br.ReadByte() != LOCAL_SIG)
248 throw new BadImageFormatException("Invalid local variable signature");
250 int count = br.ReadCompressedInt();
251 for (int i = 0; i < count; i++)
253 if (br.PeekByte() == ELEMENT_TYPE_TYPEDBYREF)
256 list.Add(new LocalVariableInfo(i, module.universe.System_TypedReference, false));
260 SkipCustomModifiers(br);
262 if (br.PeekByte() == ELEMENT_TYPE_PINNED)
267 SkipCustomModifiers(br);
268 Type type = ReadTypeOrByRef(module, br, context);
269 list.Add(new LocalVariableInfo(i, type, pinned));
274 private static Type ReadTypeOrByRef(ModuleReader module, ByteReader br, IGenericContext context)
276 if (br.PeekByte() == ELEMENT_TYPE_BYREF)
279 // LAMESPEC it is allowed (by C++/CLI, ilasm and peverify) to have custom modifiers after the BYREF
280 // (which makes sense, as it is analogous to pointers)
281 CustomModifiers mods = ReadCustomModifiers(module, br, context);
282 // C++/CLI generates void& local variables, so we need to use ReadTypeOrVoid here
283 return ReadTypeOrVoid(module, br, context).__MakeByRefType(mods.required, mods.optional);
287 return ReadType(module, br, context);
291 protected static Type ReadRetType(ModuleReader module, ByteReader br, IGenericContext context)
293 switch (br.PeekByte())
295 case ELEMENT_TYPE_VOID:
297 return module.universe.System_Void;
298 case ELEMENT_TYPE_TYPEDBYREF:
300 return module.universe.System_TypedReference;
302 return ReadTypeOrByRef(module, br, context);
306 protected static Type ReadParam(ModuleReader module, ByteReader br, IGenericContext context)
308 switch (br.PeekByte())
310 case ELEMENT_TYPE_TYPEDBYREF:
312 return module.universe.System_TypedReference;
314 return ReadTypeOrByRef(module, br, context);
318 protected static void WriteType(ModuleBuilder module, ByteBuffer bb, Type type)
320 while (type.HasElementType)
324 bb.Write(ELEMENT_TYPE_SZARRAY);
326 else if (type.IsArray)
328 int rank = type.GetArrayRank();
329 bb.Write(ELEMENT_TYPE_ARRAY);
330 // LAMESPEC the Type production (23.2.12) doesn't include CustomMod* for arrays, but the verifier allows it and ildasm also supports it
331 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, type.__GetRequiredCustomModifiers());
332 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, type.__GetOptionalCustomModifiers());
333 WriteType(module, bb, type.GetElementType());
334 bb.WriteCompressedInt(rank);
335 // since a Type doesn't contain the lower/upper bounds
336 // (they act like a custom modifier, so they are part of the signature, but not of the Type),
337 // we set them to the C# compatible values and hope for the best
338 bb.WriteCompressedInt(0); // boundsCount
339 bb.WriteCompressedInt(rank); // loCount
340 for (int i = 0; i < rank; i++)
342 bb.WriteCompressedInt(0);
346 else if (type.IsByRef)
348 bb.Write(ELEMENT_TYPE_BYREF);
350 else if (type.IsPointer)
352 bb.Write(ELEMENT_TYPE_PTR);
354 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, type.__GetRequiredCustomModifiers());
355 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, type.__GetOptionalCustomModifiers());
356 type = type.GetElementType();
358 Universe u = module.universe;
359 if (type == u.System_Void)
361 bb.Write(ELEMENT_TYPE_VOID);
363 else if (type == u.System_Boolean)
365 bb.Write(ELEMENT_TYPE_BOOLEAN);
367 else if (type == u.System_Char)
369 bb.Write(ELEMENT_TYPE_CHAR);
371 else if (type == u.System_SByte)
373 bb.Write(ELEMENT_TYPE_I1);
375 else if (type == u.System_Byte)
377 bb.Write(ELEMENT_TYPE_U1);
379 else if (type == u.System_Int16)
381 bb.Write(ELEMENT_TYPE_I2);
383 else if (type == u.System_UInt16)
385 bb.Write(ELEMENT_TYPE_U2);
387 else if (type == u.System_Int32)
389 bb.Write(ELEMENT_TYPE_I4);
391 else if (type == u.System_UInt32)
393 bb.Write(ELEMENT_TYPE_U4);
395 else if (type == u.System_Int64)
397 bb.Write(ELEMENT_TYPE_I8);
399 else if (type == u.System_UInt64)
401 bb.Write(ELEMENT_TYPE_U8);
403 else if (type == u.System_Single)
405 bb.Write(ELEMENT_TYPE_R4);
407 else if (type == u.System_Double)
409 bb.Write(ELEMENT_TYPE_R8);
411 else if (type == u.System_String)
413 bb.Write(ELEMENT_TYPE_STRING);
415 else if (type == u.System_IntPtr)
417 bb.Write(ELEMENT_TYPE_I);
419 else if (type == u.System_UIntPtr)
421 bb.Write(ELEMENT_TYPE_U);
423 else if (type == u.System_TypedReference)
425 bb.Write(ELEMENT_TYPE_TYPEDBYREF);
427 else if (type == u.System_Object)
429 bb.Write(ELEMENT_TYPE_OBJECT);
431 else if (type.IsGenericParameter)
433 if (type is UnboundGenericMethodParameter || type.DeclaringMethod != null)
435 bb.Write(ELEMENT_TYPE_MVAR);
439 bb.Write(ELEMENT_TYPE_VAR);
441 bb.WriteCompressedInt(type.GenericParameterPosition);
443 else if (type.IsGenericType)
445 WriteGenericSignature(module, bb, type);
449 if (type.IsValueType)
451 bb.Write(ELEMENT_TYPE_VALUETYPE);
455 bb.Write(ELEMENT_TYPE_CLASS);
457 bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
461 private static void WriteGenericSignature(ModuleBuilder module, ByteBuffer bb, Type type)
463 Type[] typeArguments = type.GetGenericArguments();
464 Type[][] requiredCustomModifiers = type.__GetGenericArgumentsRequiredCustomModifiers();
465 Type[][] optionalCustomModifiers = type.__GetGenericArgumentsOptionalCustomModifiers();
466 if (!type.IsGenericTypeDefinition)
468 type = type.GetGenericTypeDefinition();
470 bb.Write(ELEMENT_TYPE_GENERICINST);
471 if (type.IsValueType)
473 bb.Write(ELEMENT_TYPE_VALUETYPE);
477 bb.Write(ELEMENT_TYPE_CLASS);
479 bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
480 bb.WriteCompressedInt(typeArguments.Length);
481 for (int i = 0; i < typeArguments.Length; i++)
483 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, requiredCustomModifiers[i]);
484 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, optionalCustomModifiers[i]);
485 WriteType(module, bb, typeArguments[i]);
489 protected static void WriteCustomModifiers(ModuleBuilder module, ByteBuffer bb, byte mod, Type[] modifiers)
491 if (modifiers != null)
493 foreach (Type type in modifiers)
496 bb.WriteTypeDefOrRefEncoded(module.GetTypeTokenForMemberRef(type));
501 protected static bool IsCustomModifier(byte b)
503 return b == ELEMENT_TYPE_CMOD_OPT || b == ELEMENT_TYPE_CMOD_REQD;
506 struct CustomModifiers
508 internal Type[] required;
509 internal Type[] optional;
512 private static CustomModifiers ReadCustomModifiers(ModuleReader module, ByteReader br, IGenericContext context)
514 CustomModifiers mods = new CustomModifiers();
515 byte b = br.PeekByte();
516 if (IsCustomModifier(b))
518 List<Type> required = new List<Type>();
519 List<Type> optional = new List<Type>();
520 while (IsCustomModifier(b))
522 bool req = br.ReadByte() == ELEMENT_TYPE_CMOD_REQD;
523 Type type = ReadTypeDefOrRefEncoded(module, br, context);
524 (req ? required : optional).Add(type);
527 mods.required = required.ToArray();
528 mods.optional = optional.ToArray();
533 protected static void SkipCustomModifiers(ByteReader br)
535 byte b = br.PeekByte();
536 while (IsCustomModifier(b))
539 br.ReadCompressedInt();
544 private static Type ReadTypeDefOrRefEncoded(ModuleReader module, ByteReader br, IGenericContext context)
546 int encoded = br.ReadCompressedInt();
550 return module.ResolveType((TypeDefTable.Index << 24) + (encoded >> 2), null, null);
552 return module.ResolveType((TypeRefTable.Index << 24) + (encoded >> 2), null, null);
554 return module.ResolveType((TypeSpecTable.Index << 24) + (encoded >> 2), context);
556 throw new BadImageFormatException();
560 protected static void ReadCustomModifiers(ModuleReader module, ByteReader br, IGenericContext context, out Type[] requiredCustomModifiers, out Type[] optionalCustomModifiers)
562 byte b = br.PeekByte();
563 if (IsCustomModifier(b))
565 List<Type> required = new List<Type>();
566 List<Type> optional = new List<Type>();
567 while (IsCustomModifier(b))
570 Type type = ReadTypeDefOrRefEncoded(module, br, context);
571 if (b == ELEMENT_TYPE_CMOD_REQD)
581 requiredCustomModifiers = required.ToArray();
582 optionalCustomModifiers = optional.ToArray();
586 requiredCustomModifiers = null;
587 optionalCustomModifiers = null;
591 // unmanaged calling convention
592 internal static void WriteStandAloneMethodSig(ModuleBuilder module, ByteBuffer bb, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
594 switch (callingConvention)
596 case CallingConvention.Cdecl:
597 bb.Write((byte)0x01); // C
599 case CallingConvention.StdCall:
600 case CallingConvention.Winapi:
601 bb.Write((byte)0x02); // STDCALL
603 case CallingConvention.ThisCall:
604 bb.Write((byte)0x03); // THISCALL
606 case CallingConvention.FastCall:
607 bb.Write((byte)0x04); // FASTCALL
610 throw new ArgumentOutOfRangeException("callingConvention");
612 bb.WriteCompressedInt(parameterTypes.Length);
613 WriteType(module, bb, returnType);
614 foreach (Type t in parameterTypes)
616 WriteType(module, bb, t);
620 // managed calling convention
621 internal static void WriteStandAloneMethodSig(ModuleBuilder module, ByteBuffer bb, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
624 if ((callingConvention & CallingConventions.HasThis) != 0)
628 if ((callingConvention & CallingConventions.ExplicitThis) != 0)
630 flags |= EXPLICITTHIS;
632 if ((callingConvention & CallingConventions.VarArgs) != 0)
637 bb.WriteCompressedInt(parameterTypes.Length + optionalParameterTypes.Length);
638 WriteType(module, bb, returnType);
639 foreach (Type t in parameterTypes)
641 WriteType(module, bb, t);
643 if (optionalParameterTypes.Length > 0)
646 foreach (Type t in optionalParameterTypes)
648 WriteType(module, bb, t);
653 internal static void WriteLocalVarSig(ModuleBuilder module, ByteBuffer bb, IList<LocalBuilder> locals)
656 bb.WriteCompressedInt(locals.Count);
657 foreach (LocalBuilder local in locals)
661 bb.Write(ELEMENT_TYPE_PINNED);
663 WriteType(module, bb, local.LocalType);
667 internal static void WritePropertySig(ModuleBuilder module, ByteBuffer bb, CallingConventions callingConvention,
668 Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers,
669 Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
671 byte flags = PROPERTY;
672 if ((callingConvention & CallingConventions.HasThis) != 0)
676 if ((callingConvention & CallingConventions.ExplicitThis) != 0)
678 flags |= EXPLICITTHIS;
680 if ((callingConvention & CallingConventions.VarArgs) != 0)
685 bb.WriteCompressedInt(parameterTypes == null ? 0 : parameterTypes.Length);
686 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, returnTypeRequiredCustomModifiers);
687 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, returnTypeOptionalCustomModifiers);
688 WriteType(module, bb, returnType);
689 if (parameterTypes != null)
691 for (int i = 0; i < parameterTypes.Length; i++)
693 if (parameterTypeRequiredCustomModifiers != null)
695 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, parameterTypeRequiredCustomModifiers[i]);
697 if (parameterTypeOptionalCustomModifiers != null)
699 WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, parameterTypeOptionalCustomModifiers[i]);
701 WriteType(module, bb, parameterTypes[i]);
706 internal static void WriteTypeSpec(ModuleBuilder module, ByteBuffer bb, Type type)
708 WriteType(module, bb, type);
711 internal static void WriteMethodSpec(ModuleBuilder module, ByteBuffer bb, Type[] genArgs)
713 bb.Write(GENERICINST);
714 bb.WriteCompressedInt(genArgs.Length);
715 foreach (Type arg in genArgs)
717 WriteType(module, bb, arg);
721 // this reads just the optional parameter types, from a MethodRefSig
722 internal static Type[] ReadOptionalParameterTypes(ModuleReader module, ByteReader br)
725 int paramCount = br.ReadCompressedInt();
726 SkipCustomModifiers(br);
727 ReadRetType(module, br, null);
728 for (int i = 0; i < paramCount; i++)
730 if (br.PeekByte() == SENTINEL)
733 Type[] types = new Type[paramCount - i];
734 for (int j = 0; j < types.Length; j++)
736 SkipCustomModifiers(br);
737 types[j] = ReadType(module, br, null);
741 SkipCustomModifiers(br);
742 ReadType(module, br, null);
744 return Type.EmptyTypes;
747 protected static Type[] BindTypeParameters(IGenericBinder binder, Type[] types)
749 if (types == null || types.Length == 0)
751 return Type.EmptyTypes;
753 Type[] expanded = new Type[types.Length];
754 for (int i = 0; i < types.Length; i++)
756 expanded[i] = types[i].BindTypeParameters(binder);
761 protected static Type[][] BindTypeParameters(IGenericBinder binder, Type[][] types)
767 Type[][] expanded = new Type[types.Length][];
768 for (int i = 0; i < types.Length; i++)
770 expanded[i] = BindTypeParameters(binder, types[i]);
775 protected static Type[][][] BindTypeParameters(IGenericBinder binder, Type[][][] types)
781 Type[][][] expanded = new Type[types.Length][][];
782 for (int i = 0; i < types.Length; i++)
784 expanded[i] = BindTypeParameters(binder, types[i]);
789 protected static Type[] BindTypeParameters(IGenericBinder binder, Type[][][] types, int index, int optOrReq)
791 if (types == null || types[index] == null)
795 return BindTypeParameters(binder, types[index][optOrReq]);