コード例 #1
0
ファイル: enum.cs プロジェクト: segaman/NRefactory
 public Enum(TypeContainer parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
     : base(parent, name, attrs, MemberKind.Enum)
 {
     underlying_type_expr = type;
     var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
     ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
     spec = new EnumSpec (null, this, null, null, ModFlags);
 }
コード例 #2
0
ファイル: enum.cs プロジェクト: speier/shake
 public Enum(NamespaceEntry ns, DeclSpace parent, TypeExpr type,
     Modifiers mod_flags, MemberName name, Attributes attrs)
     : base(ns, parent, name, attrs, MemberKind.Enum)
 {
     this.base_type = type;
     var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
     ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
     spec = new EnumSpec (null, this, null, null, ModFlags);
 }
コード例 #3
0
ファイル: import.cs プロジェクト: Gobiner/ILSpy
		TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType)
		{
			TypeSpec spec;
			if (import_cache.TryGetValue (type, out spec)) {
				if (spec.BuiltinType == BuiltinTypeSpec.Type.Object) {
					if (dtype.IsDynamicObject (this))
						return module.Compiler.BuiltinTypes.Dynamic;

					return spec;
				}

				if (!spec.IsGeneric || type.IsGenericTypeDefinition)
					return spec;

				if (!dtype.HasDynamicAttribute (this))
					return spec;

				// We've found same object in the cache but this one has a dynamic custom attribute
				// and it's most likely dynamic version of same type IFoo<object> agains IFoo<dynamic>
				// Do type resolve process again in that case

				// TODO: Handle cases where they still unify
			}

			if (IsMissingType (type)) {
				spec = new TypeSpec (MemberKind.MissingType, declaringType, new ImportedTypeDefinition (type, this), type, Modifiers.PUBLIC);
				spec.MemberCache = MemberCache.Empty;
				import_cache.Add (type, spec);
				return spec;
			}

			if (type.IsGenericType && !type.IsGenericTypeDefinition) {
				var type_def = type.GetGenericTypeDefinition ();

				// Generic type definition can also be forwarded
				if (compiled_types.TryGetValue (type_def, out spec))
					return spec;

				var targs = CreateGenericArguments (0, type.GetGenericArguments (), dtype);
				if (declaringType == null) {
					// Simple case, no nesting
					spec = CreateType (type_def, null, new DynamicTypeReader (), canImportBaseType);
					spec = spec.MakeGenericType (module, targs);
				} else {
					//
					// Nested type case, converting .NET types like
					// A`1.B`1.C`1<int, long, string> to typespec like
					// A<int>.B<long>.C<string>
					//
					var nested_hierarchy = new List<TypeSpec> ();
					while (declaringType.IsNested) {
						nested_hierarchy.Add (declaringType);
						declaringType = declaringType.DeclaringType;
					}

					int targs_pos = 0;
					if (declaringType.Arity > 0) {
						spec = declaringType.MakeGenericType (module, targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ());
						targs_pos = spec.Arity;
					} else {
						spec = declaringType;
					}

					for (int i = nested_hierarchy.Count; i != 0; --i) {
						var t = nested_hierarchy [i - 1];
						spec = MemberCache.FindNestedType (spec, t.Name, t.Arity);
						if (t.Arity > 0) {
							spec = spec.MakeGenericType (module, targs.Skip (targs_pos).Take (spec.Arity).ToArray ());
							targs_pos += t.Arity;
						}
					}

					string name = type.Name;
					int index = name.IndexOf ('`');
					if (index > 0)
						name = name.Substring (0, index);

					spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos);
					if (spec == null)
						return null;

					if (spec.Arity > 0) {
						spec = spec.MakeGenericType (module, targs.Skip (targs_pos).ToArray ());
					}
				}

				// Don't add generic type with dynamic arguments, they can interfere with same type
				// using object type arguments
				if (!spec.HasDynamicElement) {

					// Add to reading cache to speed up reading
					if (!import_cache.ContainsKey (type))
						import_cache.Add (type, spec);
				}

				return spec;
			}

			Modifiers mod;
			MemberKind kind;

			var ma = type.Attributes;
			switch (ma & TypeAttributes.VisibilityMask) {
			case TypeAttributes.Public:
			case TypeAttributes.NestedPublic:
				mod = Modifiers.PUBLIC;
				break;
			case TypeAttributes.NestedPrivate:
				mod = Modifiers.PRIVATE;
				break;
			case TypeAttributes.NestedFamily:
				mod = Modifiers.PROTECTED;
				break;
			case TypeAttributes.NestedFamORAssem:
				mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
				break;
			default:
				mod = Modifiers.INTERNAL;
				break;
			}

			if ((ma & TypeAttributes.Interface) != 0) {
				kind = MemberKind.Interface;
			} else if (type.IsGenericParameter) {
				kind = MemberKind.TypeParameter;
			} else {
				var base_type = type.BaseType;
				if (base_type == null || (ma & TypeAttributes.Abstract) != 0) {
					kind = MemberKind.Class;
				} else {
					kind = DetermineKindFromBaseType (base_type);
					if (kind == MemberKind.Struct || kind == MemberKind.Delegate) {
						mod |= Modifiers.SEALED;
					}
				}

				if (kind == MemberKind.Class) {
					if ((ma & TypeAttributes.Sealed) != 0) {
						mod |= Modifiers.SEALED;
						if ((ma & TypeAttributes.Abstract) != 0)
							mod |= Modifiers.STATIC;
					} else if ((ma & TypeAttributes.Abstract) != 0) {
						mod |= Modifiers.ABSTRACT;
					}
				}
			}

			var definition = new ImportedTypeDefinition (type, this);
			TypeSpec pt;

			if (kind == MemberKind.Enum) {
				const BindingFlags underlying_member = BindingFlags.DeclaredOnly |
					BindingFlags.Instance |
					BindingFlags.Public | BindingFlags.NonPublic;

				var type_members = type.GetFields (underlying_member);
				foreach (var type_member in type_members) {
					spec = new EnumSpec (declaringType, definition, CreateType (type_member.FieldType), type, mod);
					break;
				}

				if (spec == null)
					kind = MemberKind.Class;

			} else if (kind == MemberKind.TypeParameter) {
				spec = CreateTypeParameter (type, declaringType);
			} else if (type.IsGenericTypeDefinition) {
				definition.TypeParameters = CreateGenericParameters (type, declaringType);
			} else if (compiled_types.TryGetValue (type, out pt)) {
				//
				// Same type was found in inside compiled types. It's
				// either build-in type or forward referenced typed
				// which point into just compiled assembly.
				//
				spec = pt;
				BuiltinTypeSpec bts = pt as BuiltinTypeSpec;
				if (bts != null)
					bts.SetDefinition (definition, type, mod);
			}

			if (spec == null)
				spec = new TypeSpec (kind, declaringType, definition, type, mod);

			import_cache.Add (type, spec);

			if (kind == MemberKind.TypeParameter) {
				if (canImportBaseType)
					ImportTypeParameterTypeConstraints ((TypeParameterSpec) spec, type);

				return spec;
			}

			//
			// Two stage setup as the base type can be inflated declaring type or
			// another nested type inside same declaring type which has not been
			// loaded, therefore we can import a base type of nested types once
			// the types have been imported
			//
			if (canImportBaseType)
				ImportTypeBase (spec, type);

			return spec;
		}
