private static void Validate(Type type, bool allowByRef) { ContractUtils.RequiresNotNull(type, nameof(type)); TypeUtils.ValidateType(type, nameof(type), allowByRef, allowPointer: false); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(nameof(type)); } }
private static void Validate(Type type, bool allowByRef) { ArgumentNullException.ThrowIfNull(type); TypeUtils.ValidateType(type, nameof(type), allowByRef, allowPointer: false); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(nameof(type)); } }
/// <summary> /// Creates a <see cref="NewArrayExpression"/> of the specified type from the provided initializers. /// </summary> /// <param name="type">A Type that represents the element type of the array.</param> /// <param name="initializers">The expressions used to create the array elements.</param> /// <returns>A <see cref="NewArrayExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="ExpressionType.NewArrayInit"/> and the <see cref="NewArrayExpression.Expressions"/> property set to the specified value.</returns> public static NewArrayExpression NewArrayInit(Type type, IEnumerable <Expression> initializers) { ContractUtils.RequiresNotNull(type, nameof(type)); ContractUtils.RequiresNotNull(initializers, nameof(initializers)); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(nameof(type)); } TypeUtils.ValidateType(type, nameof(type)); if (type.IsByRef) { throw Error.TypeMustNotBeByRef(nameof(type)); } if (type.IsPointer) { throw Error.TypeMustNotBePointer(nameof(type)); } ReadOnlyCollection <Expression> initializerList = initializers.ToReadOnly(); Expression[] newList = null; for (int i = 0, n = initializerList.Count; i < n; i++) { Expression expr = initializerList[i]; RequiresCanRead(expr, nameof(initializers), i); if (!TypeUtils.AreReferenceAssignable(type, expr.Type)) { if (!TryQuote(type, ref expr)) { throw Error.ExpressionTypeCannotInitializeArrayType(expr.Type, type); } if (newList == null) { newList = new Expression[initializerList.Count]; for (int j = 0; j < i; j++) { newList[j] = initializerList[j]; } } } if (newList != null) { newList[i] = expr; } } if (newList != null) { initializerList = new TrueReadOnlyCollection <Expression>(newList); } return(NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList)); }
/// <summary> /// Creates a <see cref="NewArrayExpression"/> that represents creating an array that has a specified rank. /// </summary> /// <param name="type">A <see cref="System.Type"/> that represents the element type of the array.</param> /// <param name="bounds">An <see cref="IEnumerable{T}"/> that contains <see cref="Expression"/> objects to use to populate the <see cref="NewArrayExpression.Expressions"/> collection.</param> /// <returns>A <see cref="NewArrayExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="ExpressionType.NewArrayBounds"/> and the <see cref="NewArrayExpression.Expressions"/> property set to the specified value.</returns> public static NewArrayExpression NewArrayBounds(Type type, IEnumerable <Expression> bounds) { ContractUtils.RequiresNotNull(type, nameof(type)); ContractUtils.RequiresNotNull(bounds, nameof(bounds)); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(nameof(type)); } TypeUtils.ValidateType(type, nameof(type)); if (type.IsByRef) { throw Error.TypeMustNotBeByRef(nameof(type)); } if (type.IsPointer) { throw Error.TypeMustNotBePointer(nameof(type)); } ReadOnlyCollection <Expression> boundsList = bounds.ToReadOnly(); int dimensions = boundsList.Count; if (dimensions <= 0) { throw Error.BoundsCannotBeLessThanOne(nameof(bounds)); } for (int i = 0; i < dimensions; i++) { Expression expr = boundsList[i]; RequiresCanRead(expr, nameof(bounds), i); if (!TypeUtils.IsInteger(expr.Type)) { throw Error.ArgumentMustBeInteger(nameof(bounds), i); } } Type arrayType; if (dimensions == 1) { //To get a vector, need call Type.MakeArrayType(). //Type.MakeArrayType(1) gives a non-vector array, which will cause type check error. arrayType = type.MakeArrayType(); } else { arrayType = type.MakeArrayType(dimensions); } return(NewArrayExpression.Make(ExpressionType.NewArrayBounds, arrayType, bounds.ToReadOnly())); }
/// <summary> /// Creates a <see cref="ParameterExpression" /> node that can be used to identify a parameter or a variable in an expression tree. /// </summary> /// <param name="type">The type of the parameter or variable.</param> /// <param name="name">The name of the parameter or variable, used for debugging or pretty printing purpose only.</param> /// <returns>A <see cref="ParameterExpression" /> node with the specified name and type.</returns> public static ParameterExpression Variable(Type type, string name) { ContractUtils.RequiresNotNull(type, "type"); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(); } if (type.IsByRef) { throw Error.TypeMustNotBeByRef(); } return(ParameterExpression.Make(type, name, false)); }
private static void Validate(Type type) { ContractUtils.RequiresNotNull(type, nameof(type)); TypeUtils.ValidateType(type, nameof(type)); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(nameof(type)); } if (type.IsPointer) { throw Error.TypeMustNotBePointer(nameof(type)); } }
/// <summary> /// Creates a new array expression of the specified type from the provided initializers. /// </summary> /// <param name="type">A Type that represents the element type of the array.</param> /// <param name="initializers">The expressions used to create the array elements.</param> public static NewArrayExpression NewArrayInit(Type type, IEnumerable <Expression> initializers) { ContractUtils.RequiresNotNull(type, "type"); ContractUtils.RequiresNotNull(initializers, "initializers"); if (type.Equals(typeof(void))) { throw Error.ArgumentCannotBeOfTypeVoid(); } ReadOnlyCollection <Expression> initializerList = initializers.ToReadOnly(); Expression[] newList = null; for (int i = 0, n = initializerList.Count; i < n; i++) { Expression expr = initializerList[i]; RequiresCanRead(expr, "initializers"); if (!TypeUtils.AreReferenceAssignable(type, expr.Type)) { if (TypeUtils.IsSameOrSubclass(typeof(Expression), type) && type.IsAssignableFrom(expr.GetType())) { expr = Expression.Quote(expr); } else { throw Error.ExpressionTypeCannotInitializeArrayType(expr.Type, type); } if (newList == null) { newList = new Expression[initializerList.Count]; for (int j = 0; j < i; j++) { newList[j] = initializerList[j]; } } } if (newList != null) { newList[i] = expr; } } if (newList != null) { initializerList = new ReadOnlyCollection <Expression>(newList); } return(NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList)); }
/// <summary> /// Creates a new array expression of the specified type from the provided initializers. /// </summary> /// <param name="type">A Type that represents the element type of the array.</param> /// <param name="initializers">The expressions used to create the array elements.</param> /// <returns>An instance of the <see cref="NewArrayExpression"/>.</returns> public static NewArrayExpression NewArrayInit(Type type, IEnumerable <Expression> initializers) { ContractUtils.RequiresNotNull(type, "type"); ContractUtils.RequiresNotNull(initializers, "initializers"); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(); } var initializerList = initializers.ToReadOnly(); Expression[] newList = null; var n = initializerList.Count; for (var i = 0; i < n; i++) { var expr = initializerList[i]; RequiresCanRead(expr, "initializers"); if (!TypeHelper.AreReferenceAssignable(type, expr.Type)) { if (!TryQuote(type, ref expr)) { throw Error.ExpressionTypeCannotInitializeArrayType(expr.Type, type); } if (newList == null) { newList = new Expression[n]; for (var j = 0; j < i; j++) { newList[j] = initializerList[j]; } } } if (newList != null) { newList[i] = expr; } } if (newList != null) { initializerList = new TrueReadOnlyCollection <Expression>(newList); } return(NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList)); }
/// <summary> /// Creates a <see cref="ParameterExpression" /> node that can be used to identify a parameter or a variable in an expression tree. /// </summary> /// <param name="type">The type of the parameter or variable.</param> /// <param name="name">The name of the parameter or variable, used for debugging or pretty printing purpose only.</param> /// <returns>A <see cref="ParameterExpression" /> node with the specified name and type.</returns> public static ParameterExpression Parameter(Type type, string name) { ContractUtils.RequiresNotNull(type, "type"); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(); } bool byref = type.IsByRef; if (byref) { type = type.GetElementType(); } return(ParameterExpression.Make(type, name, byref)); }
/// <summary> /// Creates a <see cref="NewExpression"/> that represents calling the parameterless constructor of the specified type. /// </summary> /// <param name="type">A <see cref="Type"/> that has a constructor that takes no arguments. </param> /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to New and the Constructor property set to the ConstructorInfo that represents the parameterless constructor of the specified type.</returns> public static NewExpression New(Type type) { ContractUtils.RequiresNotNull(type, "type"); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(); } if (!type.IsValueType) { var constructorInfo = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).SingleOrDefault(c => c.GetParameters().Length == 0); if (constructorInfo == null) { throw Error.TypeMissingDefaultConstructor(type); } return(New(constructorInfo)); } return(new NewValueTypeExpression(type, EmptyCollection <Expression> .Instance, null)); }
/// <summary> /// Creates a <see cref="NewArrayExpression"/> that represents creating an array that has a specified rank. /// </summary> /// <param name="type">A <see cref="Type"/> that represents the element type of the array.</param> /// <param name="bounds">An IEnumerable{T} that contains Expression objects to use to populate the Expressions collection.</param> /// <returns>A <see cref="NewArrayExpression"/> that has the <see cref="P:NodeType"/> property equal to type and the <see cref="P:Expressions"/> property set to the specified value.</returns> public static NewArrayExpression NewArrayBounds(Type type, IEnumerable <Expression> bounds) { ContractUtils.RequiresNotNull(type, "type"); ContractUtils.RequiresNotNull(bounds, "bounds"); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(); } var boundsList = bounds.ToReadOnly(); var dimensions = boundsList.Count; if (dimensions <= 0) { throw Error.BoundsCannotBeLessThanOne(); } for (var i = 0; i < dimensions; i++) { var expr = boundsList[i]; RequiresCanRead(expr, "bounds"); if (!expr.Type.IsInteger()) { throw Error.ArgumentMustBeInteger(); } } Type arrayType; if (dimensions == 1) { //To get a vector, need call Type.MakeArrayType(). //Type.MakeArrayType(1) gives a non-vector array, which will cause type check error. arrayType = type.MakeArrayType(); } else { arrayType = type.MakeArrayType(dimensions); } return(NewArrayExpression.Make(ExpressionType.NewArrayBounds, arrayType, boundsList)); }
//CONFORMING public static NewExpression New(Type type) { ContractUtils.RequiresNotNull(type, "type"); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(); } ConstructorInfo ci = null; if (!type.IsValueType) { ci = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, System.Type.EmptyTypes, null); if (ci == null) { throw Error.TypeMissingDefaultConstructor(type); } return(New(ci)); } return(new NewValueTypeExpression(type, EmptyReadOnlyCollection <Expression> .Instance, null)); }
/// <summary> /// Creates a <see cref="NewExpression"/> that represents calling the parameterless constructor of the specified type. /// </summary> /// <param name="type">A <see cref="Type"/> that has a constructor that takes no arguments. </param> /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to New and the Constructor property set to the ConstructorInfo that represents the parameterless constructor of the specified type.</returns> public static NewExpression New(Type type) { ContractUtils.RequiresNotNull(type, "type"); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(); } ConstructorInfo ci = null; if (!type.GetTypeInfo().IsValueType) { ci = type.GetConstructor(Array.Empty <Type>()); if (ci == null) { throw Error.TypeMissingDefaultConstructor(type); } return(New(ci)); } return(new NewValueTypeExpression(type, EmptyReadOnlyCollection <Expression> .Instance, null)); }
/// <summary> /// Creates a <see cref="NewExpression"/> that represents calling the parameterless constructor of the specified type. /// </summary> /// <param name="type">A <see cref="Type"/> that has a constructor that takes no arguments.</param> /// <returns>A <see cref="NewExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="ExpressionType.New"/> and the <see cref="NewExpression.Constructor"/> property set to the <see cref="ConstructorInfo"/> that represents the parameterless constructor of the specified type.</returns> public static NewExpression New(Type type) { ContractUtils.RequiresNotNull(type, nameof(type)); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(nameof(type)); } TypeUtils.ValidateType(type, nameof(type)); if (!type.GetTypeInfo().IsValueType) { ConstructorInfo ci = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).SingleOrDefault(c => c.GetParametersCached().Length == 0); if (ci == null) { throw Error.TypeMissingDefaultConstructor(type, nameof(type)); } return(New(ci)); } return(new NewValueTypeExpression(type, EmptyReadOnlyCollection <Expression> .Instance, null)); }
/// <summary> /// Creates a <see cref="ParameterExpression"/> node that can be used to identify a parameter or a variable in an expression tree. /// </summary> /// <param name="type">The type of the parameter or variable.</param> /// <param name="name">The name of the parameter or variable, used for debugging or pretty printing purpose only.</param> /// <returns>A <see cref="ParameterExpression"/> node with the specified name and type.</returns> public static ParameterExpression Variable(Type type, string name) { ContractUtils.RequiresNotNull(type, nameof(type)); TypeUtils.ValidateType(type, nameof(type)); if (type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(nameof(type)); } if (type.IsByRef) { throw Error.TypeMustNotBeByRef(nameof(type)); } if (type.IsPointer) { throw Error.TypeMustNotBePointer(nameof(type)); } return(ParameterExpression.Make(type, name, isByRef: false)); }
public static SwitchCSharpStatement Switch(Expression switchValue, LabelTarget breakLabel, IEnumerable <ParameterExpression> variables, IEnumerable <CSharpSwitchCase> cases) { RequiresCanRead(switchValue, nameof(switchValue)); RequiresNotNull(breakLabel, nameof(breakLabel)); if (switchValue.Type == typeof(void)) { throw LinqError.ArgumentCannotBeOfTypeVoid(); } if (breakLabel.Type != typeof(void)) { throw Error.SwitchBreakLabelShouldBeVoid(); } var type = switchValue.Type; CheckValidSwitchType(type); var isNullable = type == typeof(string) || type.IsNullableType(); var nonNullType = type.GetNonNullableType(); // NB: Switch in C# can be empty, so less checks than LINQ here. Also no custom comparison method. var casesList = cases.ToReadOnly(); if (casesList.Count > 0) { var testValues = new HashSet <object>(); foreach (var @case in casesList) { RequiresNotNull(@case, nameof(cases)); foreach (var value in @case.TestValues) { if (!testValues.Add(value)) { throw Error.DuplicateTestValue(value.ToDebugString()); } if (value == null) { if (!isNullable) { throw Error.SwitchCantHaveNullCase(type); } } else if (value != SwitchCaseDefaultValue) { var valueType = value.GetType().GetNonNullableType(); if (valueType != nonNullType) { throw Error.SwitchCaseHasIncompatibleType(value.GetType(), type); } } } } } var variableList = CheckUniqueVariables(variables, nameof(variables)); return(new SwitchCSharpStatement(switchValue, breakLabel, variableList, casesList)); }
/// <summary> /// Creates a <see cref="SwitchExpression"/>. /// </summary> /// <param name="type">The result type of the switch.</param> /// <param name="switchValue">The value to be tested against each case.</param> /// <param name="defaultBody">The result of the switch if no cases are matched.</param> /// <param name="comparison">The equality comparison method to use.</param> /// <param name="cases">The valid cases for this switch.</param> /// <returns>The created <see cref="SwitchExpression"/>.</returns> public static SwitchExpression Switch(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable <SwitchCase> cases) { RequiresCanRead(switchValue, nameof(switchValue)); if (switchValue.Type == typeof(void)) { throw Error.ArgumentCannotBeOfTypeVoid(); } var caseList = cases.ToReadOnly(); ContractUtils.RequiresNotNullItems(caseList, nameof(cases)); // Type of the result. Either provided, or it is type of the branches. Type resultType; if (type != null) { resultType = type; } else if (caseList.Count != 0) { resultType = caseList[0].Body.Type; } else if (defaultBody != null) { resultType = defaultBody.Type; } else { resultType = typeof(void); } bool customType = type != null; if (comparison != null) { var pms = comparison.GetParametersCached(); if (pms.Length != 2) { throw Error.IncorrectNumberOfMethodCallArguments(comparison); } // Validate that the switch value's type matches the comparison method's // left hand side parameter type. var leftParam = pms[0]; bool liftedCall = false; if (!ParameterIsAssignable(leftParam, switchValue.Type)) { liftedCall = ParameterIsAssignable(leftParam, switchValue.Type.GetNonNullableType()); if (!liftedCall) { throw Error.SwitchValueTypeDoesNotMatchComparisonMethodParameter(switchValue.Type, leftParam.ParameterType); } } var rightParam = pms[1]; foreach (var c in caseList) { ContractUtils.RequiresNotNull(c, nameof(cases)); ValidateSwitchCaseType(c.Body, customType, resultType, nameof(cases)); for (int i = 0; i < c.TestValues.Count; i++) { // When a comparison method is provided, test values can have different type but have to // be reference assignable to the right hand side parameter of the method. Type rightOperandType = c.TestValues[i].Type; if (liftedCall) { if (!rightOperandType.IsNullableType()) { throw Error.TestValueTypeDoesNotMatchComparisonMethodParameter(rightOperandType, rightParam.ParameterType); } rightOperandType = rightOperandType.GetNonNullableType(); } if (!ParameterIsAssignable(rightParam, rightOperandType)) { throw Error.TestValueTypeDoesNotMatchComparisonMethodParameter(rightOperandType, rightParam.ParameterType); } } } } else if (caseList.Count != 0) { // When comparison method is not present, all the test values must have // the same type. Use the first test value's type as the baseline. var firstTestValue = caseList[0].TestValues[0]; foreach (var c in caseList) { ContractUtils.RequiresNotNull(c, nameof(cases)); ValidateSwitchCaseType(c.Body, customType, resultType, nameof(cases)); // When no comparison method is provided, require all test values to have the same type. for (int i = 0; i < c.TestValues.Count; i++) { if (!TypeUtils.AreEquivalent(firstTestValue.Type, c.TestValues[i].Type)) { throw new ArgumentException(Strings.AllTestValuesMustHaveSameType, nameof(cases)); } } } // Now we need to validate that switchValue.Type and testValueType // make sense in an Equal node. Fortunately, Equal throws a // reasonable error, so just call it. var equal = Equal(switchValue, firstTestValue, false, comparison); // Get the comparison function from equals node. comparison = equal.Method; } if (defaultBody == null) { if (resultType != typeof(void)) { throw Error.DefaultBodyMustBeSupplied(); } } else { ValidateSwitchCaseType(defaultBody, customType, resultType, nameof(defaultBody)); } // if we have a non-boolean user-defined equals, we don't want it. if (comparison != null && comparison.ReturnType != typeof(bool)) { throw Error.EqualityMustReturnBoolean(comparison); } return(new SwitchExpression(resultType, switchValue, defaultBody, comparison, caseList)); }
public static NewMultidimensionalArrayInitCSharpExpression NewMultidimensionalArrayInit(Type type, IEnumerable <int> bounds, IEnumerable <Expression> initializers) { ContractUtils.RequiresNotNull(type, nameof(type)); ContractUtils.RequiresNotNull(bounds, nameof(bounds)); ContractUtils.RequiresNotNull(initializers, nameof(initializers)); if (type.Equals(typeof(void))) { throw LinqError.ArgumentCannotBeOfTypeVoid(); } var boundsList = bounds.ToReadOnly(); int dimensions = boundsList.Count; if (dimensions <= 0) { throw LinqError.BoundsCannotBeLessThanOne(); } var length = 1; foreach (var bound in boundsList) { if (bound < 0) { throw Error.BoundCannotBeLessThanZero(); } checked { length *= bound; } } var initializerList = initializers.ToReadOnly(); if (initializerList.Count != length) { throw Error.ArrayBoundsElementCountMismatch(); } var newList = default(Expression[]); for (int i = 0, n = initializerList.Count; i < n; i++) { var expr = initializerList[i]; RequiresCanRead(expr, nameof(initializers)); if (!TypeUtils.AreReferenceAssignable(type, expr.Type)) { if (!TryQuote(type, ref expr)) { throw LinqError.ExpressionTypeCannotInitializeArrayType(expr.Type, type); } if (newList == null) { newList = new Expression[initializerList.Count]; for (int j = 0; j < i; j++) { newList[j] = initializerList[j]; } } } if (newList != null) { newList[i] = expr; } } if (newList != null) { initializerList = new TrueReadOnlyCollection <Expression>(newList); } return(new NewMultidimensionalArrayInitCSharpExpression(type.MakeArrayType(boundsList.Count), boundsList, initializerList)); }