1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Diagnostics;
18 using System.Dynamic.Utils;
21 namespace Microsoft.Scripting.Ast {
23 namespace System.Linq.Expressions {
26 internal enum AnalyzeTypeIsResult {
29 KnownAssignable, // need null check only
30 Unknown, // need full runtime check
33 internal static class ConstantCheck {
35 internal static bool IsNull(Expression e) {
36 if (e.NodeType == ExpressionType.Constant) {
37 return ((ConstantExpression)e).Value == null;
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.
48 /// The result of this function must be equivalent to IsInst, or
51 internal static AnalyzeTypeIsResult AnalyzeTypeIs(TypeBinaryExpression typeIs) {
52 return AnalyzeTypeIs(typeIs.Expression, typeIs.TypeOperand);
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.
60 /// The result of this function must be equivalent to IsInst, or
63 private static AnalyzeTypeIsResult AnalyzeTypeIs(Expression operand, Type testType) {
64 Type operandType = operand.Type;
66 // Oddly, we allow void operands
67 // This is LinqV1 behavior of TypeIs
68 if (operandType == typeof(void)) {
69 return AnalyzeTypeIsResult.KnownFalse;
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.
77 Type nnOperandType = operandType.GetNonNullableType();
78 Type nnTestType = testType.GetNonNullableType();
81 // See if we can determine the answer based on the static types
83 // Extensive testing showed that Type.IsAssignableFrom,
84 // Type.IsInstanceOfType, and the isinst instruction were all
85 // equivalent when used against a live object
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;
94 // For reference/nullable types, we need to compare to null at runtime
95 return AnalyzeTypeIsResult.KnownAssignable;
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.
102 // Otherwise we need a full runtime check
103 return AnalyzeTypeIsResult.Unknown;