コード例 #4
0
        //
        // Emits the right opcode to store to an array
        //
        public void EmitArrayStore(ArrayContainer ac)
        {
            if (ac.Rank > 1)
            {
                if (IsAnonymousStoreyMutateRequired)
                {
                    ac = (ArrayContainer)ac.Mutate(CurrentAnonymousMethod.Storey.Mutator);
                }

                ig.Emit(OpCodes.Call, ac.GetSetMethod());
                return;
            }

            var type = ac.Element;

            if (type.Kind == MemberKind.Enum)
            {
                type = EnumSpec.GetUnderlyingType(type);
            }

            switch (type.BuiltinType)
            {
            case BuiltinTypeSpec.Type.Byte:
            case BuiltinTypeSpec.Type.SByte:
            case BuiltinTypeSpec.Type.Bool:
                Emit(OpCodes.Stelem_I1);
                return;

            case BuiltinTypeSpec.Type.Short:
            case BuiltinTypeSpec.Type.UShort:
            case BuiltinTypeSpec.Type.Char:
                Emit(OpCodes.Stelem_I2);
                return;

            case BuiltinTypeSpec.Type.Int:
            case BuiltinTypeSpec.Type.UInt:
                Emit(OpCodes.Stelem_I4);
                return;

            case BuiltinTypeSpec.Type.Long:
            case BuiltinTypeSpec.Type.ULong:
                Emit(OpCodes.Stelem_I8);
                return;

            case BuiltinTypeSpec.Type.Float:
                Emit(OpCodes.Stelem_R4);
                return;

            case BuiltinTypeSpec.Type.Double:
                Emit(OpCodes.Stelem_R8);
                return;
            }

            switch (type.Kind)
            {
            case MemberKind.Struct:
                Emit(OpCodes.Stobj, type);
                break;

            case MemberKind.TypeParameter:
                Emit(OpCodes.Stelem, type);
                break;

            case MemberKind.PointerType:
                Emit(OpCodes.Stelem_I);
                break;

            default:
                Emit(OpCodes.Stelem_Ref);
                break;
            }
        }
