protected internal override Expression VisitBinaryAssign(AssignBinaryCSharpExpression node) { var args = new List <object>(); if (node.IsLifted) { args.Add(new XAttribute(nameof(node.IsLifted), node.IsLifted)); } if (node.IsLiftedToNull) { args.Add(new XAttribute(nameof(node.IsLiftedToNull), node.IsLiftedToNull)); } if (node.Method != null) { args.Add(new XAttribute(nameof(node.Method), node.Method)); } args.Add(new XElement(nameof(node.Left), Visit(node.Left))); args.Add(new XElement(nameof(node.Right), Visit(node.Right))); if (node.LeftConversion != null) { args.Add(new XElement(nameof(node.LeftConversion), Visit(node.LeftConversion))); } if (node.FinalConversion != null) { args.Add(new XElement(nameof(node.FinalConversion), Visit(node.FinalConversion))); } return(Push(node, args)); }
public AssignBinaryCSharpExpressionProxy(AssignBinaryCSharpExpression node) { _node = node; }
protected internal virtual Expression VisitBinaryAssign(AssignBinaryCSharpExpression node) { return(node.Update(Visit(node.Left), VisitAndConvert(node.LeftConversion, nameof(VisitBinaryAssign)), Visit(node.Right), VisitAndConvert(node.FinalConversion, nameof(VisitBinaryAssign)))); }
private static AssignBinaryCSharpExpression MakeBinaryAssignCore(CSharpExpressionType binaryType, Expression left, Expression right, MethodInfo method, LambdaExpression finalConversion, LambdaExpression leftConversion) { Helpers.RequiresCanWrite(left, nameof(left)); RequiresCanRead(right, nameof(right)); // NB: We could return a BinaryExpression in case the lhs is not one of our index nodes, but it'd change // the return type to Expression which isn't nice to consume. Also, the Update method would either // have to change to return Expression or we should have an AssignBinary node to hold a Binary node // underneath it. This said, a specialized layout for the case where the custom node trivially wraps // a LINQ node could be useful (just make Left virtual). if (binaryType != CSharpExpressionType.Assign) { var leftType = left.Type; var rightType = right.Type; if (leftType == typeof(string)) { if (method == null) { if (binaryType == CSharpExpressionType.AddAssign || binaryType == CSharpExpressionType.AddAssignChecked) { if (rightType == typeof(string)) { method = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) }); } else { method = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(object) }); if (!TypeUtils1.AreReferenceAssignable(typeof(object), rightType)) { // DESIGN: Should our factory do this our just reject the input? right = Expression.Convert(right, typeof(object)); } } } else { throw Error.InvalidCompoundAssignment(binaryType, typeof(string)); } } } else if (typeof(MulticastDelegate).IsAssignableFrom(leftType)) { if (leftType == typeof(MulticastDelegate)) { throw Error.InvalidCompoundAssignmentWithOperands(binaryType, leftType, rightType); } // NB: This checks for assignment with variance checks in mind, e.g. // // Action<string> s = ...; // Action<object> o = ...; // s += o; if (!TypeUtils1.AreReferenceAssignable(leftType, rightType)) { throw Error.InvalidCompoundAssignmentWithOperands(binaryType, leftType, rightType); } if (method == null) { if (binaryType == CSharpExpressionType.AddAssign || binaryType == CSharpExpressionType.AddAssignChecked) { method = typeof(Delegate).GetMethod(nameof(Delegate.Combine), new[] { typeof(Delegate), typeof(Delegate) }); } else if (binaryType == CSharpExpressionType.SubtractAssign || binaryType == CSharpExpressionType.SubtractAssignChecked) { method = typeof(Delegate).GetMethod(nameof(Delegate.Remove), new[] { typeof(Delegate), typeof(Delegate) }); } else { throw Error.InvalidCompoundAssignment(binaryType, leftType); } if (finalConversion == null) { var resultParameter = Expression.Parameter(typeof(Delegate), "__result"); var convertResult = Expression.Convert(resultParameter, leftType); finalConversion = Expression.Lambda(convertResult, resultParameter); } } } else if (IsCSharpSpecificCompoundNumeric(leftType)) { // NB: If any of these are passed, we'll assume the types all line up. The call to // the ValidateCustomBinaryAssign method below will check that's indeed the case. if (method == null && leftConversion == null && finalConversion == null) { var isChecked = IsCheckedBinary(binaryType); var isNullabeLeftType = leftType.IsNullableType(); var nonNullLeftType = leftType.GetNonNullableType(); var intermediateType = nonNullLeftType.IsEnum ? nonNullLeftType.GetEnumUnderlyingType() : typeof(int); var leftParameter = Expression.Parameter(leftType, "__left"); var convertType = isNullabeLeftType ? typeof(Nullable <>).MakeGenericType(intermediateType) : intermediateType; var convertLeft = isChecked ? Expression.ConvertChecked(leftParameter, convertType) : Expression.Convert(leftParameter, convertType); leftConversion = Expression.Lambda(convertLeft, leftParameter); var resultParameter = Expression.Parameter(convertType, "__result"); var convertResult = isChecked ? Expression.ConvertChecked(resultParameter, leftType) : Expression.Convert(resultParameter, leftType); finalConversion = Expression.Lambda(convertResult, resultParameter); if (rightType != convertType) { // DESIGN: Should our factory do this or just reject the input? On the one hand, // C# allows e.g. byte += byte, so if this is a C#-specific API it may be // reasonable for the user to expect such a tree can be built. On the // other hand, it's very unlike the expression tree API to insert nodes // on behalf of the user in the factories. Note that Roslyn often models // conversions as properties on a node using a `Conversion` objects // which would be handy to keep the shape from the tree isomorphic to the // bound nodes in the compiler. Note though that the RHS of a compound // assignment doesn't have such a conversion and the compiler will insert // a convert node in this case, so this is really just a convenience in // our factory method to mimic that behavior. right = Expression.Convert(right, convertType); } } } } return(AssignBinaryCSharpExpression.Make(binaryType, left, right, method, leftConversion, finalConversion)); }
public AssignBinaryCSharpExpressionProxy(AssignBinaryCSharpExpression node) { _node = node; }
protected internal virtual Expression VisitBinaryAssign(AssignBinaryCSharpExpression node) { return node.Update(Visit(node.Left), VisitAndConvert(node.LeftConversion, nameof(VisitBinaryAssign)), Visit(node.Right), VisitAndConvert(node.FinalConversion, nameof(VisitBinaryAssign))); }