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;
 }
Example #2
0
		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;
			}
		}
Example #3
0
		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;
			}
		}
Example #4
0
		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;
			}
		}
Example #5
0
		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;
			}
		}
Example #6
0
		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;
			}
		}