static Expression ImplicitTypeParameterConversion (Expression expr, TypeSpec target_type)
{
var expr_type = (TypeParameterSpec) expr.Type;
+
//
- // From T to a type parameter U
+ // From T to a type parameter U, provided T depends on U
//
var ttype = target_type as TypeParameterSpec;
if (ttype != null) {
- if (expr_type.IsReferenceType && !ttype.IsReferenceType)
- return new BoxedCast (expr, target_type);
+ if (expr_type.TypeArguments != null) {
+ foreach (var targ in expr_type.TypeArguments) {
+ if (!TypeSpecComparer.Override.IsEqual (ttype, targ))
+ continue;
+
+ if (expr_type.IsReferenceType && !ttype.IsReferenceType)
+ return new BoxedCast (expr, target_type);
+
+ return new ClassCast (expr, target_type);
+ }
+ }
+
+ return null;
+ }
- return new ClassCast (expr, target_type);
+ //
+ // LAMESPEC: From T to dynamic type
+ //
+ if (target_type == InternalType.Dynamic) {
+ if (expr_type.IsReferenceType)
+ return new ClassCast (expr, target_type);
+
+ return new BoxedCast (expr, target_type);
}
//
{
var target_tp = target_type as TypeParameterSpec;
if (target_tp != null) {
+ if (target_tp.TypeArguments != null) {
+ foreach (var targ in target_tp.TypeArguments) {
+ if (!TypeSpecComparer.Override.IsEqual (source_type, targ))
+ continue;
+
+ return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
+ }
+ }
+
if (target_tp.Interfaces != null) {
foreach (TypeSpec iface in target_tp.Interfaces) {
if (!TypeManager.IsGenericParameter (iface))
if (TypeManager.IsValueType (expr_type))
return false;
- if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type || expr_type.IsDelegate) {
+ if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type || expr_type.IsDelegate || expr_type.Kind == MemberKind.ArrayType) {
// No mcs internal types are convertible
return true; // expr_type.MetaInfo.Module != typeof (Convert).Module;
}
if (value >= 0)
return true;
}
-
- if (value == 0 && target_type.IsEnum)
- return true;
}
if (expr is LongConstant && target_type == TypeManager.uint64_type){
return true;
}
+ if (expr is IntegralConstant && TypeManager.IsEnumType (target_type)) {
+ var i = (IntegralConstant) expr;
+ //
+ // LAMESPEC: csc allows any constant like 0 values to be converted, including const float f = 0.0
+ //
+ // An implicit enumeration conversion permits the decimal-integer-literal 0
+ // to be converted to any enum-type and to any nullable-type whose underlying
+ // type is an enum-type
+ //
+ return i.IsZeroInteger;
+ }
+
//
// If `expr_type' implements `target_type' (which is an iface)
// see TryImplicitIntConversion
return UserDefinedConversion (ec, source, target, false, loc);
}
- static void FindApplicableUserDefinedConversionOperators (MethodSpec[] operators, Expression source, TypeSpec target, bool implicitOnly, ref List<MethodSpec> candidates)
+ static void FindApplicableUserDefinedConversionOperators (IList<MemberSpec> operators, Expression source, TypeSpec target, bool implicitOnly, ref List<MethodSpec> candidates)
{
//
// LAMESPEC: Undocumented IntPtr/UIntPtr conversions
Expression texpr = null;
- foreach (var op in operators) {
+ 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)
if (e != null)
return e;
- if (expr is IntConstant && TypeManager.IsEnumType (target_type)){
- Constant i = (Constant) expr;
+ if (expr is IntegralConstant && TypeManager.IsEnumType (target_type)){
+ var i = (IntegralConstant) expr;
//
- // LAMESPEC: Conversion from any 0 constant is allowed
+ // LAMESPEC: csc allows any constant like 0 values to be converted, including const float f = 0.0
//
// An implicit enumeration conversion permits the decimal-integer-literal 0
// to be converted to any enum-type and to any nullable-type whose underlying
// type is an enum-type
//
- if (i.IsDefaultValue)
- return new EnumConstant (i, target_type).Resolve (ec);
+ if (i.IsZeroInteger) {
+ // Recreate 0 literal to remove any collected conversions
+ return new EnumConstant (new IntLiteral (0, i.Location), target_type).Resolve (ec);
+ }
}
if (ec.IsUnsafe) {
//
// Explicit type parameter conversion.
//
- if (TypeManager.IsGenericParameter (source_type))
+ if (source_type.Kind == MemberKind.TypeParameter)
return ExplicitTypeParameterConversion (source, source_type, target_type);
bool target_is_value_type = TypeManager.IsStruct (target_type) || TypeManager.IsEnumType (target_type);
//
// From any class S to any class-type T, provided S is a base class of T
//
- if (TypeManager.IsSubclassOf (target_type, source_type))
+ if (source_type.Kind == MemberKind.Class && TypeManager.IsSubclassOf (target_type, source_type))
return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
//