Exemple #1
0
            /// <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);
            }
 public override bool Equals(BoundDagEvaluation obj)
 {
     return(base.Equals(obj) &&
            // base.Equals checks the kind field, so the following cast is safe
            this.Index == ((BoundDagIndexEvaluation)obj).Index);
 }
Exemple #3
0
            /// <summary>
            /// Return the side-effect expression corresponding to an evaluation.
            /// </summary>
            protected BoundExpression LowerEvaluation(BoundDagEvaluation evaluation)
            {
                BoundExpression input = _tempAllocator.GetTemp(evaluation.Input);

                switch (evaluation)
                {
                case BoundDagFieldEvaluation f:
                {
                    FieldSymbol     field      = f.Field;
                    var             outputTemp = new BoundDagTemp(f.Syntax, field.Type.TypeSymbol, f, index: 0);
                    BoundExpression output     = _tempAllocator.GetTemp(outputTemp);
                    BoundExpression access     = _localRewriter.MakeFieldAccess(f.Syntax, input, field, null, LookupResultKind.Viable, field.Type.TypeSymbol);
                    access.WasCompilerGenerated = true;
                    return(_factory.AssignmentExpression(output, access));
                }

                case BoundDagPropertyEvaluation p:
                {
                    PropertySymbol  property   = p.Property;
                    var             outputTemp = new BoundDagTemp(p.Syntax, property.Type.TypeSymbol, p, index: 0);
                    BoundExpression output     = _tempAllocator.GetTemp(outputTemp);
                    return(_factory.AssignmentExpression(output, _factory.Property(input, property)));
                }

                case BoundDagDeconstructEvaluation d:
                {
                    MethodSymbol method         = d.DeconstructMethod;
                    var          refKindBuilder = ArrayBuilder <RefKind> .GetInstance();

                    var argBuilder = ArrayBuilder <BoundExpression> .GetInstance();

                    BoundExpression receiver;
                    void addArg(RefKind refKind, BoundExpression expression)
                    {
                        refKindBuilder.Add(refKind);
                        argBuilder.Add(expression);
                    }

                    Debug.Assert(method.Name == WellKnownMemberNames.DeconstructMethodName);
                    int extensionExtra;
                    if (method.IsStatic)
                    {
                        Debug.Assert(method.IsExtensionMethod);
                        receiver = _factory.Type(method.ContainingType);
                        addArg(method.ParameterRefKinds[0], input);
                        extensionExtra = 1;
                    }
                    else
                    {
                        receiver       = input;
                        extensionExtra = 0;
                    }

                    for (int i = extensionExtra; i < method.ParameterCount; i++)
                    {
                        ParameterSymbol parameter = method.Parameters[i];
                        Debug.Assert(parameter.RefKind == RefKind.Out);
                        var outputTemp = new BoundDagTemp(d.Syntax, parameter.Type.TypeSymbol, d, i - extensionExtra);
                        addArg(RefKind.Out, _tempAllocator.GetTemp(outputTemp));
                    }

                    return(_factory.Call(receiver, method, refKindBuilder.ToImmutableAndFree(), argBuilder.ToImmutableAndFree()));
                }

                case BoundDagTypeEvaluation t:
                {
                    TypeSymbol inputType = input.Type;
                    if (inputType.IsDynamic() || inputType.ContainsTypeParameter())
                    {
                        inputType = _factory.SpecialType(SpecialType.System_Object);
                    }

                    TypeSymbol               type               = t.Type;
                    var                      outputTemp         = new BoundDagTemp(t.Syntax, type, t, index: 0);
                    BoundExpression          output             = _tempAllocator.GetTemp(outputTemp);
                    HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                    Conversion               conversion         = _factory.Compilation.Conversions.ClassifyBuiltInConversion(inputType, output.Type, ref useSiteDiagnostics);
                    _localRewriter._diagnostics.Add(t.Syntax, useSiteDiagnostics);
                    BoundExpression evaluated;
                    if (conversion.Exists)
                    {
                        if (conversion.Kind == ConversionKind.ExplicitNullable &&
                            inputType.GetNullableUnderlyingType().Equals(output.Type, TypeCompareKind.AllIgnoreOptions) &&
                            _localRewriter.TryGetNullableMethod(t.Syntax, inputType, SpecialMember.System_Nullable_T_GetValueOrDefault, out MethodSymbol getValueOrDefault))
                        {
                            // As a special case, since the null test has already been done we can use Nullable<T>.GetValueOrDefault
                            evaluated = _factory.Call(input, getValueOrDefault);
                        }
                        else
                        {
                            evaluated = _factory.Convert(type, input, conversion);
                        }
                    }
                    else
                    {
                        evaluated = _factory.As(input, type);
                    }

                    return(_factory.AssignmentExpression(output, evaluated));
                }

                case BoundDagIndexEvaluation e:
                {
                    // This is an evaluation of an indexed property with a constant int value.
                    // The input type must be ITuple, and the property must be a property of ITuple.
                    Debug.Assert(e.Property.ContainingSymbol.Equals(input.Type));
                    Debug.Assert(e.Property.GetMethod.ParameterCount == 1);
                    Debug.Assert(e.Property.GetMethod.Parameters[0].Type.SpecialType == SpecialType.System_Int32);
                    TypeSymbol      type       = e.Property.GetMethod.ReturnType.TypeSymbol;
                    var             outputTemp = new BoundDagTemp(e.Syntax, type, e, index: 0);
                    BoundExpression output     = _tempAllocator.GetTemp(outputTemp);
                    return(_factory.AssignmentExpression(output, _factory.Call(input, e.Property.GetMethod, _factory.Literal(e.Index))));
                }

                default:
                    throw ExceptionUtilities.UnexpectedValue(evaluation);
                }
            }
 public virtual bool Equals(BoundDagEvaluation other)
 {
     return(other != (object)null && this.Kind == other.Kind && this.Input.Equals(other.Input) && this.Symbol == other.Symbol);
 }