예제 #1
0
        public Binary.PredefinedOperator[] GetPredefinedEnumAritmeticOperators(TypeSpec enumType, bool nullable)
        {
            TypeSpec underlying;

            Binary.Operator mask = 0;

            if (nullable)
            {
                underlying = Nullable.NullableInfo.GetEnumUnderlyingType(this, enumType);
                mask       = Binary.Operator.NullableMask;
            }
            else
            {
                underlying = EnumSpec.GetUnderlyingType(enumType);
            }

            var operators = new[] {
                new Binary.PredefinedOperator(enumType, underlying,
                                              mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
                new Binary.PredefinedOperator(underlying, enumType,
                                              mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
                new Binary.PredefinedOperator(enumType, mask | Binary.Operator.SubtractionMask, underlying)
            };

            return(operators);
        }
예제 #2
0
        //
        // 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;
            }

            if (type.IsStruct || TypeManager.IsGenericParameter(type))
            {
                Emit(OpCodes.Stobj, type);
            }
            else
            {
                ig.Emit(OpCodes.Stind_Ref);
            }
        }
예제 #3
0
        bool CanBeVolatile()
        {
            switch (MemberType.BuiltinType)
            {
            case BuiltinTypeSpec.Type.Bool:
            case BuiltinTypeSpec.Type.Char:
            case BuiltinTypeSpec.Type.SByte:
            case BuiltinTypeSpec.Type.Byte:
            case BuiltinTypeSpec.Type.Short:
            case BuiltinTypeSpec.Type.UShort:
            case BuiltinTypeSpec.Type.Int:
            case BuiltinTypeSpec.Type.UInt:
            case BuiltinTypeSpec.Type.Float:
            case BuiltinTypeSpec.Type.UIntPtr:
            case BuiltinTypeSpec.Type.IntPtr:
                return(true);
            }

            if (TypeSpec.IsReferenceType(MemberType))
            {
                return(true);
            }

            if (MemberType.IsPointer)
            {
                return(true);
            }

            if (MemberType.IsEnum)
            {
                switch (EnumSpec.GetUnderlyingType(MemberType).BuiltinType)
                {
                case BuiltinTypeSpec.Type.SByte:
                case BuiltinTypeSpec.Type.Byte:
                case BuiltinTypeSpec.Type.Short:
                case BuiltinTypeSpec.Type.UShort:
                case BuiltinTypeSpec.Type.Int:
                case BuiltinTypeSpec.Type.UInt:
                    return(true);

                default:
                    return(false);
                }
            }

            return(false);
        }
        //
        // The stack contains the pointer and the value of type `type'
        //
        public void EmitStoreFromPtr(TypeSpec type)
        {
            if (type.IsEnum)
            {
                type = EnumSpec.GetUnderlyingType(type);
            }

            if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
            {
                ig.Emit(OpCodes.Stind_I4);
            }
            else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
            {
                ig.Emit(OpCodes.Stind_I8);
            }
            else if (type == TypeManager.char_type || type == TypeManager.short_type ||
                     type == TypeManager.ushort_type)
            {
                ig.Emit(OpCodes.Stind_I2);
            }
            else if (type == TypeManager.float_type)
            {
                ig.Emit(OpCodes.Stind_R4);
            }
            else if (type == TypeManager.double_type)
            {
                ig.Emit(OpCodes.Stind_R8);
            }
            else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
                     type == TypeManager.bool_type)
            {
                ig.Emit(OpCodes.Stind_I1);
            }
            else if (type == TypeManager.intptr_type)
            {
                ig.Emit(OpCodes.Stind_I);
            }
            else if (TypeManager.IsStruct(type) || TypeManager.IsGenericParameter(type))
            {
                Emit(OpCodes.Stobj, type);
            }
            else
            {
                ig.Emit(OpCodes.Stind_Ref);
            }
        }
예제 #5
0
        public override Constant ConvertImplicitly(TypeSpec type)
        {
            //
            // The 0 literal can be converted to an enum value
            //
            if (Value == 0 && type.IsEnum)
            {
                Constant c = ConvertImplicitly(EnumSpec.GetUnderlyingType(type));
                if (c == null)
                {
                    return(null);
                }

                return(new EnumConstant(c, type));
            }

            return(base.ConvertImplicitly(type));
        }
