385
385
case ILCode.Ldobj:
387
387
TypeReference type = (TypeReference)expr.Operand;
388
if (expectedType != null) {
389
int infoAmount = GetInformationAmount(expectedType);
388
var argType = InferTypeForExpression(expr.Arguments[0], null);
389
if (argType is PointerType || argType is ByReferenceType) {
390
var elementType = ((TypeSpecification)argType).ElementType;
391
int infoAmount = GetInformationAmount(elementType);
390
392
if (infoAmount == 1 && GetInformationAmount(type) == 8) {
391
393
// A bool can be loaded from both bytes and sbytes.
394
396
if (infoAmount >= 8 && infoAmount <= 64 && infoAmount == GetInformationAmount(type)) {
395
397
// An integer can be loaded as another integer of the same size.
396
398
// For integers smaller than 32 bit, the signs must match (as loading performs sign extension)
397
if (infoAmount >= 32 || IsSigned(expectedType) == IsSigned(type))
399
bool? elementTypeIsSigned = IsSigned(elementType);
400
bool? typeIsSigned = IsSigned(type);
401
if (elementTypeIsSigned != null && typeIsSigned != null) {
402
if (infoAmount >= 32 || elementTypeIsSigned == typeIsSigned)
401
if (forceInferChildren) {
402
if (InferTypeForExpression(expr.Arguments[0], new ByReferenceType(type)) is PointerType)
403
InferTypeForExpression(expr.Arguments[0], new PointerType(type));
407
if (argType is PointerType)
408
InferTypeForExpression(expr.Arguments[0], new PointerType(type));
410
InferTypeForExpression(expr.Arguments[0], new ByReferenceType(type));
407
413
case ILCode.Stobj:
607
613
#region Array instructions
608
614
case ILCode.Newarr:
609
if (forceInferChildren)
610
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32);
615
if (forceInferChildren) {
616
var lengthType = InferTypeForExpression(expr.Arguments.Single(), null);
617
if (lengthType == typeSystem.IntPtr) {
618
lengthType = typeSystem.Int64;
619
} else if (lengthType == typeSystem.UIntPtr) {
620
lengthType = typeSystem.UInt64;
621
} else if (lengthType != typeSystem.UInt32 && lengthType != typeSystem.Int64 && lengthType != typeSystem.UInt64) {
622
lengthType = typeSystem.Int32;
624
if (forceInferChildren) {
625
InferTypeForExpression(expr.Arguments.Single(), lengthType);
611
628
return new ArrayType((TypeReference)expr.Operand);
612
629
case ILCode.InitArray:
613
630
var operandAsArrayType = (ArrayType)expr.Operand;
779
796
case ILCode.YieldBreak:
782
if (forceInferChildren && expr.Arguments.Count == 1)
783
InferTypeForExpression(expr.Arguments[0], context.CurrentMethod.ReturnType);
799
if (forceInferChildren && expr.Arguments.Count == 1) {
800
TypeReference returnType = context.CurrentMethod.ReturnType;
801
if (context.CurrentMethodIsAsync && returnType != null && returnType.Namespace == "System.Threading.Tasks") {
802
if (returnType.Name == "Task") {
803
returnType = typeSystem.Void;
804
} else if (returnType.Name == "Task`1" && returnType.IsGenericInstance) {
805
returnType = ((GenericInstanceType)returnType).GenericArguments[0];
808
InferTypeForExpression(expr.Arguments[0], returnType);
785
811
case ILCode.YieldReturn:
786
812
if (forceInferChildren) {
974
1008
InferTypeForExpression(right, typeSystem.IntPtr);
975
1009
return leftPreferred;
1011
if (IsEnum(leftPreferred)) {
1013
left.InferredType = left.ExpectedType = leftPreferred;
1014
InferTypeForExpression(right, GetEnumUnderlyingType(leftPreferred));
1015
return leftPreferred;
977
1017
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
978
1018
if (rightPreferred is PointerType) {
979
1019
InferTypeForExpression(left, typeSystem.IntPtr);
980
1020
right.InferredType = right.ExpectedType = rightPreferred;
981
1021
return rightPreferred;
1023
if (IsEnum(rightPreferred)) {
1025
right.InferredType = right.ExpectedType = rightPreferred;
1026
InferTypeForExpression(left, GetEnumUnderlyingType(rightPreferred));
1027
return rightPreferred;
983
1029
return InferBinaryArguments(left, right, expectedType, leftPreferred: leftPreferred, rightPreferred: rightPreferred);
993
1039
InferTypeForExpression(right, typeSystem.IntPtr);
994
1040
return leftPreferred;
1042
if (IsEnum(leftPreferred)) {
1043
if (expectedType != null && IsEnum(expectedType)) {
1045
left.InferredType = left.ExpectedType = leftPreferred;
1046
InferTypeForExpression(right, GetEnumUnderlyingType(leftPreferred));
1047
return leftPreferred;
1050
left.InferredType = left.ExpectedType = leftPreferred;
1051
InferTypeForExpression(right, leftPreferred);
1052
return GetEnumUnderlyingType(leftPreferred);
996
1055
return InferBinaryArguments(left, right, expectedType, leftPreferred: leftPreferred);
1036
1095
public const int NativeInt = 33; // treat native int as between int32 and int64
1098
/// Gets the underlying type, if the specified type is an enum.
1099
/// Otherwise, returns null.
1101
public static TypeReference GetEnumUnderlyingType(TypeReference enumType)
1103
// unfortunately we cannot rely on enumType.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec)
1104
if (enumType != null && !IsArrayPointerOrReference(enumType)) {
1105
// value type might be an enum
1106
TypeDefinition typeDef = enumType.Resolve() as TypeDefinition;
1107
if (typeDef != null && typeDef.IsEnum) {
1108
return typeDef.Fields.Single(f => !f.IsStatic).FieldType;
1038
1114
public static int GetInformationAmount(TypeReference type)
1116
type = GetEnumUnderlyingType(type) ?? type;
1040
1117
if (type == null)
1042
if (type.IsValueType && !IsArrayPointerOrReference(type)) {
1043
// value type might be an enum
1044
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
1045
if (typeDef != null && typeDef.IsEnum) {
1046
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
1047
return GetInformationAmount(underlyingType);
1050
1119
switch (type.MetadataType) {
1051
1120
case MetadataType.Void:
1099
1168
static bool? IsSigned(TypeReference type)
1101
if (type == null || IsArrayPointerOrReference(type))
1170
type = GetEnumUnderlyingType(type) ?? type;
1103
// unfortunately we cannot rely on type.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec)
1104
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
1105
if (typeDef != null && typeDef.IsEnum) {
1106
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
1107
return IsSigned(underlyingType);
1109
1173
switch (type.MetadataType) {
1110
1174
case MetadataType.SByte:
1111
1175
case MetadataType.Int16:
1128
1192
static bool OperandFitsInType(TypeReference type, int num)
1130
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
1131
if (typeDef != null && typeDef.IsEnum) {
1132
type = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
1194
type = GetEnumUnderlyingType(type) ?? type;
1134
1195
switch (type.MetadataType) {
1135
1196
case MetadataType.SByte:
1136
1197
return sbyte.MinValue <= num && num <= sbyte.MaxValue;