New tests.
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Compiler / ConstantCheck.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Microsoft Public License. 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  Microsoft Public License, 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 Microsoft Public License.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 using System;
17 using System.Diagnostics;
18 using System.Dynamic.Utils;
19
20 #if CLR2
21 namespace Microsoft.Scripting.Ast {
22 #else
23 namespace System.Linq.Expressions {
24 #endif
25
26     internal enum AnalyzeTypeIsResult {
27         KnownFalse,
28         KnownTrue,
29         KnownAssignable, // need null check only
30         Unknown,         // need full runtime check
31     }
32
33     internal static class ConstantCheck {
34
35         internal static bool IsNull(Expression e) {
36             if (e.NodeType == ExpressionType.Constant) {
37                 return ((ConstantExpression)e).Value == null;
38             }
39             return false;
40         }
41
42
43         /// <summary>
44         /// If the result of a TypeBinaryExpression is known statically, this
45         /// returns the result, otherwise it returns null, meaning we'll need
46         /// to perform the IsInst instruction at runtime.
47         /// 
48         /// The result of this function must be equivalent to IsInst, or
49         /// null.
50         /// </summary>
51         internal static AnalyzeTypeIsResult AnalyzeTypeIs(TypeBinaryExpression typeIs) {
52             return AnalyzeTypeIs(typeIs.Expression, typeIs.TypeOperand);
53         }
54
55         /// <summary>
56         /// If the result of an isinst opcode is known statically, this
57         /// returns the result, otherwise it returns null, meaning we'll need
58         /// to perform the IsInst instruction at runtime.
59         /// 
60         /// The result of this function must be equivalent to IsInst, or
61         /// null.
62         /// </summary>
63         private static AnalyzeTypeIsResult AnalyzeTypeIs(Expression operand, Type testType) {
64             Type operandType = operand.Type;
65
66             // Oddly, we allow void operands
67             // This is LinqV1 behavior of TypeIs
68             if (operandType == typeof(void)) {
69                 return AnalyzeTypeIsResult.KnownFalse;
70             }
71
72             //
73             // Type comparisons treat nullable types as if they were the
74             // underlying type. The reason is when you box a nullable it
75             // becomes a boxed value of the underlying type, or null.
76             //
77             Type nnOperandType = operandType.GetNonNullableType();
78             Type nnTestType = testType.GetNonNullableType();
79
80             //
81             // See if we can determine the answer based on the static types
82             //
83             // Extensive testing showed that Type.IsAssignableFrom,
84             // Type.IsInstanceOfType, and the isinst instruction were all
85             // equivalent when used against a live object
86             //
87             if (nnTestType.IsAssignableFrom(nnOperandType)) {
88                 // If the operand is a value type (other than nullable), we
89                 // know the result is always true.
90                 if (operandType.IsValueType && !operandType.IsNullableType()) {
91                     return AnalyzeTypeIsResult.KnownTrue;
92                 }
93
94                 // For reference/nullable types, we need to compare to null at runtime
95                 return AnalyzeTypeIsResult.KnownAssignable;
96             }
97
98             // We used to have an if IsSealed, return KnownFalse check here.
99             // but that doesn't handle generic types & co/contravariance correctly.
100             // So just use IsInst, which we know always gives us the right answer.
101
102             // Otherwise we need a full runtime check
103             return AnalyzeTypeIsResult.Unknown;
104         }
105     }
106 }