// // From a one-dimensional array-type S[] to System.Collections.IList<T> and base // interfaces of this interface, provided there is an implicit reference conversion // from S to T. // static bool Array_To_IList (Type array, Type list, bool isExplicit) { if ((array.GetArrayRank () != 1) || !TypeManager.IsGenericType (list)) return false; Type gt = TypeManager.DropGenericTypeArguments (list); if ((gt != TypeManager.generic_ilist_type) && (gt != TypeManager.generic_icollection_type) && (gt != TypeManager.generic_ienumerable_type)) return false; Type element_type = TypeManager.GetElementType (array); Type arg_type = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (list) [0]); if (element_type == arg_type) return true; if (isExplicit) return ExplicitReferenceConversionExists (element_type, arg_type); Type t = TypeManager.GetElementType (array); if (MyEmptyExpr == null) MyEmptyExpr = new EmptyExpression (t); else MyEmptyExpr.SetType (t); return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type); }
// // From a one-dimensional array-type S[] to System.Collections.IList<T> and base // interfaces of this interface, provided there is an implicit reference conversion // from S to T. // static bool ArrayToIList (ArrayContainer array, TypeSpec list, bool isExplicit) { if (array.Rank != 1 || !list.IsGeneric) return false; var open_version = list.GetDefinition (); if ((open_version != TypeManager.generic_ilist_type) && (open_version != TypeManager.generic_icollection_type) && (open_version != TypeManager.generic_ienumerable_type)) return false; var arg_type = list.TypeArguments[0]; if (array.Element == arg_type) return true; if (isExplicit) return ExplicitReferenceConversionExists (array.Element, arg_type); if (MyEmptyExpr == null) MyEmptyExpr = new EmptyExpression (array.Element); else MyEmptyExpr.SetType (array.Element); return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type); }
// // 6.1.6 Implicit reference conversions // public static bool ImplicitReferenceConversionExists (Expression expr, TypeSpec target_type) { if (TypeManager.IsStruct (target_type)) return false; TypeSpec expr_type = expr.Type; // from the null type to any reference-type. if (expr_type == InternalType.Null) return target_type != InternalType.AnonymousMethod; if (TypeManager.IsGenericParameter (expr_type)) return ImplicitTypeParameterConversion (expr, target_type) != null; // This code is kind of mirrored inside ImplicitStandardConversionExists // with the small distinction that we only probe there // // Always ensure that the code here and there is in sync // from any class-type S to any interface-type T. if (target_type.IsInterface) { if (expr_type.ImplementsInterface (target_type, true)){ return !TypeManager.IsValueType (expr_type); } } // // Implicit reference conversions (no-boxing) to object or dynamic // if (target_type == TypeManager.object_type || target_type == InternalType.Dynamic) { switch (expr_type.Kind) { case MemberKind.Class: case MemberKind.Interface: case MemberKind.Delegate: case MemberKind.ArrayType: return true; } return expr_type == InternalType.Dynamic; } if (target_type == TypeManager.value_type) { return expr_type == TypeManager.enum_type; } else if (expr_type == target_type || TypeSpec.IsBaseClass (expr_type, target_type, true)) { // // Special case: enumeration to System.Enum. // System.Enum is not a value type, it is a class, so we need // a boxing conversion // if (target_type == TypeManager.enum_type || TypeManager.IsGenericParameter (expr_type)) return false; if (TypeManager.IsValueType (expr_type)) return false; // Array type variance conversion //if (target_type.IsArray != expr_type.IsArray) // return false; return true; } var expr_type_array = expr_type as ArrayContainer; if (expr_type_array != null) { var target_type_array = target_type as ArrayContainer; // from an array-type S to an array-type of type T if (target_type_array != null && expr_type_array.Rank == target_type_array.Rank) { // // Both SE and TE are reference-types // TypeSpec expr_element_type = expr_type_array.Element; if (!TypeManager.IsReferenceType (expr_element_type)) return false; TypeSpec target_element_type = target_type_array.Element; if (!TypeManager.IsReferenceType (target_element_type)) return false; if (MyEmptyExpr == null) MyEmptyExpr = new EmptyExpression (expr_element_type); else MyEmptyExpr.SetType (expr_element_type); return ImplicitStandardConversionExists (MyEmptyExpr, target_element_type); } // from an array-type to System.Array if (target_type == TypeManager.array_type) return true; // from an array-type of type T to IList<T> if (ArrayToIList (expr_type_array, target_type, false)) return true; return false; } if (TypeSpecComparer.IsEqual (expr_type, target_type)) return true; if (TypeSpecComparer.Variant.IsEqual (expr_type, target_type)) return true; // from any interface type S to interface-type T. if (expr_type.IsInterface && target_type.IsInterface) { return expr_type.ImplementsInterface (target_type, true); } // from any delegate type to System.Delegate if (target_type == TypeManager.delegate_type && (expr_type == TypeManager.delegate_type || expr_type.IsDelegate)) return true; return false; }
public virtual object Visit (EmptyExpression emptyExpression) { return null; }
public override bool Resolve (BlockContext ec) { using (ec.With (ResolveContext.Options.CatchScope, true)) { if (type_expr != null) { TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false); if (te == null) return false; type = te.Type; if (type != TypeManager.exception_type && !TypeSpec.IsBaseClass (type, TypeManager.exception_type, false)) { ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception"); } else if (li != null) { li.Type = type; li.PrepareForFlowAnalysis (ec); // source variable is at the top of the stack Expression source = new EmptyExpression (li.Type); if (li.Type.IsGenericParameter) source = new UnboxCast (source, li.Type); assign = new CompilerAssign (new LocalVariableReference (li, loc), source, loc); Block.AddScopeStatement (new StatementExpression (assign)); } } return Block.Resolve (ec); } }
// // 7.4.3.4 Better conversion from type // public static int BetterTypeConversion(ResolveContext ec, TypeSpec p, TypeSpec q) { if (p == null || q == null) throw new InternalErrorException ("BetterTypeConversion got a null conversion"); if (p == TypeManager.int32_type) { if (q == TypeManager.uint32_type || q == TypeManager.uint64_type) return 1; } else if (p == TypeManager.int64_type) { if (q == TypeManager.uint64_type) return 1; } else if (p == TypeManager.sbyte_type) { if (q == TypeManager.byte_type || q == TypeManager.ushort_type || q == TypeManager.uint32_type || q == TypeManager.uint64_type) return 1; } else if (p == TypeManager.short_type) { if (q == TypeManager.ushort_type || q == TypeManager.uint32_type || q == TypeManager.uint64_type) return 1; } else if (p == InternalType.Dynamic) { if (q == TypeManager.object_type) return 2; } if (q == TypeManager.int32_type) { if (p == TypeManager.uint32_type || p == TypeManager.uint64_type) return 2; } if (q == TypeManager.int64_type) { if (p == TypeManager.uint64_type) return 2; } else if (q == TypeManager.sbyte_type) { if (p == TypeManager.byte_type || p == TypeManager.ushort_type || p == TypeManager.uint32_type || p == TypeManager.uint64_type) return 2; } if (q == TypeManager.short_type) { if (p == TypeManager.ushort_type || p == TypeManager.uint32_type || p == TypeManager.uint64_type) return 2; } else if (q == InternalType.Dynamic) { if (p == TypeManager.object_type) return 1; } // TODO: this is expensive Expression p_tmp = new EmptyExpression (p); Expression q_tmp = new EmptyExpression (q); bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q); bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p); if (p_to_q && !q_to_p) return 1; if (q_to_p && !p_to_q) return 2; return 0; }
/// <summary> /// Finds "most encompassing type" according to the spec (13.4.2) /// amongst the types in the given set /// </summary> static TypeSpec FindMostEncompassingType (IList<TypeSpec> types) { TypeSpec best = null; if (types.Count == 0) return null; if (types.Count == 1) return types [0]; foreach (TypeSpec t in types) { if (best == null) { best = t; continue; } var expr = new EmptyExpression (best); if (ImplicitStandardConversionExists (expr, t)) best = t; } foreach (TypeSpec t in types) { if (best == t) continue; var expr = new EmptyExpression (best); if (!ImplicitStandardConversionExists (expr, best)) { best = null; break; } } return best; }
/// <summary> /// Finds the most specific target Tx according to section 13.4.4 /// </summary> static public TypeSpec FindMostSpecificTarget (IList<MethodSpec> list, TypeSpec target, bool apply_explicit_conv_rules) { var tgt_types_set = new List<TypeSpec> (); // // If any operator converts to T then Tx = T // foreach (var mi in list){ TypeSpec ret_type = mi.ReturnType; if (ret_type == target) return ret_type; tgt_types_set.Add (ret_type); } // // Explicit conv rules // if (apply_explicit_conv_rules) { var candidate_set = new List<TypeSpec> (); foreach (TypeSpec ret_type in tgt_types_set) { var expr = new EmptyExpression (ret_type); if (ImplicitStandardConversionExists (expr, target)) candidate_set.Add (ret_type); } if (candidate_set.Count != 0) return FindMostEncompassingType (candidate_set); } // // Okay, final case ! // if (apply_explicit_conv_rules) return FindMostEncompassedType (tgt_types_set); else return FindMostEncompassingType (tgt_types_set); }
/// <summary> /// Finds "most encompassed type" according to the spec (13.4.2) /// amongst the methods in the MethodGroupExpr /// </summary> public static TypeSpec FindMostEncompassedType (IList<TypeSpec> types) { TypeSpec best = null; EmptyExpression expr; foreach (TypeSpec t in types) { if (best == null) { best = t; continue; } expr = new EmptyExpression (t); if (ImplicitStandardConversionExists (expr, best)) best = t; } expr = new EmptyExpression (best); foreach (TypeSpec t in types) { if (best == t) continue; if (!ImplicitStandardConversionExists (expr, t)) { best = null; break; } } return best; }
public static EmptyExpression Grab () { EmptyExpression retval = temp == null ? new EmptyExpression () : temp; temp = null; return retval; }
public override Expression DoResolve (ResolveContext ec) { MethodInfo method = (MethodInfo)mg; type = TypeManager.TypeToCoreType (method.ReturnType); AParametersCollection pd = TypeManager.GetParameterData (method); if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) { ec.Report.Error (217, loc, "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator", TypeManager.CSharpSignature (method)); return null; } Expression left_dup = new EmptyExpression (type); Expression op_true = GetOperatorTrue (ec, left_dup, loc); Expression op_false = GetOperatorFalse (ec, left_dup, loc); if (op_true == null || op_false == null) { ec.Report.Error (218, loc, "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator", TypeManager.CSharpName (type), TypeManager.CSharpSignature (method)); return null; } oper = is_and ? op_false : op_true; eclass = ExprClass.Value; return this; }
protected bool CheckConstraints (IResolveContext ec, int index) { Type atype = atypes [index]; Type ptype = gen_params [index]; if (atype == ptype) return true; Expression aexpr = new EmptyExpression (atype); GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype); if (gc == null) return true; bool is_class, is_struct; if (atype.IsGenericParameter) { GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype); if (agc != null) { if (agc is Constraints) ((Constraints) agc).Resolve (ec); is_class = agc.IsReferenceType; is_struct = agc.IsValueType; } else { is_class = is_struct = false; } } else { #if MS_COMPATIBLE is_class = false; if (!atype.IsGenericType) #endif is_class = atype.IsClass || atype.IsInterface; is_struct = atype.IsValueType && !TypeManager.IsNullableType (atype); } // // First, check the `class' and `struct' constraints. // if (gc.HasReferenceTypeConstraint && !is_class) { Report.Error (452, loc, "The type `{0}' must be " + "a reference type in order to use it " + "as type parameter `{1}' in the " + "generic type or method `{2}'.", TypeManager.CSharpName (atype), TypeManager.CSharpName (ptype), GetSignatureForError ()); return false; } else if (gc.HasValueTypeConstraint && !is_struct) { Report.Error (453, loc, "The type `{0}' must be a " + "non-nullable value type in order to use it " + "as type parameter `{1}' in the " + "generic type or method `{2}'.", TypeManager.CSharpName (atype), TypeManager.CSharpName (ptype), GetSignatureForError ()); return false; } // // The class constraint comes next. // if (gc.HasClassConstraint) { if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint)) return false; } // // Now, check the interface constraints. // if (gc.InterfaceConstraints != null) { foreach (Type it in gc.InterfaceConstraints) { if (!CheckConstraint (ec, ptype, aexpr, it)) return false; } } // // Finally, check the constructor constraint. // if (!gc.HasConstructorConstraint) return true; if (TypeManager.IsBuiltinType (atype) || atype.IsValueType) return true; if (HasDefaultConstructor (atype)) return true; Report_SymbolRelatedToPreviousError (); Report.SymbolRelatedToPreviousError (atype); Report.Error (310, loc, "The type `{0}' must have a public " + "parameterless constructor in order to use it " + "as parameter `{1}' in the generic type or " + "method `{2}'", TypeManager.CSharpName (atype), TypeManager.CSharpName (ptype), GetSignatureForError ()); return false; }
static void CheckConversion (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc) { var expr = new EmptyExpression (atype); if (!Convert.ImplicitStandardConversionExists (expr, ttype)) { mc.Compiler.Report.SymbolRelatedToPreviousError (tparam); if (TypeManager.IsValueType (atype)) { mc.Compiler.Report.Error (315, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing conversion from `{0}' to `{3}'", atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); } else if (atype.IsGenericParameter) { mc.Compiler.Report.Error (314, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing or type parameter conversion from `{0}' to `{3}'", atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); } else { mc.Compiler.Report.Error (311, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no implicit reference conversion from `{0}' to `{3}'", atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); } } }
protected bool CheckConstraints (IMemberContext ec, int index) { Type atype = atypes [index]; Type ptype = gen_params [index]; if (atype == ptype) return true; Expression aexpr = new EmptyExpression (atype); GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype); if (gc == null) return true; bool is_class, is_struct; if (atype.IsGenericParameter) { GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype); if (agc != null) { if (agc is Constraints) { // FIXME: No constraints can be resolved here, we are in // completely wrong/different context. This path is hit // when resolving base type of unresolved generic type // with constraints. We are waiting with CheckConsttraints // after type-definition but not in this case if (!((Constraints) agc).Resolve (null, null, Report)) return true; } is_class = agc.IsReferenceType; is_struct = agc.IsValueType; } else { is_class = is_struct = false; } } else { is_class = TypeManager.IsReferenceType (atype); is_struct = TypeManager.IsValueType (atype) && !TypeManager.IsNullableType (atype); } // // First, check the `class' and `struct' constraints. // if (gc.HasReferenceTypeConstraint && !is_class) { Report.Error (452, loc, "The type `{0}' must be " + "a reference type in order to use it " + "as type parameter `{1}' in the " + "generic type or method `{2}'.", TypeManager.CSharpName (atype), TypeManager.CSharpName (ptype), GetSignatureForError ()); return false; } else if (gc.HasValueTypeConstraint && !is_struct) { Report.Error (453, loc, "The type `{0}' must be a " + "non-nullable value type in order to use it " + "as type parameter `{1}' in the " + "generic type or method `{2}'.", TypeManager.CSharpName (atype), TypeManager.CSharpName (ptype), GetSignatureForError ()); return false; } // // The class constraint comes next. // if (gc.HasClassConstraint) { if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint)) return false; } // // Now, check the interface constraints. // if (gc.InterfaceConstraints != null) { foreach (Type it in gc.InterfaceConstraints) { if (!CheckConstraint (ec, ptype, aexpr, it)) return false; } } // // Finally, check the constructor constraint. // if (!gc.HasConstructorConstraint) return true; if (TypeManager.IsValueType (atype)) return true; if (HasDefaultConstructor (atype)) return true; Report_SymbolRelatedToPreviousError (); Report.SymbolRelatedToPreviousError (atype); Report.Error (310, loc, "The type `{0}' must have a public " + "parameterless constructor in order to use it " + "as parameter `{1}' in the generic type or " + "method `{2}'", TypeManager.CSharpName (atype), TypeManager.CSharpName (ptype), GetSignatureForError ()); return false; }
static void FindApplicableUserDefinedConversionOperators (IList<MemberSpec> operators, Expression source, TypeSpec target, bool implicitOnly, ref List<MethodSpec> candidates) { // // LAMESPEC: Undocumented IntPtr/UIntPtr conversions // IntPtr -> uint uses int // UIntPtr -> long uses ulong // if (source.Type == TypeManager.intptr_type) { if (target == TypeManager.uint32_type) target = TypeManager.int32_type; } else if (source.Type == TypeManager.uintptr_type) { if (target == TypeManager.int64_type) target = TypeManager.uint64_type; } // For a conversion operator to be applicable, it must be possible // to perform a standard conversion from the source type to // the operand type of the operator, and it must be possible // to perform a standard conversion from the result type of // the operator to the target type. Expression texpr = null; foreach (MethodSpec op in operators) { // Can be null because MemberCache.GetUserOperator does not resize the array if (op == null) continue; var t = op.Parameters.Types[0]; if (source.Type != t && !ImplicitStandardConversionExists (source, t)) { if (implicitOnly) continue; if (!ImplicitStandardConversionExists (new EmptyExpression (t), source.Type)) continue; } t = op.ReturnType; // LAMESPEC: Exclude UIntPtr -> int conversion if (t == TypeManager.uint32_type && source.Type == TypeManager.uintptr_type) continue; if (target != t && !ImplicitStandardConversionExists (new EmptyExpression (t), target)) { if (implicitOnly) continue; if (texpr == null) texpr = new EmptyExpression (target); if (!ImplicitStandardConversionExists (texpr, t)) continue; } if (candidates == null) candidates = new List<MethodSpec> (); candidates.Add (op); } }
public static void Reset () { MyEmptyExpr = null; }
public static void Release (EmptyExpression e) { temp = e; }
public static void Reset() { MyEmptyExpr = null; explicit_conv = new DoubleHash (100); implicit_conv = new DoubleHash (100); }
// // Finds the most encompassing type (type into which all other // types can convert to) amongst the types in the given set // static TypeSpec FindMostEncompassingType (IList<TypeSpec> types) { if (types.Count == 0) return null; if (types.Count == 1) return types [0]; TypeSpec best = null; for (int i = 0; i < types.Count; ++i) { int ii = 0; for (; ii < types.Count; ++ii) { if (ii == i) continue; var expr = new EmptyExpression (types[ii]); if (!ImplicitStandardConversionExists (expr, types [i])) { ii = 0; break; } } if (ii == 0) continue; if (best == null) { best = types[i]; continue; } // Indicates multiple best types return InternalType.FakeInternalType; } return best; }
// // 6.1.6 Implicit reference conversions // public static bool ImplicitReferenceConversionExists(Expression expr, TypeSpec target_type) { if (TypeManager.IsStruct (target_type)) return false; TypeSpec expr_type = expr.Type; // from the null type to any reference-type. if (expr_type == TypeManager.null_type) return target_type != InternalType.AnonymousMethod; if (TypeManager.IsGenericParameter (expr_type)) return ImplicitTypeParameterConversion (expr, target_type) != null; // This code is kind of mirrored inside ImplicitStandardConversionExists // with the small distinction that we only probe there // // Always ensure that the code here and there is in sync // from any class-type S to any interface-type T. if (target_type.IsInterface) { if (expr_type.ImplementsInterface (target_type)){ return !TypeManager.IsValueType (expr_type); } } // // notice that it is possible to write "ValueType v = 1", the ValueType here // is an abstract class, and not really a value type, so we apply the same rules. // if (target_type == TypeManager.object_type || target_type == InternalType.Dynamic) { // // A pointer type cannot be converted to object // if (expr_type.IsPointer) return false; if (TypeManager.IsValueType (expr_type)) return false; if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type || expr_type.IsDelegate) { // No mcs internal types are convertible return true; // expr_type.MetaInfo.Module != typeof (Convert).Module; } // From anything to dynamic if (target_type == InternalType.Dynamic) return true; // From dynamic to object if (expr_type == InternalType.Dynamic) return true; return false; } else if (target_type == TypeManager.value_type) { return expr_type == TypeManager.enum_type; } else if (TypeManager.IsSubclassOf (expr_type, target_type)) { // // Special case: enumeration to System.Enum. // System.Enum is not a value type, it is a class, so we need // a boxing conversion // if (target_type == TypeManager.enum_type || TypeManager.IsGenericParameter (expr_type)) return false; if (TypeManager.IsValueType (expr_type)) return false; // Array type variance conversion //if (target_type.IsArray != expr_type.IsArray) // return false; return true; } var expr_type_array = expr_type as ArrayContainer; if (expr_type_array != null) { var target_type_array = target_type as ArrayContainer; // from an array-type S to an array-type of type T if (target_type_array != null && expr_type_array.Rank == target_type_array.Rank) { // // Both SE and TE are reference-types // TypeSpec expr_element_type = expr_type_array.Element; if (!TypeManager.IsReferenceType (expr_element_type)) return false; TypeSpec target_element_type = target_type_array.Element; if (!TypeManager.IsReferenceType (target_element_type)) return false; if (MyEmptyExpr == null) MyEmptyExpr = new EmptyExpression (expr_element_type); else MyEmptyExpr.SetType (expr_element_type); return ImplicitStandardConversionExists (MyEmptyExpr, target_element_type); } // from an array-type to System.Array if (target_type == TypeManager.array_type) return true; // from an array-type of type T to IList<T> if (ArrayToIList (expr_type_array, target_type, false)) return true; return false; } if (TypeSpecComparer.Variant.IsEqual (expr_type, target_type)) return true; // from any interface type S to interface-type T. if (expr_type.IsInterface && target_type.IsInterface) { return expr_type.ImplementsInterface (target_type); } // from any delegate type to System.Delegate if (target_type == TypeManager.delegate_type && (expr_type == TypeManager.delegate_type || expr_type.IsDelegate)) return true; if (TypeManager.IsEqual (expr_type, target_type)) return true; return false; }
static void FindApplicableUserDefinedConversionOperators (IList<MemberSpec> operators, Expression source, TypeSpec target, bool implicitOnly, ref List<MethodSpec> candidates) { if (source.Type.IsInterface) { // Neither A nor B are interface-types return; } // For a conversion operator to be applicable, it must be possible // to perform a standard conversion from the source type to // the operand type of the operator, and it must be possible // to perform a standard conversion from the result type of // the operator to the target type. Expression texpr = null; foreach (MethodSpec op in operators) { // Can be null because MemberCache.GetUserOperator does not resize the array if (op == null) continue; var t = op.Parameters.Types[0]; if (source.Type != t && !ImplicitStandardConversionExists (source, t)) { if (implicitOnly) continue; if (!ImplicitStandardConversionExists (new EmptyExpression (t), source.Type)) continue; } t = op.ReturnType; if (t.IsInterface) continue; if (target != t) { if (t.IsNullableType) t = Nullable.NullableInfo.GetUnderlyingType (t); if (!ImplicitStandardConversionExists (new EmptyExpression (t), target)) { if (implicitOnly) continue; if (texpr == null) texpr = new EmptyExpression (target); if (!ImplicitStandardConversionExists (texpr, t)) continue; } } if (candidates == null) candidates = new List<MethodSpec> (); candidates.Add (op); } }
/// <summary> /// Determines "better conversion" as specified in 7.4.2.3 /// Returns : 1 if a->p is better /// 0 if a->q or neither is better /// </summary> static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc) { Type argument_type = a.Type; Expression argument_expr = a.Expr; if (argument_type == null) throw new Exception ("Expression of type " + a.Expr + " does not resolve its type"); // // This is a special case since csc behaves this way. I can't find // it anywhere in the spec but oh well ... // if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type) return 1; else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type) return 0; if (p == q) return 0; if (argument_type == p) return 1; if (argument_type == q) return 0; // // Now probe whether an implicit constant expression conversion // can be used. // // An implicit constant expression conversion permits the following // conversions: // // * A constant-expression of type `int' can be converted to type // sbyte, byute, short, ushort, uint, ulong provided the value of // of the expression is withing the range of the destination type. // // * A constant-expression of type long can be converted to type // ulong, provided the value of the constant expression is not negative // // FIXME: Note that this assumes that constant folding has // taken place. We dont do constant folding yet. // if (argument_expr is IntConstant){ IntConstant ei = (IntConstant) argument_expr; int value = ei.Value; if (p == TypeManager.sbyte_type){ if (value >= SByte.MinValue && value <= SByte.MaxValue) return 1; } else if (p == TypeManager.byte_type){ if (q == TypeManager.sbyte_type && value >= SByte.MinValue && value <= SByte.MaxValue) return 0; else if (Byte.MinValue >= 0 && value <= Byte.MaxValue) return 1; } else if (p == TypeManager.short_type){ if (value >= Int16.MinValue && value <= Int16.MaxValue) return 1; } else if (p == TypeManager.ushort_type){ if (q == TypeManager.short_type && value >= Int16.MinValue && value <= Int16.MaxValue) return 0; else if (value >= UInt16.MinValue && value <= UInt16.MaxValue) return 1; } else if (p == TypeManager.int32_type){ if (value >= Int32.MinValue && value <= Int32.MaxValue) return 1; } else if (p == TypeManager.uint32_type){ // // we can optimize this case: a positive int32 // always fits on a uint32 // if (value >= 0) return 1; } else if (p == TypeManager.uint64_type){ // // we can optimize this case: a positive int32 // always fits on a uint64 // if (q == TypeManager.int64_type) return 0; else if (value >= 0) return 1; } else if (p == TypeManager.int64_type){ return 1; } } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){ LongConstant lc = (LongConstant) argument_expr; if (p == TypeManager.uint64_type){ if (lc.Value > 0) return 1; } } if (q == null) { Expression tmp = ConvertImplicit (ec, argument_expr, p, loc); if (tmp != null) return 1; else return 0; } Expression p_tmp = new EmptyExpression (p); Expression q_tmp = new EmptyExpression (q); if (ImplicitConversionExists (ec, p_tmp, q) == true && ImplicitConversionExists (ec, q_tmp, p) == false) return 1; if (p == TypeManager.sbyte_type) if (q == TypeManager.byte_type || q == TypeManager.ushort_type || q == TypeManager.uint32_type || q == TypeManager.uint64_type) return 1; if (p == TypeManager.short_type) if (q == TypeManager.ushort_type || q == TypeManager.uint32_type || q == TypeManager.uint64_type) return 1; if (p == TypeManager.int32_type) if (q == TypeManager.uint32_type || q == TypeManager.uint64_type) return 1; if (p == TypeManager.int64_type) if (q == TypeManager.uint64_type) return 1; return 0; }