//
static class Convert
{
+ [Flags]
+ public enum UserConversionRestriction
+ {
+ None = 0,
+ ImplicitOnly = 1,
+ ProbingOnly = 1 << 1,
+ NullableSourceOnly = 1 << 2
+
+ }
//
// 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
//
static bool ArrayToIList (ArrayContainer array, TypeSpec list, bool isExplicit)
{
- if (array.Rank != 1 || !list.IsGenericIterateInterface)
+ if (array.Rank != 1 || !list.IsArrayGenericInterface)
return false;
var arg_type = list.TypeArguments[0];
static bool IList_To_Array(TypeSpec list, ArrayContainer array)
{
- if (array.Rank != 1 || !list.IsGenericIterateInterface)
+ if (array.Rank != 1 || !list.IsArrayGenericInterface)
return false;
var arg_type = list.TypeArguments[0];
// From T to a type parameter U, provided T depends on U
//
if (target_type.IsGenericParameter) {
- if (expr_type.TypeArguments != null) {
- foreach (var targ in expr_type.TypeArguments) {
- if (!TypeSpecComparer.Override.IsEqual (target_type, targ))
- continue;
-
- if (expr == null)
- return EmptyExpression.Null;
+ if (expr_type.TypeArguments != null && expr_type.HasDependencyOn (target_type)) {
+ if (expr == null)
+ return EmptyExpression.Null;
- if (expr_type.IsReferenceType && !((TypeParameterSpec)target_type).IsReferenceType)
- return new BoxedCast (expr, target_type);
+ if (expr_type.IsReferenceType && !((TypeParameterSpec) target_type).IsReferenceType)
+ return new BoxedCast (expr, target_type);
- return new ClassCast (expr, target_type);
- }
+ return new ClassCast (expr, target_type);
}
return null;
return null;
}
- static Expression ExplicitTypeParameterConversion (Expression source, TypeSpec source_type, TypeSpec target_type)
+ static Expression ExplicitTypeParameterConversionFromT (Expression source, TypeSpec source_type, TypeSpec 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))
- continue;
-
- if (TypeManager.IsSubclassOf (source_type, iface))
- return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true);
- }
+ //
+ // From a type parameter U to T, provided T depends on U
+ //
+ if (target_tp.TypeArguments != null && target_tp.HasDependencyOn (source_type)) {
+ return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
}
-*/
- return null;
}
+ //
+ // From T to any interface-type I provided there is not already an implicit conversion from T to I
+ //
if (target_type.IsInterface)
return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true);
return null;
}
+ static Expression ExplicitTypeParameterConversionToT (Expression source, TypeSpec source_type, TypeParameterSpec target_type)
+ {
+ //
+ // From the effective base class C of T to T and from any base class of C to T
+ //
+ var effective = target_type.GetEffectiveBase ();
+ if (TypeSpecComparer.IsEqual (effective, source_type) || TypeSpec.IsBaseClass (effective, source_type, false))
+ return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
+
+ return null;
+ }
+
public static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast)
{
TypeSpec expr_type = expr.Type;
if (target_type.Kind == MemberKind.InternalCompilerType)
return target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
- return TypeSpec.IsReferenceType (target_type);
+ return TypeSpec.IsReferenceType (target_type) || target_type.Kind == MemberKind.PointerType;
}
//
}
if (expr_type != expr.Type)
- return new Nullable.Lifted (conv, unwrap, target_type).Resolve (ec);
+ return new Nullable.LiftedConversion (conv, unwrap, target_type).Resolve (ec);
return Nullable.Wrap.Create (conv, target_type);
}
//
public static bool ImplicitConversionExists (ResolveContext ec, Expression expr, TypeSpec target_type)
{
- if (ImplicitStandardConversionExists (expr, target_type))
+ if (ImplicitStandardConversionExists (ec, expr, target_type))
return true;
if (expr.Type == InternalType.AnonymousMethod) {
return ame.ImplicitStandardConversionExists (ec, target_type);
}
+ // Conversion from __arglist to System.ArgIterator
+ if (expr.Type == InternalType.Arglist)
+ return target_type == ec.Module.PredefinedTypes.ArgIterator.TypeSpec;
+
+ return UserDefinedConversion (ec, expr, target_type,
+ UserConversionRestriction.ImplicitOnly | UserConversionRestriction.ProbingOnly, Location.Null) != null;
+ }
+
+ public static bool ImplicitStandardConversionExists (ResolveContext rc, Expression expr, TypeSpec target_type)
+ {
if (expr.eclass == ExprClass.MethodGroup) {
- if (target_type.IsDelegate && ec.Module.Compiler.Settings.Version != LanguageVersion.ISO_1) {
+ if (target_type.IsDelegate && rc.Module.Compiler.Settings.Version != LanguageVersion.ISO_1) {
MethodGroupExpr mg = expr as MethodGroupExpr;
if (mg != null)
- return DelegateCreation.ImplicitStandardConversionExists (ec, mg, target_type);
+ return DelegateCreation.ImplicitStandardConversionExists (rc, mg, target_type);
}
return false;
}
- // Conversion from __arglist to System.ArgIterator
- if (expr.Type == InternalType.Arglist)
- return target_type == ec.Module.PredefinedTypes.ArgIterator.TypeSpec;
-
- return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null;
+ return ImplicitStandardConversionExists (expr, target_type);
}
//
// 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)
+ static TypeSpec FindMostSpecificSource (ResolveContext rc, List<MethodSpec> list, TypeSpec sourceType, Expression source, bool apply_explicit_conv_rules)
{
- var src_types_set = new TypeSpec [list.Count];
+ TypeSpec[] src_types_set = null;
//
// Try exact match first, if any operator converts from S then Sx = S
//
- for (int i = 0; i < src_types_set.Length; ++i) {
+ for (int i = 0; i < list.Count; ++i) {
TypeSpec param_type = list [i].Parameters.Types [0];
if (param_type == sourceType)
return param_type;
+ if (src_types_set == null)
+ src_types_set = new TypeSpec [list.Count];
+
src_types_set [i] = param_type;
}
var candidate_set = new List<TypeSpec> ();
foreach (TypeSpec param_type in src_types_set){
- if (ImplicitStandardConversionExists (source, param_type))
+ if (ImplicitStandardConversionExists (rc, source, param_type))
candidate_set.Add (param_type);
}
- if (candidate_set.Count != 0)
+ if (candidate_set.Count != 0) {
+ if (source.eclass == ExprClass.MethodGroup)
+ return InternalType.FakeInternalType;
+
return FindMostEncompassedType (candidate_set);
+ }
}
//
static public TypeSpec FindMostSpecificTarget (IList<MethodSpec> list,
TypeSpec target, bool apply_explicit_conv_rules)
{
- var tgt_types_set = new List<TypeSpec> ();
+ List<TypeSpec> tgt_types_set = null;
//
// If any operator converts to T then Tx = T
if (ret_type == target)
return ret_type;
+ if (tgt_types_set == null) {
+ tgt_types_set = new List<TypeSpec> (list.Count);
+ } else if (tgt_types_set.Contains (ret_type)) {
+ continue;
+ }
+
tgt_types_set.Add (ret_type);
}
/// </summary>
static public Expression ImplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc)
{
- return UserDefinedConversion (ec, source, target, true, loc);
+ return UserDefinedConversion (ec, source, target, UserConversionRestriction.ImplicitOnly, loc);
}
/// <summary>
/// </summary>
static Expression ExplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc)
{
- return UserDefinedConversion (ec, source, target, false, loc);
+ return UserDefinedConversion (ec, source, target, 0, loc);
}
- static void FindApplicableUserDefinedConversionOperators (IList<MemberSpec> operators, Expression source, TypeSpec target, bool implicitOnly, ref List<MethodSpec> candidates)
+ static void FindApplicableUserDefinedConversionOperators (ResolveContext rc, IList<MemberSpec> operators, Expression source, TypeSpec target, UserConversionRestriction restr, ref List<MethodSpec> candidates)
{
if (source.Type.IsInterface) {
// Neither A nor B are interface-types
continue;
var t = op.Parameters.Types[0];
- if (source.Type != t && !ImplicitStandardConversionExists (source, t)) {
- if (implicitOnly)
+ if (source.Type != t && !ImplicitStandardConversionExists (rc, source, t)) {
+ if ((restr & UserConversionRestriction.ImplicitOnly) != 0)
continue;
if (!ImplicitStandardConversionExists (new EmptyExpression (t), source.Type))
- continue;
+ continue;
}
+ if ((restr & UserConversionRestriction.NullableSourceOnly) != 0 && !t.IsNullableType)
+ continue;
+
t = op.ReturnType;
if (t.IsInterface)
t = Nullable.NullableInfo.GetUnderlyingType (t);
if (!ImplicitStandardConversionExists (new EmptyExpression (t), target)) {
- if (implicitOnly)
+ if ((restr & UserConversionRestriction.ImplicitOnly) != 0)
continue;
if (texpr == null)
//
// User-defined conversions
//
- static Expression UserDefinedConversion (ResolveContext ec, Expression source, TypeSpec target, bool implicitOnly, Location loc)
+ public static Expression UserDefinedConversion (ResolveContext rc, Expression source, TypeSpec target, UserConversionRestriction restr, Location loc)
{
List<MethodSpec> candidates = null;
TypeSpec source_type = source.Type;
TypeSpec target_type = target;
Expression source_type_expr;
+ bool nullable_source = false;
+ var implicitOnly = (restr & UserConversionRestriction.ImplicitOnly) != 0;
if (source_type.IsNullableType) {
- // No implicit conversion S? -> T for non-reference types
- if (implicitOnly && !TypeSpec.IsReferenceType (target_type) && !target_type.IsNullableType)
- return null;
-
- source_type_expr = Nullable.Unwrap.Create (source);
- source_type = source_type_expr.Type;
+ // No unwrapping conversion S? -> T for non-reference types
+ if (implicitOnly && !TypeSpec.IsReferenceType (target_type) && !target_type.IsNullableType) {
+ source_type_expr = source;
+ } else {
+ source_type_expr = Nullable.Unwrap.CreateUnwrapped (source);
+ source_type = source_type_expr.Type;
+ nullable_source = true;
+ }
} else {
source_type_expr = source;
}
var operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Implicit, declared_only);
if (operators != null) {
- FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, implicitOnly, ref candidates);
+ FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates);
}
if (!implicitOnly) {
operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Explicit, declared_only);
if (operators != null) {
- FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, false, ref candidates);
+ FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates);
}
}
}
var operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Implicit, declared_only);
if (operators != null) {
- FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, implicitOnly, ref candidates);
+ FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates);
}
if (!implicitOnly) {
operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Explicit, declared_only);
if (operators != null) {
- FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, false, ref candidates);
+ FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates);
}
}
}
// 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);
+ s_x = FindMostSpecificSource (rc, candidates, source.Type, source_type_expr, !implicitOnly);
if (s_x == null)
return null;
}
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;
+ //
+ // Unless running in probing more
+ //
+ if ((restr & UserConversionRestriction.ProbingOnly) == 0) {
+ MethodSpec ambig_arg = candidates [0];
+ most_specific_operator = candidates [1];
+ /*
+ 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;
+ }
+ */
+ rc.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 ());
}
- 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 ());
-
return ErrorExpression.Instance;
}
}
if (s_x != source_type) {
var c = source as Constant;
if (c != null) {
- source = c.TryReduce (ec, s_x, loc);
- } else {
+ source = c.Reduce (rc, s_x);
+ if (source == null)
+ c = null;
+ }
+
+ if (c == null) {
source = implicitOnly ?
- ImplicitConversionStandard (ec, source_type_expr, s_x, loc) :
- ExplicitConversionStandard (ec, source_type_expr, s_x, loc);
+ ImplicitConversionStandard (rc, source_type_expr, s_x, loc) :
+ ExplicitConversionStandard (rc, source_type_expr, s_x, loc);
}
} else {
source = source_type_expr;
}
- source = new UserCast (most_specific_operator, source, loc).Resolve (ec);
+ source = new UserCast (most_specific_operator, source, loc).Resolve (rc);
//
// Convert result type when it's different to best operator return type
//
if (t_x != target_type) {
//
- // User operator is of T?, no need to lift it
+ // User operator is of T?
//
- if (t_x == target && t_x.IsNullableType)
- return source;
+ if (t_x.IsNullableType && (target.IsNullableType || !implicitOnly)) {
+ //
+ // User operator return type does not match target type we need
+ // yet another conversion. This should happen for promoted numeric
+ // types only
+ //
+ if (t_x != target) {
+ var unwrap = Nullable.Unwrap.CreateUnwrapped (source);
- source = implicitOnly ?
- ImplicitConversionStandard (ec, source, target_type, loc) :
- ExplicitConversionStandard (ec, source, target_type, loc);
+ source = implicitOnly ?
+ ImplicitConversionStandard (rc, unwrap, target_type, loc) :
+ ExplicitConversionStandard (rc, unwrap, target_type, loc);
- if (source == null)
- return null;
+ if (source == null)
+ return null;
+
+ if (target.IsNullableType)
+ source = new Nullable.LiftedConversion (source, unwrap, target).Resolve (rc);
+ }
+ } else {
+ source = implicitOnly ?
+ ImplicitConversionStandard (rc, source, target_type, loc) :
+ ExplicitConversionStandard (rc, source, target_type, loc);
+
+ if (source == null)
+ return null;
+ }
}
+
+ //
+ // Source expression is of nullable type and underlying conversion returns
+ // only non-nullable type we need to lift it manually
+ //
+ if (nullable_source && !s_x.IsNullableType)
+ return new Nullable.LiftedConversion (source, source_type_expr, target).Resolve (rc);
+
//
- // Source expression is of nullable type, lift the result in the case it's null and
- // not nullable/lifted user operator is used
+ // Target is of nullable type but source type is not, wrap the result expression
//
- if (source_type_expr is Nullable.Unwrap && !s_x.IsNullableType && (TypeSpec.IsReferenceType (target) || target_type != target))
- source = new Nullable.Lifted (source, source_type_expr, target).Resolve (ec);
- else if (target_type != target)
+ if (target.IsNullableType && !t_x.IsNullableType)
source = Nullable.Wrap.Create (source, target);
return source;
if (ec.Module.Compiler.Settings.Version != LanguageVersion.ISO_1){
MethodGroupExpr mg = expr as MethodGroupExpr;
if (mg != null)
- return ImplicitDelegateCreation.Create (
- ec, mg, target_type, loc);
+ return new ImplicitDelegateCreation (target_type, mg, loc).Resolve (ec);
}
}
try {
c = c.ConvertImplicitly (target_type);
} catch {
- Console.WriteLine ("Conversion error happened in line {0}", loc);
- throw;
+ throw new InternalErrorException ("Conversion error", loc);
}
if (c != null)
return c;
}
}
- if (ec.IsUnsafe) {
- var target_pc = target_type as PointerContainer;
- if (target_pc != null) {
- if (expr_type.IsPointer) {
- //
- // Pointer types are same when they have same element types
- //
- if (expr_type == target_pc)
- return expr;
+ var target_pc = target_type as PointerContainer;
+ if (target_pc != null) {
+ if (expr_type.IsPointer) {
+ //
+ // Pointer types are same when they have same element types
+ //
+ if (expr_type == target_pc)
+ return expr;
- if (target_pc.Element.Kind == MemberKind.Void)
- return EmptyCast.Create (expr, target_type);
+ if (target_pc.Element.Kind == MemberKind.Void)
+ return EmptyCast.Create (expr, target_type);
//return null;
- }
-
- if (expr_type == InternalType.NullLiteral)
- return new NullPointer (target_type, loc);
}
+
+ if (expr_type == InternalType.NullLiteral)
+ return new NullPointer (target_type, loc);
}
if (expr_type == InternalType.AnonymousMethod){
Expression am = ame.Compatible (ec, target_type);
if (am != null)
return am.Resolve (ec);
+
+ // Avoid CS1503 after CS1661
+ return ErrorExpression.Instance;
}
if (expr_type == InternalType.Arglist && target_type == ec.Module.PredefinedTypes.ArgIterator.TypeSpec)
if (expr_type.IsStruct && TypeSpecComparer.IsEqual (expr_type, target_type))
return expr_type == target_type ? expr : EmptyCast.Create (expr, target_type);
+ var interpolated_string = expr as InterpolatedString;
+ if (interpolated_string != null) {
+ if (target_type == ec.Module.PredefinedTypes.IFormattable.TypeSpec || target_type == ec.Module.PredefinedTypes.FormattableString.TypeSpec)
+ return interpolated_string.ConvertTo (ec, target_type);
+ }
+
return null;
}
if (e != null)
return e;
- source.Error_ValueCannotBeConverted (ec, loc, target_type, false);
+ source.Error_ValueCannotBeConverted (ec, target_type, false);
+
return null;
}
return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
//
- // Explicit type parameter conversion.
+ // Explicit type parameter conversion from T
//
if (source_type.Kind == MemberKind.TypeParameter)
- return ExplicitTypeParameterConversion (source, source_type, target_type);
+ return ExplicitTypeParameterConversionFromT (source, source_type, target_type);
bool target_is_value_type = target_type.Kind == MemberKind.Struct || target_type.Kind == MemberKind.Enum;
// From any interface-type S to to any class type T, provided T is not
// sealed, or provided T implements S.
//
+ // This also covers Explicit conversions involving type parameters
+ // section From any interface type to T
+ //
if (source_type.Kind == MemberKind.Interface) {
if (!target_type.IsSealed || target_type.ImplementsInterface (source_type, true)) {
if (source == null)
if (source_array.Rank == target_array.Rank) {
source_type = source_array.Element;
- if (!TypeSpec.IsReferenceType (source_type))
- return null;
-
var target_element = target_array.Element;
+
+ //
+ // LAMESPEC: Type parameters are special cased somehow but
+ // only when both source and target elements are type parameters
+ //
+ if ((source_type.Kind & target_element.Kind & MemberKind.TypeParameter) == MemberKind.TypeParameter) {
+ //
+ // Conversion is allowed unless source element type has struct constrain
+ //
+ if (TypeSpec.IsValueType (source_type))
+ return null;
+ } else {
+ if (!TypeSpec.IsReferenceType (source_type))
+ return null;
+ }
+
if (!TypeSpec.IsReferenceType (target_element))
return null;
return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
}
+ var tps = target_type as TypeParameterSpec;
+ if (tps != null)
+ return ExplicitTypeParameterConversionToT (source, source_type, tps);
+
return null;
}
if (expr_type == real_target)
return EmptyCast.Create (expr, target_type);
- ne = ImplicitNumericConversion (expr, real_target);
- if (ne != null)
- return EmptyCast.Create (ne, target_type);
-
- ne = ExplicitNumericConversion (ec, expr, real_target);
- if (ne != null)
- return EmptyCast.Create (ne, target_type);
+ Constant c = expr as Constant;
+ if (c != null) {
+ c = c.TryReduce (ec, real_target);
+ if (c != null)
+ return c;
+ } else {
+ ne = ImplicitNumericConversion (expr, real_target);
+ if (ne != null)
+ return EmptyCast.Create (ne, target_type);
- //
- // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
- //
- if (expr_type.BuiltinType == BuiltinTypeSpec.Type.IntPtr || expr_type.BuiltinType == BuiltinTypeSpec.Type.UIntPtr) {
- ne = ExplicitUserConversion (ec, expr, real_target, loc);
+ ne = ExplicitNumericConversion (ec, expr, real_target);
if (ne != null)
- return ExplicitConversionCore (ec, ne, target_type, loc);
+ return EmptyCast.Create (ne, target_type);
+
+ //
+ // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
+ //
+ if (expr_type.BuiltinType == BuiltinTypeSpec.Type.IntPtr || expr_type.BuiltinType == BuiltinTypeSpec.Type.UIntPtr) {
+ ne = ExplicitUserConversion (ec, expr, real_target, loc);
+ if (ne != null)
+ return ExplicitConversionCore (ec, ne, target_type, loc);
+ }
}
} else {
ne = ExplicitNumericConversion (ec, expr, target_type);
if (ec.IsUnsafe && expr.Type.IsPointer && target_type.IsPointer && ((PointerContainer)expr.Type).Element.Kind == MemberKind.Void)
return EmptyCast.Create (expr, target_type);
- expr.Error_ValueCannotBeConverted (ec, l, target_type, true);
+ expr.Error_ValueCannotBeConverted (ec, target_type, true);
return null;
}
if (e == null)
return null;
- return new Nullable.Lifted (e, unwrap, target_type).Resolve (ec);
+ return new Nullable.LiftedConversion (e, unwrap, target_type).Resolve (ec);
}
if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
return new UnboxCast (expr, target_type);
target = TypeManager.GetTypeArguments (target_type) [0];
e = ExplicitConversionCore (ec, expr, target, loc);
if (e != null)
- return Nullable.Wrap.Create (e, target_type);
+ return TypeSpec.IsReferenceType (expr.Type) ? new UnboxCast (expr, target_type) : Nullable.Wrap.Create (e, target_type);
} else if (expr_type.IsNullableType) {
e = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type);
if (e != null)
}
e = ExplicitUserConversion (ec, expr, target_type, loc);
+
if (e != null)
return e;
- expr.Error_ValueCannotBeConverted (ec, loc, target_type, true);
+ expr.Error_ValueCannotBeConverted (ec, target_type, true);
return null;
}
}