コード例 #5
0
ファイル: codegen.cs プロジェクト: tkokof/NRefactory
        //
        // The stack contains the pointer and the value of type `type'
        //
        public void EmitStoreFromPtr(TypeSpec type)
        {
            if (type.IsEnum)
            {
                type = EnumSpec.GetUnderlyingType(type);
            }

            switch (type.BuiltinType)
            {
            case BuiltinTypeSpec.Type.Int:
            case BuiltinTypeSpec.Type.UInt:
                ig.Emit(OpCodes.Stind_I4);
                return;

            case BuiltinTypeSpec.Type.Long:
            case BuiltinTypeSpec.Type.ULong:
                ig.Emit(OpCodes.Stind_I8);
                return;

            case BuiltinTypeSpec.Type.Char:
            case BuiltinTypeSpec.Type.Short:
            case BuiltinTypeSpec.Type.UShort:
                ig.Emit(OpCodes.Stind_I2);
                return;

            case BuiltinTypeSpec.Type.Float:
                ig.Emit(OpCodes.Stind_R4);
                return;

            case BuiltinTypeSpec.Type.Double:
                ig.Emit(OpCodes.Stind_R8);
                return;

            case BuiltinTypeSpec.Type.Byte:
            case BuiltinTypeSpec.Type.SByte:
            case BuiltinTypeSpec.Type.Bool:
                ig.Emit(OpCodes.Stind_I1);
                return;

            case BuiltinTypeSpec.Type.IntPtr:
                ig.Emit(OpCodes.Stind_I);
                return;
            }

            switch (type.Kind)
            {
            case MemberKind.Struct:
            case MemberKind.TypeParameter:
                if (IsAnonymousStoreyMutateRequired)
                {
                    type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type);
                }

                ig.Emit(OpCodes.Stobj, type.GetMetaInfo());
                break;

            default:
                ig.Emit(OpCodes.Stind_Ref);
                break;
            }
        }
