/// <summary> /// Return the boolean expression to be evaluated for the given test. Returns `null` if the test is trivially true. /// </summary> protected BoundExpression LowerTest(BoundDagTest test) { _factory.Syntax = test.Syntax; BoundExpression input = _tempAllocator.GetTemp(test.Input); switch (test) { case BoundDagNonNullTest d: return(_localRewriter.MakeNullCheck(d.Syntax, input, input.Type.IsNullableType() ? BinaryOperatorKind.NullableNullNotEqual : BinaryOperatorKind.NotEqual)); case BoundDagTypeTest d: // Note that this tests for non-null as a side-effect. We depend on that to sometimes avoid the null check. return(_factory.Is(input, d.Type)); case BoundDagNullTest d: return(_localRewriter.MakeNullCheck(d.Syntax, input, input.Type.IsNullableType() ? BinaryOperatorKind.NullableNullEqual : BinaryOperatorKind.Equal)); case BoundDagValueTest d: Debug.Assert(!input.Type.IsNullableType()); return(MakeEqual(_localRewriter.MakeLiteral(d.Syntax, d.Value, input.Type), input)); default: throw ExceptionUtilities.UnexpectedValue(test); } }
/// <summary> /// Lower a test followed by an evaluation into a side-effect followed by a test. This permits us to optimize /// a type test followed by a cast into an `as` expression followed by a null check. Returns true if the optimization /// applies and the results are placed into <paramref name="sideEffect"/> and <paramref name="test"/>. The caller /// should place the side-effect before the test in the generated code. /// </summary> /// <param name="evaluation"></param> /// <param name="test"></param> /// <param name="sideEffect"></param> /// <param name="testExpression"></param> /// <returns>true if the optimization is applied</returns> protected bool TryLowerTypeTestAndCast( BoundDagTest test, BoundDagEvaluation evaluation, out BoundExpression sideEffect, out BoundExpression testExpression) { if (test is BoundDagTypeTest typeDecision && evaluation is BoundDagTypeEvaluation typeEvaluation && typeDecision.Type.IsReferenceType && typeEvaluation.Type.Equals(typeDecision.Type, TypeCompareKind.AllIgnoreOptions) && typeEvaluation.Input == typeDecision.Input ) { BoundExpression input = _tempAllocator.GetTemp(test.Input); BoundExpression output = _tempAllocator.GetTemp(new BoundDagTemp(evaluation.Syntax, typeEvaluation.Type, evaluation, index: 0)); sideEffect = _factory.AssignmentExpression(output, _factory.As(input, typeEvaluation.Type)); testExpression = _factory.ObjectNotEqual(output, _factory.Null(output.Type)); return(true); } sideEffect = testExpression = null; return(false); }
/// <summary> /// Translate the single test into _sideEffectBuilder and _conjunctBuilder. /// </summary> private void LowerOneTest(BoundDagTest test) { _factory.Syntax = test.Syntax; switch (test) { case BoundDagEvaluation eval: { var sideEffect = LowerEvaluation(eval); _sideEffectBuilder.Add(sideEffect); return; } case var _: { var testExpression = LowerTest(test); if (testExpression != null) { AddConjunct(testExpression); } return; } } }