1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Apache License, Version 2.0, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Apache License, Version 2.0.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Dynamic.Utils;
18 using System.Diagnostics;
21 namespace Microsoft.Scripting.Ast {
23 namespace System.Linq.Expressions {
27 /// Represents an expression that has a conditional operator.
29 [DebuggerTypeProxy(typeof(Expression.ConditionalExpressionProxy))]
30 public class ConditionalExpression : Expression {
31 private readonly Expression _test;
32 private readonly Expression _true;
34 internal ConditionalExpression(Expression test, Expression ifTrue) {
39 internal static ConditionalExpression Make(Expression test, Expression ifTrue, Expression ifFalse, Type type) {
40 if (ifTrue.Type != type || ifFalse.Type != type) {
41 return new FullConditionalExpressionWithType(test, ifTrue, ifFalse, type);
42 } if (ifFalse is DefaultExpression && ifFalse.Type == typeof(void)) {
43 return new ConditionalExpression(test, ifTrue);
45 return new FullConditionalExpression(test, ifTrue, ifFalse);
50 /// Returns the node type of this Expression. Extension nodes should return
51 /// ExpressionType.Extension when overriding this method.
53 /// <returns>The <see cref="ExpressionType"/> of the expression.</returns>
54 public sealed override ExpressionType NodeType {
55 get { return ExpressionType.Conditional; }
59 /// Gets the static type of the expression that this <see cref="Expression" /> represents.
61 /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
62 public override Type Type {
63 get { return IfTrue.Type; }
67 /// Gets the test of the conditional operation.
69 public Expression Test {
73 /// Gets the expression to execute if the test evaluates to true.
75 public Expression IfTrue {
79 /// Gets the expression to execute if the test evaluates to false.
81 public Expression IfFalse {
82 get { return GetFalse(); }
85 internal virtual Expression GetFalse() {
86 return Expression.Empty();
90 /// Dispatches to the specific visit method for this node type.
92 protected internal override Expression Accept(ExpressionVisitor visitor) {
93 return visitor.VisitConditional(this);
97 /// Creates a new expression that is like this one, but using the
98 /// supplied children. If all of the children are the same, it will
99 /// return this expression.
101 /// <param name="test">The <see cref="Test" /> property of the result.</param>
102 /// <param name="ifTrue">The <see cref="IfTrue" /> property of the result.</param>
103 /// <param name="ifFalse">The <see cref="IfFalse" /> property of the result.</param>
104 /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
105 public ConditionalExpression Update(Expression test, Expression ifTrue, Expression ifFalse) {
106 if (test == Test && ifTrue == IfTrue && ifFalse == IfFalse) {
109 return Expression.Condition(test, ifTrue, ifFalse, Type);
113 internal class FullConditionalExpression : ConditionalExpression {
114 private readonly Expression _false;
116 internal FullConditionalExpression(Expression test, Expression ifTrue, Expression ifFalse)
117 : base(test, ifTrue) {
121 internal override Expression GetFalse() {
126 internal class FullConditionalExpressionWithType : FullConditionalExpression {
127 private readonly Type _type;
129 internal FullConditionalExpressionWithType(Expression test, Expression ifTrue, Expression ifFalse, Type type)
130 : base(test, ifTrue, ifFalse) {
134 public sealed override Type Type {
135 get { return _type; }
139 public partial class Expression {
142 /// Creates a <see cref="ConditionalExpression"/>.
144 /// <param name="test">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.Test"/> property equal to.</param>
145 /// <param name="ifTrue">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfTrue"/> property equal to.</param>
146 /// <param name="ifFalse">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfFalse"/> property equal to.</param>
147 /// <returns>A <see cref="ConditionalExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to
148 /// <see cref="F:ExpressionType.Conditional"/> and the <see cref="P:ConditionalExpression.Test"/>, <see cref="P:ConditionalExpression.IfTrue"/>,
149 /// and <see cref="P:ConditionalExpression.IfFalse"/> properties set to the specified values.</returns>
150 public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse) {
151 RequiresCanRead(test, "test");
152 RequiresCanRead(ifTrue, "ifTrue");
153 RequiresCanRead(ifFalse, "ifFalse");
155 if (test.Type != typeof(bool)) {
156 throw Error.ArgumentMustBeBoolean();
158 if (!TypeUtils.AreEquivalent(ifTrue.Type, ifFalse.Type)) {
159 throw Error.ArgumentTypesMustMatch();
162 return ConditionalExpression.Make(test, ifTrue, ifFalse, ifTrue.Type);
167 /// Creates a <see cref="ConditionalExpression"/>.
169 /// <param name="test">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.Test"/> property equal to.</param>
170 /// <param name="ifTrue">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfTrue"/> property equal to.</param>
171 /// <param name="ifFalse">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfFalse"/> property equal to.</param>
172 /// <param name="type">A <see cref="Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
173 /// <returns>A <see cref="ConditionalExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to
174 /// <see cref="F:ExpressionType.Conditional"/> and the <see cref="P:ConditionalExpression.Test"/>, <see cref="P:ConditionalExpression.IfTrue"/>,
175 /// and <see cref="P:ConditionalExpression.IfFalse"/> properties set to the specified values.</returns>
176 /// <remarks>This method allows explicitly unifying the result type of the conditional expression in cases where the types of <paramref name="ifTrue"/>
177 /// and <paramref name="ifFalse"/> expressions are not equal. Types of both <paramref name="ifTrue"/> and <paramref name="ifFalse"/> must be implicitly
178 /// reference assignable to the result type. The <paramref name="type"/> is allowed to be <see cref="System.Void"/>.</remarks>
179 public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse, Type type) {
180 RequiresCanRead(test, "test");
181 RequiresCanRead(ifTrue, "ifTrue");
182 RequiresCanRead(ifFalse, "ifFalse");
183 ContractUtils.RequiresNotNull(type, "type");
185 if (test.Type != typeof(bool)) {
186 throw Error.ArgumentMustBeBoolean();
189 if (type != typeof(void)) {
190 if (!TypeUtils.AreReferenceAssignable(type, ifTrue.Type) ||
191 !TypeUtils.AreReferenceAssignable(type, ifFalse.Type)) {
192 throw Error.ArgumentTypesMustMatch();
196 return ConditionalExpression.Make(test, ifTrue, ifFalse, type);
200 /// Creates a <see cref="ConditionalExpression"/>.
202 /// <param name="test">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.Test"/> property equal to.</param>
203 /// <param name="ifTrue">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfTrue"/> property equal to.</param>
204 /// <returns>A <see cref="ConditionalExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to
205 /// <see cref="F:ExpressionType.Conditional"/> and the <see cref="P:ConditionalExpression.Test"/>, <see cref="P:ConditionalExpression.IfTrue"/>,
206 /// properties set to the specified values. The <see cref="P:ConditionalExpression.IfFalse"/> property is set to default expression and
207 /// the type of the resulting <see cref="ConditionalExpression"/> returned by this method is <see cref="System.Void"/>.</returns>
208 public static ConditionalExpression IfThen(Expression test, Expression ifTrue) {
209 return Condition(test, ifTrue, Expression.Empty(), typeof(void));
213 /// Creates a <see cref="ConditionalExpression"/>.
215 /// <param name="test">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.Test"/> property equal to.</param>
216 /// <param name="ifTrue">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfTrue"/> property equal to.</param>
217 /// <param name="ifFalse">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfFalse"/> property equal to.</param>
218 /// <returns>A <see cref="ConditionalExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to
219 /// <see cref="F:ExpressionType.Conditional"/> and the <see cref="P:ConditionalExpression.Test"/>, <see cref="P:ConditionalExpression.IfTrue"/>,
220 /// and <see cref="P:ConditionalExpression.IfFalse"/> properties set to the specified values. The type of the resulting <see cref="ConditionalExpression"/>
221 /// returned by this method is <see cref="System.Void"/>.</returns>
222 public static ConditionalExpression IfThenElse(Expression test, Expression ifTrue, Expression ifFalse) {
223 return Condition(test, ifTrue, ifFalse, typeof(void));