コード例 #6
0
ファイル: import.cs プロジェクト: davidwaters/mono
		public TypeSpec CreateType (Type type, TypeSpec declaringType, ICustomAttributeProvider ca, int dynamicCursor, bool canImportBaseType)
		{
			TypeSpec spec;
			if (import_cache.TryGetValue (type, out spec)) {
				if (ca == null)
					return spec;

				if (type == typeof (object)) {
					if (IsDynamicType (ca, dynamicCursor))
						return InternalType.Dynamic;

					return spec;
				}

				if (!spec.IsGeneric)
					return spec;

#if NET_4_0
				if (!ca.IsDefined (typeof (DynamicAttribute), false))
#endif
					return spec;

				// We've found same object in the cache but this one has a dynamic custom attribute
				// and it's most likely dynamic version of same type IFoo<object> agains IFoo<dynamic>
				// Do resolve the type process again in that case
			}

			if (type.IsGenericType && !type.IsGenericTypeDefinition) {
				var type_def = type.GetGenericTypeDefinition ();
				var targs = CreateGenericArguments (0, type.GetGenericArguments (), ca, dynamicCursor + 1);
				if (declaringType == null) {
					// Simple case, no nesting
					spec = CreateType (type_def, null, null, 0, canImportBaseType);
					spec = spec.MakeGenericType (targs);
				} else {
					//
					// Nested type case, converting .NET types like
					// A`1.B`1.C`1<int, long, string> to typespec like
					// A<int>.B<long>.C<string>
					//
					var nested_hierarchy = new List<TypeSpec> ();
					while (declaringType.IsNested) {
						nested_hierarchy.Add (declaringType);
						declaringType = declaringType.DeclaringType;
					}

					int targs_pos = 0;
					if (declaringType.Arity > 0) {
						spec = declaringType.MakeGenericType (targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ());
						targs_pos = spec.Arity;
					} else {
						spec = declaringType;
					}

					for (int i = nested_hierarchy.Count; i != 0; --i) {
						var t = nested_hierarchy [i - 1];
						spec = MemberCache.FindNestedType (spec, t.Name, t.Arity);
						if (t.Arity > 0) {
							spec = spec.MakeGenericType (targs.Skip (targs_pos).Take (spec.Arity).ToArray ());
							targs_pos += t.Arity;
						}
					}

					string name = type.Name;
					int index = name.IndexOf ('`');
					if (index > 0)
						name = name.Substring (0, index);

					spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos);
					if (spec.Arity > 0) {
						spec = spec.MakeGenericType (targs.Skip (targs_pos).ToArray ());
					}
				}

				// Don't add generic type with dynamic arguments, they can interfere with same type
				// using object type arguments
				if (!spec.HasDynamicElement) {

					// Add to reading cache to speed up reading
					if (!import_cache.ContainsKey (type))
						import_cache.Add (type, spec);
				}

				return spec;
			}

			Modifiers mod;
			MemberKind kind;

			var ma = type.Attributes;
			switch (ma & TypeAttributes.VisibilityMask) {
			case TypeAttributes.Public:
			case TypeAttributes.NestedPublic:
				mod = Modifiers.PUBLIC;
				break;
			case TypeAttributes.NestedPrivate:
				mod = Modifiers.PRIVATE;
				break;
			case TypeAttributes.NestedFamily:
				mod = Modifiers.PROTECTED;
				break;
			case TypeAttributes.NestedFamORAssem:
				mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
				break;
			default:
				mod = Modifiers.INTERNAL;
				break;
			}

			if ((ma & TypeAttributes.Interface) != 0) {
				kind = MemberKind.Interface;
			} else if (type.IsGenericParameter) {
				kind = MemberKind.TypeParameter;
			} else if (type.IsClass || type.IsAbstract) {  				// System.Reflection: System.Enum returns false for IsClass
				if ((ma & TypeAttributes.Sealed) != 0 && type.IsSubclassOf (typeof (MulticastDelegate))) {
					kind = MemberKind.Delegate;
					mod |= Modifiers.SEALED;
				} else {
					kind = MemberKind.Class;
					if ((ma & TypeAttributes.Sealed) != 0) {
						mod |= Modifiers.SEALED;
						if ((ma & TypeAttributes.Abstract) != 0)
							mod |= Modifiers.STATIC;
					} else if ((ma & TypeAttributes.Abstract) != 0) {
						mod |= Modifiers.ABSTRACT;
					}
				}
			} else if (type.IsEnum) {
				kind = MemberKind.Enum;
			} else {
				kind = MemberKind.Struct;
				mod |= Modifiers.SEALED;
			}

			var definition = new ImportedTypeDefinition (this, type);
			PredefinedTypeSpec pt;

			if (kind == MemberKind.Enum) {
				const BindingFlags underlying_member = BindingFlags.DeclaredOnly |
					BindingFlags.Instance |
					BindingFlags.Public | BindingFlags.NonPublic;

				var type_members = type.GetFields (underlying_member);
				foreach (var type_member in type_members) {
					spec = new EnumSpec (declaringType, definition, CreateType (type_member.FieldType), type, mod);
					break;
				}

				if (spec == null)
					kind = MemberKind.Class;

			} else if (kind == MemberKind.TypeParameter) {
				// Return as type_cache was updated
				return CreateTypeParameter (type, declaringType);
			} else if (type.IsGenericTypeDefinition) {
				definition.TypeParameters = CreateGenericParameters (type, declaringType);

				// Constraints are not loaded on demand and can reference this type
				if (import_cache.TryGetValue (type, out spec))
					return spec;

			} else if (type_2_predefined.TryGetValue (type, out pt)) {
				spec = pt;
				pt.SetDefinition (definition, type);
			}

			if (spec == null)
				spec = new TypeSpec (kind, declaringType, definition, type, mod);

			import_cache.Add (type, spec);

			//
			// Two stage setup as the base type can be inflated declaring type or
			// another nested type inside same declaring type which has not been
			// loaded, therefore we can import a base type of nested types once
			// the types have been imported
			//
			if (canImportBaseType)
				ImportTypeBase (spec, type);

			return spec;
		}