예제 #6
0
        public override Constant ConvertImplicitly(TypeSpec type, ResolveContext opt_ec, bool upconvert_only = false)
        {
            //
            // The 0 literal can be converted to an enum value
            //
            if (Value == 0 && type.IsEnum)
            {
                Constant c = ConvertImplicitly(EnumSpec.GetUnderlyingType(type), opt_ec, upconvert_only);
                if (c == null)
                {
                    return(null);
                }

                return(new EnumConstant(c, type));
            }

            return(base.ConvertImplicitly(type, opt_ec, upconvert_only));
        }
        public override Constant ConvertImplicitly(ResolveContext rc, TypeSpec type)
        {
            //
            // The 0 literal can be converted to an enum value
            //
            if (Value == 0 && TypeManager.IsEnumType(type))
            {
                Constant c = ConvertImplicitly(rc, EnumSpec.GetUnderlyingType(type));
                if (c == null)
                {
                    return(null);
                }

                return(new EnumConstant(c, type).Resolve(rc));
            }

            return(base.ConvertImplicitly(rc, type));
        }
예제 #8
0
        //
        // 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;
            }
        }
예제 #9
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;
            }
        }
예제 #10
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:
            //
            // 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;
            }
        }
예제 #11
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_0);
                ig.Emit(OpCodes.Cgt_Un);
                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;
            }
        }
예제 #12
0
        //
        // 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;
            }
        }
 //
 // Load the object from the pointer.
 //
 public void EmitLoadFromPtr(TypeSpec t)
 {
     if (t == TypeManager.int32_type)
     {
         ig.Emit(OpCodes.Ldind_I4);
     }
     else if (t == TypeManager.uint32_type)
     {
         ig.Emit(OpCodes.Ldind_U4);
     }
     else if (t == TypeManager.short_type)
     {
         ig.Emit(OpCodes.Ldind_I2);
     }
     else if (t == TypeManager.ushort_type)
     {
         ig.Emit(OpCodes.Ldind_U2);
     }
     else if (t == TypeManager.char_type)
     {
         ig.Emit(OpCodes.Ldind_U2);
     }
     else if (t == TypeManager.byte_type)
     {
         ig.Emit(OpCodes.Ldind_U1);
     }
     else if (t == TypeManager.sbyte_type)
     {
         ig.Emit(OpCodes.Ldind_I1);
     }
     else if (t == TypeManager.uint64_type)
     {
         ig.Emit(OpCodes.Ldind_I8);
     }
     else if (t == TypeManager.int64_type)
     {
         ig.Emit(OpCodes.Ldind_I8);
     }
     else if (t == TypeManager.float_type)
     {
         ig.Emit(OpCodes.Ldind_R4);
     }
     else if (t == TypeManager.double_type)
     {
         ig.Emit(OpCodes.Ldind_R8);
     }
     else if (t == TypeManager.bool_type)
     {
         ig.Emit(OpCodes.Ldind_I1);
     }
     else if (t == TypeManager.intptr_type)
     {
         ig.Emit(OpCodes.Ldind_I);
     }
     else if (t.IsEnum)
     {
         if (t == TypeManager.enum_type)
         {
             ig.Emit(OpCodes.Ldind_Ref);
         }
         else
         {
             EmitLoadFromPtr(EnumSpec.GetUnderlyingType(t));
         }
     }
     else if (TypeManager.IsStruct(t) || TypeManager.IsGenericParameter(t))
     {
         Emit(OpCodes.Ldobj, t);
     }
     else if (t.IsPointer)
     {
         ig.Emit(OpCodes.Ldind_I);
     }
     else
     {
         ig.Emit(OpCodes.Ldind_Ref);
     }
 }
        //
        // 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.IsEnum)
            {
                type = EnumSpec.GetUnderlyingType(type);
            }

            if (type == TypeManager.byte_type || type == TypeManager.sbyte_type || type == TypeManager.bool_type)
            {
                Emit(OpCodes.Stelem_I1);
            }
            else if (type == TypeManager.short_type || type == TypeManager.ushort_type || type == TypeManager.char_type)
            {
                Emit(OpCodes.Stelem_I2);
            }
            else if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
            {
                Emit(OpCodes.Stelem_I4);
            }
            else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
            {
                Emit(OpCodes.Stelem_I8);
            }
            else if (type == TypeManager.float_type)
            {
                Emit(OpCodes.Stelem_R4);
            }
            else if (type == TypeManager.double_type)
            {
                Emit(OpCodes.Stelem_R8);
            }
            else if (type == TypeManager.intptr_type)
            {
                Emit(OpCodes.Stobj, type);
            }
            else if (TypeManager.IsStruct(type))
            {
                Emit(OpCodes.Stobj, type);
            }
            else if (type.IsGenericParameter)
            {
                Emit(OpCodes.Stelem, type);
            }
            else if (type.IsPointer)
            {
                Emit(OpCodes.Stelem_I);
            }
            else
            {
                Emit(OpCodes.Stelem_Ref);
            }
        }
예제 #15
0
        //
        // 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);
                break;

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

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

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

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

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

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

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

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

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

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

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

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

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

            if (TrackStackTypes)
            {
                // TODO: test for async when `this' can be used inside structs
                SetStackType(type);
            }
        }