static void CheckOperand(Expression operand, string paramName, ref int operandCount, ref bool lifted) { if (operand == null) { return; } operandCount++; ExpressionStubs.RequiresCanRead(operand, paramName); if (operand.Type != typeof(Index) && operand.Type != typeof(Index?)) { throw Error.InvalidRangeOperandType(operand.Type); } if (operand.Type.IsNullableType()) { lifted = true; } }
public static void RequiresCanWrite(Expression expression, string paramName) { // NB: This does not account for dynamic member and index nodes; to make dynamically bound assignments, // one should use the appropriate methods on DynamicCSharpExpression, which require the use of // dynamic arguments and also allow to separate the dynamic API from the rest of the nodes without // having a strange circular dependency. if (expression is DiscardCSharpExpression) { return; } else if (expression is IndexCSharpExpression index) { EnsureCanWrite(index, paramName); } else { // NB: Our current modification of the Roslyn compiler can emit these nodes as the LHS of an // assignment. We can deal with this in reduction steps by rewriting it to ArrayAccess // using MakeWriteable below. if (expression.NodeType == ExpressionType.ArrayIndex) { return; } if (expression.NodeType == ExpressionType.Call) { var call = (MethodCallExpression)expression; if (IsArrayAssignment(call)) { return; } } ExpressionStubs.RequiresCanWrite(expression, paramName); } }
/// <summary> /// Creates a <see cref="FromEndIndexCSharpExpression"/> that represents an index from the end of an indexable object. /// </summary> /// <param name="operand">The expression representing the index value.</param> /// <param name="method">The method or constructor used to instantiate the index.</param> /// <param name="type">The index type, either <see cref="System.Index"/> or <see cref="System.Index?"/>.</param> /// <returns>The created <see cref="FromEndIndexCSharpExpression"/>.</returns> public static FromEndIndexCSharpExpression FromEndIndex(Expression operand, MethodBase method, Type type) { ExpressionStubs.RequiresCanRead(operand, nameof(operand)); if (operand.Type != typeof(int) && operand.Type != typeof(int?)) { throw Error.InvalidFromEndIndexOperandType(operand.Type); } if (method != null) { if (method.IsGenericMethodDefinition || method.GetReturnType() != typeof(Index)) { throw Error.InvalidFromEndIndexMethod(); } if (method.MemberType == MemberTypes.Method && !method.IsStatic) { throw Error.InvalidFromEndIndexMethod(); } var parameters = method.GetParametersCached(); switch (parameters.Length) { case 1: if (parameters[0].ParameterType != typeof(int)) { throw Error.InvalidFromEndIndexMethod(); } break; case 2: if (parameters[0].ParameterType != typeof(int) || parameters[1].ParameterType != typeof(bool)) { throw Error.InvalidFromEndIndexMethod(); } break; default: throw Error.InvalidFromEndIndexMethod(); } } if (type != null) { if (type == typeof(Index)) { if (operand.Type != typeof(int)) { throw Error.InvalidIndexType(type); } } else if (type == typeof(Index?)) { if (operand.Type != typeof(int?)) { throw Error.InvalidIndexType(type); } } else { throw Error.InvalidIndexType(type); } } return(new FromEndIndexCSharpExpression(operand, method, type)); }
public static void RequiresCanRead(Expression expression, string paramName) { ExpressionStubs.RequiresCanRead(expression, paramName); }