コード例 #7
0
        //
        // Emits the right opcode to load from an array
        //
        public void EmitArrayLoad(ArrayContainer ac)
        {
            if (ac.Rank > 1)
            {
                if (IsAnonymousStoreyMutateRequired)
                {
                    ac = (ArrayContainer)ac.Mutate(CurrentAnonymousMethod.Storey.Mutator);
                }

                ig.Emit(OpCodes.Call, ac.GetGetMethod());
                return;
            }


            var type = ac.Element;

            if (type.Kind == MemberKind.Enum)
            {
                type = EnumSpec.GetUnderlyingType(type);
            }

            switch (type.BuiltinType)
            {
            case BuiltinTypeSpec.Type.Bool:
                //
                // Workaround MSIL limitation. Load bool element as single bit,
                // bool array can actually store any byte value
                //
                ig.Emit(OpCodes.Ldelem_U1);
                ig.Emit(OpCodes.Ldc_I4_1);
                ig.Emit(OpCodes.And);
                break;

            case BuiltinTypeSpec.Type.Byte:
                ig.Emit(OpCodes.Ldelem_U1);
                break;

            case BuiltinTypeSpec.Type.SByte:
                ig.Emit(OpCodes.Ldelem_I1);
                break;

            case BuiltinTypeSpec.Type.Short:
                ig.Emit(OpCodes.Ldelem_I2);
                break;

            case BuiltinTypeSpec.Type.UShort:
            case BuiltinTypeSpec.Type.Char:
                ig.Emit(OpCodes.Ldelem_U2);
                break;

            case BuiltinTypeSpec.Type.Int:
                ig.Emit(OpCodes.Ldelem_I4);
                break;

            case BuiltinTypeSpec.Type.UInt:
                ig.Emit(OpCodes.Ldelem_U4);
                break;

            case BuiltinTypeSpec.Type.ULong:
            case BuiltinTypeSpec.Type.Long:
                ig.Emit(OpCodes.Ldelem_I8);
                break;

            case BuiltinTypeSpec.Type.Float:
                ig.Emit(OpCodes.Ldelem_R4);
                break;

            case BuiltinTypeSpec.Type.Double:
                ig.Emit(OpCodes.Ldelem_R8);
                break;

            case BuiltinTypeSpec.Type.IntPtr:
                ig.Emit(OpCodes.Ldelem_I);
                break;

            default:
                switch (type.Kind)
                {
                case MemberKind.Struct:
                    if (IsAnonymousStoreyMutateRequired)
                    {
                        type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type);
                    }

                    ig.Emit(OpCodes.Ldelema, type.GetMetaInfo());
                    ig.Emit(OpCodes.Ldobj, type.GetMetaInfo());
                    break;

                case MemberKind.TypeParameter:
                    if (IsAnonymousStoreyMutateRequired)
                    {
                        type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type);
                    }

                    ig.Emit(OpCodes.Ldelem, type.GetMetaInfo());
                    break;

                case MemberKind.PointerType:
                    ig.Emit(OpCodes.Ldelem_I);
                    break;

                default:
                    ig.Emit(OpCodes.Ldelem_Ref);
                    break;
                }
                break;
            }
        }
