Skip to content

Commit

Permalink
Fix ToString conversion in assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
exyi committed Jul 1, 2023
1 parent 168d21a commit 81c264b
Show file tree
Hide file tree
Showing 10 changed files with 23 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/Framework/Framework/Binding/BindingFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static IBinding CreateBinding(this BindingCompilationService service, Typ
if (ctor == null) throw new NotSupportedException($"Could not find .ctor(BindingCompilationService service, object[] properties) on binding '{type.FullName}'.");
var bindingServiceParam = Expression.Parameter(typeof(BindingCompilationService));
var propertiesParam = Expression.Parameter(typeof(object?[]));
var expression = Expression.New(ctor, bindingServiceParam, TypeConversion.ImplicitConversion(propertiesParam, ctor.GetParameters()[1].ParameterType, throwException: true)!);
var expression = Expression.New(ctor, bindingServiceParam, TypeConversion.EnsureImplicitConversion(propertiesParam, ctor.GetParameters()[1].ParameterType));
return Expression.Lambda<Func<BindingCompilationService, object?[], IBinding>>(expression, bindingServiceParam, propertiesParam).CompileFast(flags: CompilerFlags.ThrowOnNotSupportedExpression);
})(service, properties);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ protected override Expression VisitAssemblyQualifiedName(AssemblyQualifiedNameBi

protected override Expression VisitConditionalExpression(ConditionalExpressionBindingParserNode node)
{
var condition = HandleErrors(node.ConditionExpression, n => TypeConversion.ImplicitConversion(Visit(n), typeof(bool), true));
var condition = HandleErrors(node.ConditionExpression, n => TypeConversion.EnsureImplicitConversion(Visit(n), typeof(bool)));
var trueExpr = HandleErrors(node.TrueExpression, Visit)!;
var falseExpr = HandleErrors(node.FalseExpression, Visit)!;
ThrowOnErrors();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ protected override Expression VisitConditional(ConditionalExpression node)
if (ifTrue.Type != ifFalse.Type)
{
var nullable = ifTrue.Type.IsNullable() ? ifTrue.Type : ifFalse.Type;
ifTrue = TypeConversion.ImplicitConversion(ifTrue, nullable, throwException: true)!;
ifFalse = TypeConversion.ImplicitConversion(ifFalse, nullable, throwException: true)!;
ifTrue = TypeConversion.EnsureImplicitConversion(ifTrue, nullable);
ifFalse = TypeConversion.EnsureImplicitConversion(ifFalse, nullable);
}
return Expression.Condition(test, ifTrue, ifFalse);
});
Expand Down Expand Up @@ -181,7 +181,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
{
return CheckForNull(Visit(node.Arguments.First()), index =>
{
var convertedIndex = TypeConversion.ImplicitConversion(index, node.Method.GetParameters().First().ParameterType, throwException: true)!;
var convertedIndex = TypeConversion.EnsureImplicitConversion(index, node.Method.GetParameters().First().ParameterType);
return Expression.Call(target, node.Method, new[] { convertedIndex }.Concat(node.Arguments.Skip(1)));
});
}, suppress: node.Object?.Type?.IsNullable() ?? true);
Expand Down Expand Up @@ -244,7 +244,7 @@ protected Expression CheckForNull(Expression? parameter, Func<Expression, Expres
parameter as ParameterExpression ??
Expression.Parameter(parameter.Type, "tmp" + tmpCounter++);
var eresult = callback(p2.Type.IsNullable() ? (Expression)Expression.Property(p2, "Value") : p2);
eresult = TypeConversion.ImplicitConversion(eresult, eresult.Type.MakeNullableType())!;
eresult = TypeConversion.EnsureImplicitConversion(eresult, eresult.Type.MakeNullableType());
var condition = parameter.Type.IsNullable() ? (Expression)Expression.Property(p2, "HasValue") : Expression.NotEqual(p2, Expression.Constant(null, p2.Type));
var handledResult =
Expression.Condition(condition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public CastedExpressionBindingProperty ConvertExpressionToType(ParsedExpressionB
// if the expression is of type object (i.e. null literal) try the lambda conversion.
convertedExpr != null && expr.Expression.Type != typeof(object) ? convertedExpr :
TypeConversion.MagicLambdaConversion(expr.Expression, destType) ?? convertedExpr ??
TypeConversion.ImplicitConversion(expr.Expression, destType, throwException: true, allowToString: true)!
TypeConversion.EnsureImplicitConversion(expr.Expression, destType, allowToString: true)!
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ public MethodRecognitionResult(int automaticTypeArgCount, int castCount, Express
if (args.Length == i + 1 && hasParamsArrayAttributes && !args[i].Type.IsArray)
{
var converted = positionalArguments.Skip(i)
.Select(a => TypeConversion.ImplicitConversion(a, elm, throwException: true)!)
.Select(a => TypeConversion.EnsureImplicitConversion(a, elm))
.ToArray();
args[i] = NewArrayExpression.NewArrayInit(elm, converted);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static Expression GetBinaryOperator(

if (operation == ExpressionType.Assign)
{
return expressionFactory.UpdateMember(left, TypeConversion.EnsureImplicitConversion(right, left.Type, true)!)
return expressionFactory.UpdateMember(left, TypeConversion.EnsureImplicitConversion(right, left.Type, true))
.NotNull($"Expression '{right}' cannot be assigned into '{left}'.");
}

Expand Down Expand Up @@ -110,11 +110,11 @@ public static Expression GetBinaryOperator(
// numeric operations
if (operation == ExpressionType.LeftShift)
{
return Expression.LeftShift(left, ConvertToMaybeNullable(right, typeof(int), true));
return Expression.LeftShift(left, ConvertToMaybeNullable(right, typeof(int), true)!);
}
else if (operation == ExpressionType.RightShift)
{
return Expression.RightShift(left, ConvertToMaybeNullable(right, typeof(int), true));
return Expression.RightShift(left, ConvertToMaybeNullable(right, typeof(int), true)!);
}

// List of types in order of precendence
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public static Expression BoxToObject(Expression src)

//TODO: Refactor ImplicitConversion usages to EnsureImplicitConversion where applicable to take advantage of nullability
public static Expression EnsureImplicitConversion(Expression src, Type destType, bool allowToString = false)
=> ImplicitConversion(src, destType, true, false)!;
=> ImplicitConversion(src, destType, throwException: true, allowToString: allowToString)!;

// 6.1 Implicit Conversions
public static Expression? ImplicitConversion(Expression src, Type destType, bool throwException = false, bool allowToString = false)
Expand Down
2 changes: 1 addition & 1 deletion src/Framework/Testing/BindingTestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public Expression ParseBinding(string expression, DataContextStack context, Type
var parsedExpression = ExpressionBuilder.ParseWithLambdaConversion(expression, context, BindingParserOptions.Value.AddImports(imports), expectedType);
return
TypeConversion.MagicLambdaConversion(parsedExpression, expectedType) ??
TypeConversion.ImplicitConversion(parsedExpression, expectedType, true, true)!;
TypeConversion.EnsureImplicitConversion(parsedExpression, expectedType, allowToString: true)!;
}

/// <summary> Returns JavaScript code to which the <paramref name="expression" /> translates. </summary>
Expand Down
3 changes: 1 addition & 2 deletions src/Tests/Binding/BindingCompilationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,7 @@ public void BindingCompiler_Errors_AssigningToType()
{
var aggEx = Assert.ThrowsException<BindingPropertyException>(() => ExecuteBinding("System.String = 123", new [] { new TestViewModel() }));
var ex = aggEx.GetBaseException();
StringAssert.Contains(ex.Message, "Could not implicitly convert expression of type int to string");
StringAssert.Contains(ex.Message, "Expression '123' cannot be assigned into 'System.String'.");
}

[TestMethod]
Expand Down Expand Up @@ -1128,7 +1128,6 @@ public void BindingCompiler_OperatorType(string expr, object expectedResult)
var vm = new TestViewModel { IntProp = 100, DoubleProp = 1.5 };
Assert.AreEqual(expectedResult, ExecuteBinding(expr, vm));
}
>>>>>>> ba2cf6708 (Add tests for OperatorResolution)
}
class TestViewModel
{
Expand Down
18 changes: 9 additions & 9 deletions src/Tests/Binding/ImplicitConversionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@ public class ImplicitConversionTests
[TestMethod]
public void Conversion_IntToNullableDouble()
{
TypeConversion.ImplicitConversion(Expression.Parameter(typeof(int)), typeof(double?), throwException: true);
TypeConversion.EnsureImplicitConversion(Expression.Parameter(typeof(int)), typeof(double?));
}

[TestMethod]
public void Conversion_DoubleNullable()
{
TypeConversion.ImplicitConversion(Expression.Parameter(typeof(double)), typeof(double?), throwException: true);
TypeConversion.EnsureImplicitConversion(Expression.Parameter(typeof(double)), typeof(double?));
}

[TestMethod]
public void Conversion_IntToDouble()
{
TypeConversion.ImplicitConversion(Expression.Parameter(typeof(int)), typeof(double), throwException: true);
TypeConversion.EnsureImplicitConversion(Expression.Parameter(typeof(int)), typeof(double));
}

[TestMethod]
public void Conversion_ValidToString()
{
TypeConversion.ImplicitConversion(Expression.Parameter(typeof(DateTime)), typeof(string), throwException: true, allowToString: true);
TypeConversion.ImplicitConversion(Expression.Parameter(typeof(int)), typeof(string), throwException: true, allowToString: true);
TypeConversion.ImplicitConversion(Expression.Parameter(typeof(string)), typeof(string), throwException: true, allowToString: true);
TypeConversion.ImplicitConversion(Expression.Parameter(typeof(double)), typeof(string), throwException: true, allowToString: true);
TypeConversion.ImplicitConversion(Expression.Parameter(typeof(TimeSpan)), typeof(string), throwException: true, allowToString: true);
TypeConversion.ImplicitConversion(Expression.Parameter(typeof(Tuple<int, int>)), typeof(string), throwException: true, allowToString: true);
TypeConversion.EnsureImplicitConversion(Expression.Parameter(typeof(DateTime)), typeof(string), allowToString: true);
TypeConversion.EnsureImplicitConversion(Expression.Parameter(typeof(int)), typeof(string), allowToString: true);
TypeConversion.EnsureImplicitConversion(Expression.Parameter(typeof(string)), typeof(string), allowToString: true);
TypeConversion.EnsureImplicitConversion(Expression.Parameter(typeof(double)), typeof(string), allowToString: true);
TypeConversion.EnsureImplicitConversion(Expression.Parameter(typeof(TimeSpan)), typeof(string), allowToString: true);
TypeConversion.EnsureImplicitConversion(Expression.Parameter(typeof(Tuple<int, int>)), typeof(string), allowToString: true);
}

[TestMethod]
Expand Down

0 comments on commit 81c264b

Please sign in to comment.