static TypeSig getArgType(MethodDef method, TypeSig arg) { if (arg.GetElementType() != ElementType.MVar) return arg; var mvar = (GenericMVar)arg; foreach (var gp in method.GenericParameters) { if (gp.Number != mvar.Number) continue; foreach (var gpc in gp.GenericParamConstraints) return gpc.Constraint.ToTypeSig(); } return arg; }
TypeSig DoInferTypeForExpression(ILExpression expr, TypeSig expectedType, bool forceInferChildren = false) { switch (expr.Code) { #region Logical operators case ILCode.LogicNot: if (forceInferChildren) { InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); } return typeSystem.Boolean; case ILCode.LogicAnd: case ILCode.LogicOr: // if Operand is set the logic and/or expression is a custom operator // we can deal with it the same as a normal invocation. if (expr.Operand != null) goto case ILCode.Call; if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean); } return typeSystem.Boolean; case ILCode.TernaryOp: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); } return InferBinaryArguments(expr.Arguments[1], expr.Arguments[2], expectedType, forceInferChildren); case ILCode.NullCoalescing: return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType, forceInferChildren); #endregion #region Variable load/store case ILCode.Stloc: { ILVariable v = (ILVariable)expr.Operand; if (forceInferChildren) { // do not use 'expectedType' in here! InferTypeForExpression(expr.Arguments.Single(), v.Type); } return v.Type; } case ILCode.Ldloc: { ILVariable v = (ILVariable)expr.Operand; if (v.Type == null && singleLoadVariables.Contains(v)) { v.Type = expectedType; } return v.Type; } case ILCode.Ldloca: { ILVariable v = (ILVariable)expr.Operand; if (v.Type != null) return new ByRefSig(v.Type); else return null; } #endregion #region Call / NewObj case ILCode.Call: case ILCode.Callvirt: case ILCode.CallGetter: case ILCode.CallvirtGetter: case ILCode.CallSetter: case ILCode.CallvirtSetter: { IMethod method = expr.Operand as IMethod; var parameters = method == null ? null : method.MethodSig.GetParameters(); if (forceInferChildren && parameters != null && method.MethodSig != null) { for (int i = 0; i < expr.Arguments.Count; i++) { if (i == 0 && method.MethodSig.HasThis) { InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(method.DeclaringType.ToTypeSig(), expr.GetPrefix(ILCode.Constrained))); } else { InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(parameters[method.MethodSig.HasThis ? i - 1 : i], method: method)); } } } if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter) { return SubstituteTypeArgs(parameters.Last(), method: method); } else { return SubstituteTypeArgs(method.MethodSig.GetRetType(), method: method); } } case ILCode.Newobj: { IMethod ctor = (IMethod)expr.Operand; if (forceInferChildren) { var parameters = ctor.MethodSig.GetParameters(); for (int i = 0; i < parameters.Count; i++) { InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(parameters[i], null, ctor)); } } return ctor.DeclaringType.ToTypeSig(); } case ILCode.InitObject: case ILCode.InitCollection: return InferTypeForExpression(expr.Arguments[0], expectedType); case ILCode.InitializedObject: // expectedType should always be known due to the parent method call / property setter Debug.Assert(expectedType != null); return expectedType; #endregion #region Load/Store Fields case ILCode.Ldfld: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(!(expr.Operand is IField) ? null : ((IField)expr.Operand).DeclaringType.ToTypeSig(), expr.GetPrefix(ILCode.Constrained))); } return GetFieldType(expr.Operand as IField); case ILCode.Ldsfld: return GetFieldType(expr.Operand as IField); case ILCode.Ldflda: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(!(expr.Operand is IField) ? null : ((IField)expr.Operand).DeclaringType.ToTypeSig(), expr.GetPrefix(ILCode.Constrained))); } return new ByRefSig(GetFieldType(expr.Operand as IField)); case ILCode.Ldsflda: return new ByRefSig(GetFieldType(expr.Operand as IField)); case ILCode.Stfld: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(!(expr.Operand is IField) ? null : ((IField)expr.Operand).DeclaringType.ToTypeSig(), expr.GetPrefix(ILCode.Constrained))); InferTypeForExpression(expr.Arguments[1], GetFieldType(expr.Operand as IField)); } return GetFieldType(expr.Operand as IField); case ILCode.Stsfld: if (forceInferChildren) InferTypeForExpression(expr.Arguments[0], GetFieldType(expr.Operand as IField)); return GetFieldType(expr.Operand as IField); #endregion #region Reference/Pointer instructions case ILCode.Ldind_Ref: return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); case ILCode.Stind_Ref: if (forceInferChildren) { TypeSig elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); InferTypeForExpression(expr.Arguments[1], elementType); } return null; case ILCode.Ldobj: { TypeSig type = ((ITypeDefOrRef)expr.Operand).ToTypeSig(); var argType = InferTypeForExpression(expr.Arguments[0], null); if (argType is PtrSig || argType is ByRefSig) { var elementType = argType.Next; int infoAmount = GetInformationAmount(elementType); if (infoAmount == 1 && GetInformationAmount(type) == 8) { // A bool can be loaded from both bytes and sbytes. type = elementType; } if (infoAmount >= 8 && infoAmount <= 64 && infoAmount == GetInformationAmount(type)) { // An integer can be loaded as another integer of the same size. // For integers smaller than 32 bit, the signs must match (as loading performs sign extension) bool? elementTypeIsSigned = IsSigned(elementType); bool? typeIsSigned = IsSigned(type); if (elementTypeIsSigned != null && typeIsSigned != null) { if (infoAmount >= 32 || elementTypeIsSigned == typeIsSigned) type = elementType; } } } if (argType is PtrSig) InferTypeForExpression(expr.Arguments[0], new PtrSig(type)); else InferTypeForExpression(expr.Arguments[0], new ByRefSig(type)); return type; } case ILCode.Stobj: { TypeSig operandType = ((ITypeDefOrRef)expr.Operand).ToTypeSig(); TypeSig pointerType = InferTypeForExpression(expr.Arguments[0], new ByRefSig(operandType)); TypeSig elementType; if (pointerType is PtrSig) elementType = ((PtrSig)pointerType).Next; else if (pointerType is ByRefSig) elementType = ((ByRefSig)pointerType).Next; else elementType = null; if (elementType != null) { // An integer can be stored in any other integer of the same size. int infoAmount = GetInformationAmount(elementType); if (infoAmount == 1 && GetInformationAmount(operandType) == 8) operandType = elementType; else if (infoAmount == GetInformationAmount(operandType) && IsSigned(elementType) != null && IsSigned(operandType) != null) operandType = elementType; } if (forceInferChildren) { if (pointerType is PtrSig) InferTypeForExpression(expr.Arguments[0], new PtrSig(operandType)); else if (!IsSameType(operandType, (expr.Operand as ITypeDefOrRef).ToTypeSig())) InferTypeForExpression(expr.Arguments[0], new ByRefSig(operandType)); InferTypeForExpression(expr.Arguments[1], operandType); } return operandType; } case ILCode.Initobj: return null; case ILCode.DefaultValue: return ((ITypeDefOrRef)expr.Operand).ToTypeSig(); case ILCode.Localloc: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], null); } if (expectedType is PtrSig) return expectedType; else return typeSystem.IntPtr; case ILCode.Sizeof: return typeSystem.Int32; case ILCode.PostIncrement: case ILCode.PostIncrement_Ovf: case ILCode.PostIncrement_Ovf_Un: { TypeSig elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); if (forceInferChildren && elementType != null) { // Assign expected type to the child expression InferTypeForExpression(expr.Arguments[0], new ByRefSig(elementType)); } return elementType; } case ILCode.Mkrefany: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], ((ITypeDefOrRef)expr.Operand).ToTypeSig()); } return typeSystem.TypedReference; case ILCode.Refanytype: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference); } return typeSystem.GetTypeRef("System", "RuntimeTypeHandle").ToTypeSig(); case ILCode.Refanyval: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference); } return new ByRefSig(((ITypeDefOrRef)expr.Operand).ToTypeSig()); case ILCode.AddressOf: { TypeSig t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType)); return t != null ? new ByRefSig(t) : null; } case ILCode.ValueOf: return GetNullableTypeArgument(InferTypeForExpression(expr.Arguments[0], CreateNullableType(expectedType))); case ILCode.NullableOf: return CreateNullableType(InferTypeForExpression(expr.Arguments[0], GetNullableTypeArgument(expectedType))); #endregion #region Arithmetic instructions case ILCode.Not: // bitwise complement case ILCode.Neg: return InferTypeForExpression(expr.Arguments.Single(), expectedType); case ILCode.Add: return InferArgumentsInAddition(expr, null, expectedType); case ILCode.Sub: return InferArgumentsInSubtraction(expr, null, expectedType); case ILCode.Mul: case ILCode.Or: case ILCode.And: case ILCode.Xor: return InferArgumentsInBinaryOperator(expr, null, expectedType); case ILCode.Add_Ovf: return InferArgumentsInAddition(expr, true, expectedType); case ILCode.Sub_Ovf: return InferArgumentsInSubtraction(expr, true, expectedType); case ILCode.Mul_Ovf: case ILCode.Div: case ILCode.Rem: return InferArgumentsInBinaryOperator(expr, true, expectedType); case ILCode.Add_Ovf_Un: return InferArgumentsInAddition(expr, false, expectedType); case ILCode.Sub_Ovf_Un: return InferArgumentsInSubtraction(expr, false, expectedType); case ILCode.Mul_Ovf_Un: case ILCode.Div_Un: case ILCode.Rem_Un: return InferArgumentsInBinaryOperator(expr, false, expectedType); case ILCode.Shl: if (forceInferChildren) InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); if (expectedType != null && ( expectedType.ElementType == ElementType.I4 || expectedType.ElementType == ElementType.U4 || expectedType.ElementType == ElementType.I8 || expectedType.ElementType == ElementType.U8) ) return NumericPromotion(InferTypeForExpression(expr.Arguments[0], expectedType)); else return NumericPromotion(InferTypeForExpression(expr.Arguments[0], null)); case ILCode.Shr: case ILCode.Shr_Un: { if (forceInferChildren) InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); TypeSig type = NumericPromotion(InferTypeForExpression(expr.Arguments[0], null)); if (type == null) return null; TypeSig expectedInputType = null; switch (type.GetElementType()) { case ElementType.I4: if (expr.Code == ILCode.Shr_Un) expectedInputType = typeSystem.UInt32; break; case ElementType.U4: if (expr.Code == ILCode.Shr) expectedInputType = typeSystem.Int32; break; case ElementType.I8: if (expr.Code == ILCode.Shr_Un) expectedInputType = typeSystem.UInt64; break; case ElementType.U8: if (expr.Code == ILCode.Shr) expectedInputType = typeSystem.UInt64; break; } if (expectedInputType != null) { InferTypeForExpression(expr.Arguments[0], expectedInputType); return expectedInputType; } else { return type; } } case ILCode.CompoundAssignment: { var op = expr.Arguments[0]; if (op.Code == ILCode.NullableOf) op = op.Arguments[0].Arguments[0]; var varType = InferTypeForExpression(op.Arguments[0], null); if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], varType); } return varType; } #endregion #region Constant loading instructions case ILCode.Ldnull: return typeSystem.Object; case ILCode.Ldstr: return typeSystem.String; case ILCode.Ldftn: case ILCode.Ldvirtftn: return typeSystem.IntPtr; case ILCode.Ldc_I4: if (expectedType.GetElementType() == ElementType.Boolean && ((int)expr.Operand == 0 || (int)expr.Operand == 1)) return typeSystem.Boolean; if (expectedType is PtrSig && (int)expr.Operand == 0) return expectedType; if (IsIntegerOrEnum(expectedType) && OperandFitsInType(expectedType, (int)expr.Operand)) return expectedType; else return typeSystem.Int32; case ILCode.Ldc_I8: if (expectedType is PtrSig && (long)expr.Operand == 0) return expectedType; if (IsIntegerOrEnum(expectedType) && GetInformationAmount(expectedType) >= NativeInt) return expectedType; else return typeSystem.Int64; case ILCode.Ldc_R4: return typeSystem.Single; case ILCode.Ldc_R8: return typeSystem.Double; case ILCode.Ldc_Decimal: return typeSystem.GetTypeRef("System", "Decimal").ToTypeSig(); case ILCode.Ldtoken: if (expr.Operand is ITypeDefOrRef) return typeSystem.GetTypeRef("System", "RuntimeTypeHandle").ToTypeSig(); else if (expr.Operand is IField && ((IField)expr.Operand).FieldSig != null) return typeSystem.GetTypeRef("System", "RuntimeFieldHandle").ToTypeSig(); else return typeSystem.GetTypeRef("System", "RuntimeMethodHandle").ToTypeSig(); case ILCode.Arglist: return typeSystem.GetTypeRef("System", "RuntimeArgumentHandle").ToTypeSig(); #endregion #region Array instructions case ILCode.Newarr: if (forceInferChildren) { var lengthType = InferTypeForExpression(expr.Arguments.Single(), null); if (new SigComparer().Equals(lengthType, typeSystem.IntPtr)) { lengthType = typeSystem.Int64; } else if (new SigComparer().Equals(lengthType, typeSystem.UIntPtr)) { lengthType = typeSystem.UInt64; } else if (!new SigComparer().Equals(lengthType, typeSystem.UInt32) && !new SigComparer().Equals(lengthType, typeSystem.Int64) && !new SigComparer().Equals(lengthType, typeSystem.UInt64)) { lengthType = typeSystem.Int32; } if (forceInferChildren) { InferTypeForExpression(expr.Arguments.Single(), lengthType); } } return new SZArraySig(((ITypeDefOrRef)expr.Operand).ToTypeSig()); case ILCode.InitArray: var operandSig = ((ITypeDefOrRef)expr.Operand).ToTypeSig(); if (forceInferChildren) { foreach (ILExpression arg in expr.Arguments) InferTypeForExpression(arg, operandSig.Next); } return operandSig; case ILCode.Ldlen: return typeSystem.Int32; case ILCode.Ldelem_U1: case ILCode.Ldelem_U2: case ILCode.Ldelem_U4: case ILCode.Ldelem_I1: case ILCode.Ldelem_I2: case ILCode.Ldelem_I4: case ILCode.Ldelem_I8: case ILCode.Ldelem_R4: case ILCode.Ldelem_R8: case ILCode.Ldelem_I: case ILCode.Ldelem_Ref: { SZArraySig arrayType = InferTypeForExpression(expr.Arguments[0], null) as SZArraySig; if (forceInferChildren) { InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); } return arrayType != null ? arrayType.Next : null; } case ILCode.Ldelem: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); } return ((ITypeDefOrRef)expr.Operand).ToTypeSig(); case ILCode.Ldelema: { SZArraySig arrayType = InferTypeForExpression(expr.Arguments[0], null) as SZArraySig; if (forceInferChildren) InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); return arrayType != null ? new ByRefSig(arrayType.Next) : null; } case ILCode.Stelem_I: case ILCode.Stelem_I1: case ILCode.Stelem_I2: case ILCode.Stelem_I4: case ILCode.Stelem_I8: case ILCode.Stelem_R4: case ILCode.Stelem_R8: case ILCode.Stelem_Ref: case ILCode.Stelem: { SZArraySig arrayType = InferTypeForExpression(expr.Arguments[0], null) as SZArraySig; if (forceInferChildren) { InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); if (arrayType != null) { InferTypeForExpression(expr.Arguments[2], arrayType.Next); } } return arrayType != null ? arrayType.Next : null; } #endregion #region Conversion instructions case ILCode.Conv_I1: case ILCode.Conv_Ovf_I1: case ILCode.Conv_Ovf_I1_Un: return HandleConversion(8, true, expr.Arguments[0], expectedType, typeSystem.SByte); case ILCode.Conv_I2: case ILCode.Conv_Ovf_I2: case ILCode.Conv_Ovf_I2_Un: return HandleConversion(16, true, expr.Arguments[0], expectedType, typeSystem.Int16); case ILCode.Conv_I4: case ILCode.Conv_Ovf_I4: case ILCode.Conv_Ovf_I4_Un: return HandleConversion(32, true, expr.Arguments[0], expectedType, typeSystem.Int32); case ILCode.Conv_I8: case ILCode.Conv_Ovf_I8: case ILCode.Conv_Ovf_I8_Un: return HandleConversion(64, true, expr.Arguments[0], expectedType, typeSystem.Int64); case ILCode.Conv_U1: case ILCode.Conv_Ovf_U1: case ILCode.Conv_Ovf_U1_Un: return HandleConversion(8, false, expr.Arguments[0], expectedType, typeSystem.Byte); case ILCode.Conv_U2: case ILCode.Conv_Ovf_U2: case ILCode.Conv_Ovf_U2_Un: return HandleConversion(16, false, expr.Arguments[0], expectedType, typeSystem.UInt16); case ILCode.Conv_U4: case ILCode.Conv_Ovf_U4: case ILCode.Conv_Ovf_U4_Un: return HandleConversion(32, false, expr.Arguments[0], expectedType, typeSystem.UInt32); case ILCode.Conv_U8: case ILCode.Conv_Ovf_U8: case ILCode.Conv_Ovf_U8_Un: return HandleConversion(64, false, expr.Arguments[0], expectedType, typeSystem.UInt64); case ILCode.Conv_I: case ILCode.Conv_Ovf_I: case ILCode.Conv_Ovf_I_Un: return HandleConversion(NativeInt, true, expr.Arguments[0], expectedType, typeSystem.IntPtr); case ILCode.Conv_U: case ILCode.Conv_Ovf_U: case ILCode.Conv_Ovf_U_Un: return HandleConversion(NativeInt, false, expr.Arguments[0], expectedType, typeSystem.UIntPtr); case ILCode.Conv_R4: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Single); } return typeSystem.Single; case ILCode.Conv_R8: if (forceInferChildren) { InferTypeForExpression(expr.Arguments[0], typeSystem.Double); } return typeSystem.Double; case ILCode.Conv_R_Un: return (expectedType != null && expectedType.ElementType == ElementType.R4) ? typeSystem.Single : typeSystem.Double; case ILCode.Castclass: case ILCode.Unbox_Any: return ((ITypeDefOrRef)expr.Operand).ToTypeSig(); case ILCode.Unbox: return new ByRefSig(((ITypeDefOrRef)expr.Operand).ToTypeSig()); case ILCode.Isinst: { // isinst performs the equivalent of a cast only for reference types; // value types still need to be unboxed after an isinst instruction TypeSig tr = ((ITypeDefOrRef)expr.Operand).ToTypeSig(); return DnlibExtensions.IsValueType(tr) ? typeSystem.Object : tr; } case ILCode.Box: { var tr = ((ITypeDefOrRef)expr.Operand).ToTypeSig(); if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), tr); return DnlibExtensions.IsValueType(tr) ? typeSystem.Object : tr; } #endregion #region Comparison instructions case ILCode.Ceq: case ILCode.Cne: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, null, null); return typeSystem.Boolean; case ILCode.Clt: case ILCode.Cgt: case ILCode.Cle: case ILCode.Cge: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, true, null); return typeSystem.Boolean; case ILCode.Clt_Un: case ILCode.Cgt_Un: case ILCode.Cle_Un: case ILCode.Cge_Un: if (forceInferChildren) InferArgumentsInBinaryOperator(expr, false, null); return typeSystem.Boolean; #endregion #region Branch instructions case ILCode.Brtrue: if (forceInferChildren) InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); return null; case ILCode.Br: case ILCode.Leave: case ILCode.Endfinally: case ILCode.Switch: case ILCode.Throw: case ILCode.Rethrow: case ILCode.LoopOrSwitchBreak: case ILCode.LoopContinue: case ILCode.YieldBreak: return null; case ILCode.Ret: if (forceInferChildren && expr.Arguments.Count == 1) { TypeSig returnType = context.CurrentMethod.ReturnType; if (context.CurrentMethodIsAsync && returnType != null && returnType.Namespace == "System.Threading.Tasks") { if (returnType.TypeName == "Task") { returnType = typeSystem.Void; } else if (returnType.TypeName == "Task`1" && returnType.IsGenericInstanceType) { returnType = ((GenericInstSig)returnType).GenericArguments[0]; } } InferTypeForExpression(expr.Arguments[0], returnType); } return null; case ILCode.YieldReturn: if (forceInferChildren) { GenericInstSig genericType = context.CurrentMethod.ReturnType as GenericInstSig; if (genericType != null) { // IEnumerable<T> or IEnumerator<T> InferTypeForExpression(expr.Arguments[0], genericType.GenericArguments[0]); } else { // non-generic IEnumerable or IEnumerator InferTypeForExpression(expr.Arguments[0], typeSystem.Object); } } return null; case ILCode.Await: { TypeSig taskType = InferTypeForExpression(expr.Arguments[0], null); if (taskType != null && taskType.TypeName == "Task`1" && taskType.IsGenericInstanceType && taskType.Namespace == "System.Threading.Tasks") { return ((GenericInstSig)taskType).GenericArguments[0]; } return null; } #endregion case ILCode.Pop: return null; case ILCode.Wrap: case ILCode.Dup: { var arg = expr.Arguments.Single(); return arg.ExpectedType = InferTypeForExpression(arg, expectedType); } default: Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName()); return null; } }
static bool OperandFitsInType(TypeSig type, int num) { type = GetEnumUnderlyingType(type) ?? type; switch (type.GetElementType()) { case ElementType.I1: return sbyte.MinValue <= num && num <= sbyte.MaxValue; case ElementType.I2: return short.MinValue <= num && num <= short.MaxValue; case ElementType.U1: return byte.MinValue <= num && num <= byte.MaxValue; case ElementType.Char: return char.MinValue <= num && num <= char.MaxValue; case ElementType.U2: return ushort.MinValue <= num && num <= ushort.MaxValue; default: return true; } }
Ast.Expression Convert(Ast.Expression expr, TypeSig actualType, TypeSig reqType) { if (actualType == null || reqType == null || TypeAnalysis.IsSameType(actualType, reqType)) { return expr; } else if (actualType is ByRefSig && reqType is PtrSig && expr is DirectionExpression) { return Convert( new UnaryOperatorExpression(UnaryOperatorType.AddressOf, ((DirectionExpression)expr).Expression.Detach()), new PtrSig(((ByRefSig)actualType).Next), reqType); } else if (actualType is PtrSig && reqType is ByRefSig) { expr = Convert(expr, actualType, new PtrSig(((ByRefSig)reqType).Next)); return new DirectionExpression { FieldDirection = FieldDirection.Ref, Expression = new UnaryOperatorExpression(UnaryOperatorType.Dereference, expr) }; } else if (actualType is PtrSig && reqType is PtrSig) { if (actualType.FullName != reqType.FullName) return expr.CastTo(AstBuilder.ConvertType(reqType)); else return expr; } else { bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(actualType); bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(reqType); if (reqType.GetElementType() == ElementType.Boolean) { if (actualType.GetElementType() == ElementType.Boolean) return expr; if (actualIsIntegerOrEnum) { return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, AstBuilder.MakePrimitive(0, actualType.ToTypeDefOrRef())); } else { return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, new NullReferenceExpression()); } } if (actualType.GetElementType() == ElementType.Boolean && requiredIsIntegerOrEnum) { return new ConditionalExpression { Condition = expr, TrueExpression = AstBuilder.MakePrimitive(1, reqType.ToTypeDefOrRef()), FalseExpression = AstBuilder.MakePrimitive(0, reqType.ToTypeDefOrRef()) }; } if (expr is PrimitiveExpression && !requiredIsIntegerOrEnum && TypeAnalysis.IsEnum(actualType)) { return expr.CastTo(AstBuilder.ConvertType(actualType)); } bool actualIsPrimitiveType = actualIsIntegerOrEnum || actualType.GetElementType() == ElementType.R4 || actualType.GetElementType() == ElementType.R8; bool requiredIsPrimitiveType = requiredIsIntegerOrEnum || reqType.GetElementType() == ElementType.R4 || reqType.GetElementType() == ElementType.R8; if (actualIsPrimitiveType && requiredIsPrimitiveType) { return expr.CastTo(AstBuilder.ConvertType(reqType)); } return expr; } }
internal static ITypeDefOrRef GetScopeType(TypeSig typeSig) { if (typeSig == null) return null; var scopeType = typeSig.ScopeType; if (scopeType != null) return scopeType; for (int i = 0; i < 100; i++) { var nls = typeSig as NonLeafSig; if (nls == null) break; typeSig = nls.Next; } switch (typeSig.GetElementType()) { case ElementType.MVar: case ElementType.Var: return new TypeSpecUser(typeSig); default: return null; } }
void Hash(TypeSig sig, int level) { if (sig == null) return; if (level++ > 20) return; hasher.Hash((byte)0x41); var etype = sig.GetElementType(); hasher.Hash((byte)etype); switch (etype) { case ElementType.Ptr: case ElementType.ByRef: case ElementType.SZArray: case ElementType.Pinned: Hash(sig.Next, level); break; case ElementType.Array: var arySig = (ArraySig)sig; hasher.Hash(arySig.Rank); hasher.Hash(arySig.Sizes.Count); hasher.Hash(arySig.LowerBounds.Count); Hash(sig.Next, level); break; case ElementType.CModReqd: case ElementType.CModOpt: Hash(((ModifierSig)sig).Modifier); Hash(sig.Next, level); break; case ElementType.ValueArray: hasher.Hash(((ValueArraySig)sig).Size); Hash(sig.Next, level); break; case ElementType.Module: hasher.Hash(((ModuleSig)sig).Index); Hash(sig.Next, level); break; case ElementType.GenericInst: var gis = (GenericInstSig)sig; Hash(gis.GenericType, level); foreach (var ga in gis.GenericArguments) Hash(ga, level); Hash(sig.Next, level); break; case ElementType.FnPtr: Hash(((FnPtrSig)sig).Signature); break; case ElementType.Var: case ElementType.MVar: hasher.Hash(((GenericSig)sig).Number); break; case ElementType.ValueType: case ElementType.Class: Hash(((TypeDefOrRefSig)sig).TypeDefOrRef); break; case ElementType.End: case ElementType.Void: case ElementType.Boolean: case ElementType.Char: case ElementType.I1: case ElementType.U1: case ElementType.I2: case ElementType.U2: case ElementType.I4: case ElementType.U4: case ElementType.I8: case ElementType.U8: case ElementType.R4: case ElementType.R8: case ElementType.String: case ElementType.TypedByRef: case ElementType.I: case ElementType.U: case ElementType.R: case ElementType.Object: case ElementType.Internal: case ElementType.Sentinel: default: break; } }