コード例 #8
0
ファイル: codegen.cs プロジェクト: zhufengGNSS/mono
        //
        // Emits the right opcode to load from an array
        //
        public void EmitArrayLoad(ArrayContainer ac)
        {
            if (ac.Rank > 1)
            {
                if (IsAnonymousStoreyMutateRequired)
                {
                    ac = (ArrayContainer)ac.Mutate(CurrentAnonymousMethod.Storey.Mutator);
                }

                ig.Emit(OpCodes.Call, ac.GetGetMethod());
                return;
            }


            var type = ac.Element;

            if (type.Kind == MemberKind.Enum)
            {
                type = EnumSpec.GetUnderlyingType(type);
            }

            switch (type.BuiltinType)
            {
            case BuiltinTypeSpec.Type.Bool:
            //
            // bool array can actually store any byte value in underlying byte slot
            // and C# spec does not specify any normalization rule, except the result
            // is undefined
            //
            case BuiltinTypeSpec.Type.Byte:
                ig.Emit(OpCodes.Ldelem_U1);
                break;

            case BuiltinTypeSpec.Type.SByte:
                ig.Emit(OpCodes.Ldelem_I1);
                break;

            case BuiltinTypeSpec.Type.Short:
                ig.Emit(OpCodes.Ldelem_I2);
                break;

            case BuiltinTypeSpec.Type.UShort:
            case BuiltinTypeSpec.Type.Char:
                ig.Emit(OpCodes.Ldelem_U2);
                break;

            case BuiltinTypeSpec.Type.Int:
                ig.Emit(OpCodes.Ldelem_I4);
                break;

            case BuiltinTypeSpec.Type.UInt:
                ig.Emit(OpCodes.Ldelem_U4);
                break;

            case BuiltinTypeSpec.Type.ULong:
            case BuiltinTypeSpec.Type.Long:
                ig.Emit(OpCodes.Ldelem_I8);
                break;

            case BuiltinTypeSpec.Type.Float:
                ig.Emit(OpCodes.Ldelem_R4);
                break;

            case BuiltinTypeSpec.Type.Double:
                ig.Emit(OpCodes.Ldelem_R8);
                break;

            case BuiltinTypeSpec.Type.IntPtr:
                ig.Emit(OpCodes.Ldelem_I);
                break;

            default:
                switch (type.Kind)
                {
                case MemberKind.Struct:
                    if (IsAnonymousStoreyMutateRequired)
                    {
                        type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type);
                    }

                    ig.Emit(OpCodes.Ldelema, type.GetMetaInfo());
                    ig.Emit(OpCodes.Ldobj, type.GetMetaInfo());
                    break;

                case MemberKind.TypeParameter:
                    if (IsAnonymousStoreyMutateRequired)
                    {
                        type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type);
                    }

                    ig.Emit(OpCodes.Ldelem, type.GetMetaInfo());
                    break;

                case MemberKind.PointerType:
                    ig.Emit(OpCodes.Ldelem_I);
                    break;

                default:
                    ig.Emit(OpCodes.Ldelem_Ref);
                    break;
                }
                break;
            }
        }
コード例 #9
0
ファイル: codegen.cs プロジェクト: mono-soc-2011/monodevelop
        //
        // Load the object from the pointer.
        //
        public void EmitLoadFromPtr(TypeSpec type)
        {
            if (type.Kind == MemberKind.Enum)
            {
                type = EnumSpec.GetUnderlyingType(type);
            }

            switch (type.BuiltinType)
            {
            case BuiltinTypeSpec.Type.Int:
                ig.Emit(OpCodes.Ldind_I4);
                return;

            case BuiltinTypeSpec.Type.UInt:
                ig.Emit(OpCodes.Ldind_U4);
                return;

            case BuiltinTypeSpec.Type.Short:
                ig.Emit(OpCodes.Ldind_I2);
                return;

            case BuiltinTypeSpec.Type.UShort:
            case BuiltinTypeSpec.Type.Char:
                ig.Emit(OpCodes.Ldind_U2);
                return;

            case BuiltinTypeSpec.Type.Byte:
                ig.Emit(OpCodes.Ldind_U1);
                return;

            case BuiltinTypeSpec.Type.SByte:
            case BuiltinTypeSpec.Type.Bool:
                ig.Emit(OpCodes.Ldind_I1);
                return;

            case BuiltinTypeSpec.Type.ULong:
            case BuiltinTypeSpec.Type.Long:
                ig.Emit(OpCodes.Ldind_I8);
                return;

            case BuiltinTypeSpec.Type.Float:
                ig.Emit(OpCodes.Ldind_R4);
                return;

            case BuiltinTypeSpec.Type.Double:
                ig.Emit(OpCodes.Ldind_R8);
                return;

            case BuiltinTypeSpec.Type.IntPtr:
                ig.Emit(OpCodes.Ldind_I);
                return;
            }

            switch (type.Kind)
            {
            case MemberKind.Struct:
            case MemberKind.TypeParameter:
                Emit(OpCodes.Ldobj, type);
                break;

            case MemberKind.PointerType:
                ig.Emit(OpCodes.Ldind_I);
                break;

            default:
                ig.Emit(OpCodes.Ldind_Ref);
                break;
            }
        }