return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists (array.Element, arg_type);
}
- static Expression ImplicitTypeParameterConversion (Expression expr, TypeSpec target_type)
+ public static Expression ImplicitTypeParameterConversion (Expression expr, TypeSpec target_type)
{
var expr_type = (TypeParameterSpec) expr.Type;
}
//
- // LAMESPEC: From T to dynamic type
+ // LAMESPEC: From T to dynamic type because it's like T to object
//
if (target_type == InternalType.Dynamic) {
if (expr_type.IsReferenceType)
//
// From T to its effective base class C
- // From T to any base class of C
+ // From T to any base class of C (it cannot contain dynamic of be of dynamic type)
// From T to any interface implemented by C
//
var base_type = expr_type.GetEffectiveBase ();
- if (base_type == target_type || TypeManager.IsSubclassOf (base_type, target_type) || base_type.ImplementsInterface (target_type)) {
+ if (base_type == target_type || TypeSpec.IsBaseClass (base_type, target_type, false) || base_type.ImplementsInterface (target_type, true)) {
if (expr_type.IsReferenceType)
return new ClassCast (expr, target_type);
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))
return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true);
}
}
-
+*/
return null;
}
return null;
}
- static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast)
+ public static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast)
{
TypeSpec expr_type = expr.Type;
TypeSpec expr_type = expr.Type;
// from the null type to any reference-type.
- if (expr_type == TypeManager.null_type)
+ if (expr_type == InternalType.Null)
return target_type != InternalType.AnonymousMethod;
if (TypeManager.IsGenericParameter (expr_type))
// from any class-type S to any interface-type T.
if (target_type.IsInterface) {
- if (expr_type.ImplementsInterface (target_type)){
+ if (expr_type.ImplementsInterface (target_type, true)){
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.
+ // Implicit reference conversions (no-boxing) to object or dynamic
//
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 || expr_type.Kind == MemberKind.ArrayType) {
- // No mcs internal types are convertible
- return true; // expr_type.MetaInfo.Module != typeof (Convert).Module;
- }
-
- // From anything to dynamic
- if (target_type == InternalType.Dynamic)
+ switch (expr_type.Kind) {
+ case MemberKind.Class:
+ case MemberKind.Interface:
+ case MemberKind.Delegate:
+ case MemberKind.ArrayType:
return true;
+ }
- // From dynamic to object
- if (expr_type == InternalType.Dynamic)
- return true;
+ return expr_type == InternalType.Dynamic;
+ }
- return false;
- } else if (target_type == TypeManager.value_type) {
+ if (target_type == TypeManager.value_type) {
return expr_type == TypeManager.enum_type;
- } else if (TypeManager.IsSubclassOf (expr_type, target_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
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);
+ return expr_type.ImplementsInterface (target_type, true);
}
// from any delegate type to System.Delegate
(expr_type == TypeManager.delegate_type || expr_type.IsDelegate))
return true;
- if (TypeManager.IsEqual (expr_type, target_type))
- return true;
-
return false;
}
return res;
}
- if (TypeManager.IsSubclassOf (expr_type, target_type)) {
+ if (TypeSpec.IsBaseClass (expr_type, target_type, false)) {
//
// Don't box same type arguments
//
// from any class-type S to any interface-type T.
if (target_type.IsInterface) {
- if (expr_type.ImplementsInterface (target_type) &&
+ if (expr_type.ImplementsInterface (target_type, true) &&
(TypeManager.IsGenericParameter (expr_type) || TypeManager.IsValueType (expr_type))) {
return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type);
}
//
// From null to any nullable type
//
- if (expr_type == TypeManager.null_type)
+ if (expr_type == InternalType.Null)
return ec == null ? EmptyExpression.Null : Nullable.LiftedNull.Create (target_type, expr.Location);
// S -> T?
// conversion exists only mode
if (ec == null) {
- if (expr_type == t_el)
+ if (TypeSpecComparer.IsEqual (expr_type, t_el))
return EmptyExpression.Null;
if (expr is Constant)
unwrap = expr;
Expression conv = unwrap;
- if (expr_type != t_el) {
+ if (!TypeSpecComparer.IsEqual (expr_type, t_el)) {
if (conv is Constant)
conv = ((Constant)conv).ConvertImplicitly (ec, t_el);
else
if (target_type == TypeManager.uint64_type)
return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
if (target_type == TypeManager.double_type)
- return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
+ return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R8);
if (target_type == TypeManager.float_type)
- return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
+ return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4);
if (target_type == TypeManager.decimal_type)
return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
} else if (expr_type == TypeManager.int64_type){
// From ulong to float, double
//
if (target_type == TypeManager.double_type)
- return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
+ return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R8);
if (target_type == TypeManager.float_type)
- return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
+ return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4);
if (target_type == TypeManager.decimal_type)
return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
} else if (expr_type == TypeManager.char_type){
/// Determines if a standard implicit conversion exists from
/// expr_type to target_type
///
- /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
/// </summary>
public static bool ImplicitStandardConversionExists (Expression expr, TypeSpec target_type)
{
TypeSpec expr_type = expr.Type;
- if (expr_type == TypeManager.null_type) {
- NullLiteral nl = expr as NullLiteral;
- if (nl != null)
- return nl.ConvertImplicitly (null, target_type) != null;
- }
+ NullLiteral nl = expr as NullLiteral;
+ if (nl != null)
+ return nl.ConvertImplicitly (null, target_type) != null;
if (expr_type == TypeManager.void_type)
return false;
- if (TypeManager.IsEqual (expr_type, target_type))
+ if (expr_type == target_type)
return true;
+ // Implicit dynamic conversion
+ if (expr_type == InternalType.Dynamic) {
+ switch (target_type.Kind) {
+ case MemberKind.ArrayType:
+ case MemberKind.Class:
+ case MemberKind.Struct:
+ case MemberKind.Delegate:
+ case MemberKind.Enum:
+ case MemberKind.Interface:
+ case MemberKind.TypeParameter:
+ return true;
+ }
+
+ // dynamic to __arglist
+ if (target_type == InternalType.Arglist)
+ return true;
+
+ return false;
+ }
+
if (TypeManager.IsNullableType (target_type)) {
return ImplicitNulableConversion (null, expr, target_type) != null;
}
if (ImplicitBoxingConversion (null, expr_type, target_type) != null)
return true;
-
+
//
// Implicit Constant Expression Conversions
//
// If `expr_type' implements `target_type' (which is an iface)
// see TryImplicitIntConversion
//
- if (target_type.IsInterface && expr_type.ImplementsInterface (target_type))
+ if (target_type.IsInterface && expr_type.ImplementsInterface (target_type, true))
return true;
if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
if (expr_type == InternalType.Arglist)
return target_type == TypeManager.arg_iterator_type;
+ if (TypeSpecComparer.IsEqual (expr_type, target_type))
+ return true;
+
return false;
}
return best;
}
- /// <summary>
- /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
- /// by making use of FindMostEncomp* methods. Applies the correct rules separately
- /// for explicit and implicit conversion operators.
- /// </summary>
- static TypeSpec FindMostSpecificSource (IList<MethodSpec> list,
- Expression source, bool apply_explicit_conv_rules)
+ //
+ // Finds the most specific source Sx according to the rules of the spec (13.4.4)
+ // by making use of FindMostEncomp* methods. Applies the correct rules separately
+ // for explicit and implicit conversion operators.
+ //
+ static TypeSpec FindMostSpecificSource (List<MethodSpec> list, TypeSpec sourceType, Expression source, bool apply_explicit_conv_rules)
{
- var src_types_set = new List<TypeSpec> ();
+ var src_types_set = new TypeSpec [list.Count];
//
- // If any operator converts from S then Sx = S
+ // Try exact match first, if any operator converts from S then Sx = S
//
- TypeSpec source_type = source.Type;
- foreach (var mb in list){
- TypeSpec param_type = mb.Parameters.Types [0];
+ for (int i = 0; i < src_types_set.Length; ++i) {
+ TypeSpec param_type = list [i].Parameters.Types [0];
- if (param_type == source_type)
+ if (param_type == sourceType)
return param_type;
- src_types_set.Add (param_type);
+ src_types_set [i] = param_type;
}
//
target = TypeManager.uint64_type;
}
+ // Neither A nor B are interface-types
+ if (source.Type.IsInterface)
+ 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
if (t == TypeManager.uint32_type && source.Type == TypeManager.uintptr_type)
continue;
- if (target != t && !ImplicitStandardConversionExists (new EmptyExpression (t), target)) {
- if (implicitOnly)
- continue;
+ if (t.IsInterface)
+ continue;
- if (texpr == null)
- texpr = new EmptyExpression (target);
+ if (target != t) {
+ if (TypeManager.IsNullableType (t))
+ t = Nullable.NullableInfo.GetUnderlyingType (t);
- if (!ImplicitStandardConversionExists (texpr, t))
- continue;
+ if (!ImplicitStandardConversionExists (new EmptyExpression (t), target)) {
+ if (implicitOnly)
+ continue;
+
+ if (texpr == null)
+ texpr = new EmptyExpression (target);
+
+ if (!ImplicitStandardConversionExists (texpr, t))
+ continue;
+ }
}
if (candidates == null)
List<MethodSpec> candidates = null;
//
- // If S or T are nullable types, S0 and T0 are their underlying types
- // otherwise S0 and T0 are equal to S and T respectively.
+ // If S or T are nullable types, source_type and target_type are their underlying types
+ // otherwise source_type and target_type are equal to S and T respectively.
//
TypeSpec source_type = source.Type;
TypeSpec target_type = target;
- Expression unwrap;
+ Expression source_type_expr;
if (TypeManager.IsNullableType (source_type)) {
// No implicit conversion S? -> T for non-reference types
if (implicitOnly && !TypeManager.IsReferenceType (target_type) && !TypeManager.IsNullableType (target_type))
return null;
- unwrap = source = Nullable.Unwrap.Create (source);
- source_type = source.Type;
+ source_type_expr = Nullable.Unwrap.Create (source);
+ source_type = source_type_expr.Type;
} else {
- unwrap = null;
+ source_type_expr = source;
}
if (TypeManager.IsNullableType (target_type))
var operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Implicit, declared_only);
if (operators != null) {
- FindApplicableUserDefinedConversionOperators (operators, source, target_type, implicitOnly, ref candidates);
+ FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, implicitOnly, ref candidates);
}
if (!implicitOnly) {
operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Explicit, declared_only);
if (operators != null) {
- FindApplicableUserDefinedConversionOperators (operators, source, target_type, false, ref candidates);
+ FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, false, ref candidates);
}
}
}
- if ((target.Kind & user_conversion_kinds) != 0 && target != TypeManager.decimal_type) {
+ if ((target.Kind & user_conversion_kinds) != 0 && target_type != TypeManager.decimal_type) {
bool declared_only = target.IsStruct || implicitOnly;
var operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Implicit, declared_only);
if (operators != null) {
- FindApplicableUserDefinedConversionOperators (operators, source, target_type, implicitOnly, ref candidates);
+ FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, implicitOnly, ref candidates);
}
if (!implicitOnly) {
operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Explicit, declared_only);
if (operators != null) {
- FindApplicableUserDefinedConversionOperators (operators, source, target_type, false, ref candidates);
+ FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, false, ref candidates);
}
}
}
s_x = most_specific_operator.Parameters.Types[0];
t_x = most_specific_operator.ReturnType;
} else {
- s_x = FindMostSpecificSource (candidates, source, !implicitOnly);
+ //
+ // Pass original source type to find the best match against input type and
+ // not the unwrapped expression
+ //
+ s_x = FindMostSpecificSource (candidates, source.Type, source_type_expr, !implicitOnly);
if (s_x == null)
return null;
if (t_x == null)
return null;
- most_specific_operator = candidates[0];
-
- for (int i = 1; i < candidates.Count; ++i) {
+ most_specific_operator = null;
+ for (int i = 0; i < candidates.Count; ++i) {
if (candidates[i].ReturnType == t_x && candidates[i].Parameters.Types[0] == s_x) {
most_specific_operator = candidates[i];
break;
}
}
+
+ if (most_specific_operator == null) {
+ MethodSpec ambig_arg = null;
+ foreach (var candidate in candidates) {
+ if (candidate.ReturnType == t_x)
+ most_specific_operator = candidate;
+ else if (candidate.Parameters.Types[0] == s_x)
+ ambig_arg = candidate;
+ }
+
+ ec.Report.Error (457, loc,
+ "Ambiguous user defined operators `{0}' and `{1}' when converting from `{2}' to `{3}'",
+ ambig_arg.GetSignatureForError (), most_specific_operator.GetSignatureForError (),
+ source.Type.GetSignatureForError (), target.GetSignatureForError ());
+ }
}
//
// Convert input type when it's different to best operator argument
//
- if (s_x != source.Type)
+ if (s_x != source_type)
source = implicitOnly ?
- ImplicitConversionStandard (ec, source, s_x, loc) :
- ExplicitConversionStandard (ec, source, s_x, loc);
+ ImplicitConversionStandard (ec, source_type_expr, s_x, loc) :
+ ExplicitConversionStandard (ec, source_type_expr, s_x, loc);
+ else {
+ source = source_type_expr;
+ }
source = new UserCast (most_specific_operator, source, loc).Resolve (ec);
source = implicitOnly ?
ImplicitConversionStandard (ec, source, target_type, loc) :
ExplicitConversionStandard (ec, source, target_type, loc);
+
+ if (source == null)
+ return null;
}
//
- // Source expression is of nullable type, lift the result in case of it's null
+ // Source expression is of nullable type, lift the result in the case it's null and
+ // not nullable/lifted user operator is used
//
- if (unwrap != null && (TypeManager.IsReferenceType (target) || target_type != target))
- source = new Nullable.Lifted (source, unwrap, target).Resolve (ec);
+ if (source_type_expr is Nullable.Unwrap && !TypeManager.IsNullableType (s_x) && (TypeManager.IsReferenceType (target) || target_type != target))
+ source = new Nullable.Lifted (source, source_type_expr, target).Resolve (ec);
else if (target_type != target)
source = Nullable.Wrap.Create (source, target);
TypeSpec expr_type = expr.Type;
Expression e;
- if (expr_type.Equals (target_type)) {
- if (expr_type != TypeManager.null_type && expr_type != InternalType.AnonymousMethod)
+ if (expr_type == target_type) {
+ if (expr_type != InternalType.Null && expr_type != InternalType.AnonymousMethod)
return expr;
return null;
}
- if (TypeSpecComparer.Variant.IsEqual (expr_type, target_type)) {
- return expr;
+ if (expr_type == InternalType.Dynamic) {
+ switch (target_type.Kind) {
+ case MemberKind.ArrayType:
+ case MemberKind.Class:
+ if (target_type == TypeManager.object_type)
+ return EmptyCast.Create (expr, target_type);
+
+ goto case MemberKind.Struct;
+ case MemberKind.Struct:
+ // TODO: Should really introduce MemberKind.Void
+ if (target_type == TypeManager.void_type)
+ return null;
+
+ goto case MemberKind.Enum;
+ case MemberKind.Delegate:
+ case MemberKind.Enum:
+ case MemberKind.Interface:
+ case MemberKind.TypeParameter:
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (expr));
+ return new DynamicConversion (target_type, explicit_cast ? CSharpBinderFlags.ConvertExplicit : 0, args, loc).Resolve (ec);
+ }
+
+ return null;
}
if (TypeManager.IsNullableType (target_type))
}
}
- if (expr_type == TypeManager.null_type && target_type.IsPointer)
+ if (expr_type == InternalType.Null && target_type.IsPointer)
return EmptyCast.Create (new NullPointer (loc), target_type);
}
if (expr_type == InternalType.Arglist && target_type == TypeManager.arg_iterator_type)
return expr;
+ if (TypeSpecComparer.IsEqual (expr_type, target_type))
+ return expr;
+
return null;
}
if (e != null)
return e;
- if (source.Type == InternalType.Dynamic) {
- Arguments args = new Arguments (1);
- args.Add (new Argument (source));
- return new DynamicConversion (target_type, 0, args, loc).Resolve (ec);
- }
-
source.Error_ValueCannotBeConverted (ec, loc, target_type, false);
return null;
}
return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
//
- // From object to any reference type or value type (unboxing)
+ // From object or dynamic to any reference type or value type (unboxing)
//
- if (source_type == TypeManager.object_type)
+ if (source_type == TypeManager.object_type || source_type == InternalType.Dynamic) {
+ if (target_type.IsPointer)
+ return null;
+
return
source == null ? EmptyExpression.Null :
target_is_value_type ? new UnboxCast (source, target_type) :
source is Constant ? (Expression) new EmptyConstantCast ((Constant) source, target_type) :
new ClassCast (source, target_type);
+ }
//
// From any class S to any class-type T, provided S is a base class of T
//
- if (source_type.Kind == MemberKind.Class && TypeManager.IsSubclassOf (target_type, source_type))
+ if (source_type.Kind == MemberKind.Class && TypeSpec.IsBaseClass (target_type, source_type, true))
return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
//
// sealed, or provided T implements S.
//
if (source_type.IsInterface) {
- if (!target_type.IsSealed || target_type.ImplementsInterface (source_type)) {
- if (target_type.IsClass)
- return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
+ if (!target_type.IsSealed || target_type.ImplementsInterface (source_type, true)) {
+ if (source == null)
+ return EmptyExpression.Null;
//
// Unboxing conversion from any interface-type to any non-nullable-value-type that
// implements the interface-type
//
- return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
+ return target_is_value_type ? new UnboxCast (source, target_type) : (Expression) new ClassCast (source, target_type);
}
//
// From any class type S to any interface T, provides S is not sealed
// and provided S does not implement T.
//
- if (target_type.IsInterface && !source_type.IsSealed && !source_type.ImplementsInterface (target_type)) {
+ if (target_type.IsInterface && !source_type.IsSealed && !source_type.ImplementsInterface (target_type, true)) {
return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
}
if (source_type == TypeManager.delegate_type && TypeManager.IsDelegateType (target_type))
return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
+ //
+ // From variant generic delegate to same variant generic delegate type
+ //
+ if (source_type.IsDelegate && target_type.IsDelegate && source_type.MemberDefinition == target_type.MemberDefinition) {
+ var tparams = source_type.MemberDefinition.TypeParameters;
+ var targs_src = source_type.TypeArguments;
+ var targs_dst = target_type.TypeArguments;
+ int i;
+ for (i = 0; i < tparams.Length; ++i) {
+ //
+ // If TP is invariant, types have to be identical
+ //
+ if (TypeSpecComparer.IsEqual (targs_src[i], targs_dst[i]))
+ continue;
+
+ if (tparams[i].Variance == Variance.Covariant) {
+ //
+ //If TP is covariant, an implicit or explicit identity or reference conversion is required
+ //
+ if (ImplicitReferenceConversionExists (new EmptyExpression (targs_src[i]), targs_dst[i]))
+ continue;
+
+ if (ExplicitReferenceConversionExists (targs_src[i], targs_dst[i]))
+ continue;
+
+ } else if (tparams[i].Variance == Variance.Contravariant) {
+ //
+ //If TP is contravariant, both are either identical or reference types
+ //
+ if (TypeManager.IsReferenceType (targs_src[i]) && TypeManager.IsReferenceType (targs_dst[i]))
+ continue;
+ }
+
+ break;
+ }
+
+ if (i == tparams.Length)
+ return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
+ }
+
return null;
}
// from Null to a ValueType, and ExplicitReference wont check against
// null literal explicitly
//
- if (expr_type != TypeManager.null_type){
+ if (expr_type != InternalType.Null) {
ne = ExplicitReferenceConversion (expr, expr_type, target_type);
if (ne != null)
return ne;