Esempio n. 1
0
		//
		// 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);
		}
Esempio n. 2
0
		//
		// 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);
		}
Esempio n. 3
0
		//
		// 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;
		}
Esempio n. 4
0
		public virtual object Visit (EmptyExpression emptyExpression)
		{
			return null;
		}
Esempio n. 5
0
		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);
			}
		}
Esempio n. 6
0
        //
        // 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;
        }
Esempio n. 7
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;
		}
Esempio n. 8
0
		/// <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);
		}
Esempio n. 9
0
		/// <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;
		}
Esempio n. 10
0
		public static EmptyExpression Grab ()
		{
			EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
			temp = null;
			return retval;
		}
Esempio n. 11
0
		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;
		}
Esempio n. 12
0
		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;
		}
Esempio n. 13
0
File: generic.cs Progetto: ikvm/mono
		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 ());
				}
			}
		}
Esempio n. 14
0
		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;
		}
Esempio n. 15
0
		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);
			}
		}
Esempio n. 16
0
		public static void Reset ()
		{
			MyEmptyExpr = null;
		}
Esempio n. 17
0
		public static void Release (EmptyExpression e)
		{
			temp = e;
		}
Esempio n. 18
0
 public static void Reset()
 {
     MyEmptyExpr = null;
     explicit_conv = new DoubleHash (100);
     implicit_conv = new DoubleHash (100);
 }
Esempio n. 19
0
		//
		// 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;
		}
Esempio n. 20
0
        //
        // 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;
        }
Esempio n. 21
0
		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);
			}
		}
Esempio n. 22
0
		/// <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;
		}