//
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
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;
}
//
//
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 UserDefinedConversion (ec, expr, target_type, true, true, 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)
{
TypeSpec[] src_types_set = null;
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);
+ }
}
//
/// </summary>
static public Expression ImplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc)
{
- return UserDefinedConversion (ec, source, target, true, false, 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, 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, bool probingOnly, Location loc)
+ public static Expression UserDefinedConversion (ResolveContext rc, Expression source, TypeSpec target, UserConversionRestriction restr, Location loc)
{
List<MethodSpec> candidates = null;
TypeSpec target_type = target;
Expression source_type_expr;
bool nullable_source = false;
+ var implicitOnly = (restr & UserConversionRestriction.ImplicitOnly) != 0;
if (source_type.IsNullableType) {
// No unwrapping conversion S? -> T for non-reference types
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;
//
// Unless running in probing more
//
- if (!probingOnly) {
- MethodSpec ambig_arg = null;
+ 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;
}
-
- ec.Report.Error (457, loc,
+ */
+ 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 ());
if (s_x != source_type) {
var c = source as Constant;
if (c != null) {
- source = c.Reduce (ec, s_x);
+ 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
var unwrap = Nullable.Unwrap.CreateUnwrapped (source);
source = implicitOnly ?
- ImplicitConversionStandard (ec, unwrap, target_type, loc) :
- ExplicitConversionStandard (ec, unwrap, target_type, loc);
+ ImplicitConversionStandard (rc, unwrap, target_type, loc) :
+ ExplicitConversionStandard (rc, unwrap, target_type, loc);
if (source == null)
return null;
if (target.IsNullableType)
- source = new Nullable.LiftedConversion (source, unwrap, target).Resolve (ec);
+ source = new Nullable.LiftedConversion (source, unwrap, target).Resolve (rc);
}
} else {
source = implicitOnly ?
- ImplicitConversionStandard (ec, source, target_type, loc) :
- ExplicitConversionStandard (ec, source, target_type, loc);
+ ImplicitConversionStandard (rc, source, target_type, loc) :
+ ExplicitConversionStandard (rc, source, target_type, loc);
if (source == null)
return null;
// 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 (ec);
+ return new Nullable.LiftedConversion (source, source_type_expr, target).Resolve (rc);
//
// Target is of nullable type but source type is not, wrap the result expression
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;
}
}
e = ExplicitUserConversion (ec, expr, target_type, loc);
+
if (e != null)
return e;