Example #1
0
        protected void EmitConditionalAccess(EmitContext ec)
        {
            var a_expr = arguments [0].Expr;

            var des = a_expr as DynamicExpressionStatement;

            if (des != null)
            {
                des.EmitConditionalAccess(ec);
            }

            if (HasConditionalAccess())
            {
                var NullOperatorLabel = ec.DefineLabel();

                if (ExpressionAnalyzer.IsInexpensiveLoad(a_expr))
                {
                    a_expr.Emit(ec);
                }
                else
                {
                    var lt = new LocalTemporary(a_expr.Type);
                    lt.EmitAssign(ec, a_expr, true, false);

                    Arguments [0].Expr = lt;
                }

                ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel);

                if (!ec.ConditionalAccess.Statement)
                {
                    if (ec.ConditionalAccess.Type.IsNullableType)
                    {
                        Nullable.LiftedNull.Create(ec.ConditionalAccess.Type, Location.Null).Emit(ec);
                    }
                    else
                    {
                        ec.EmitNull();
                    }
                }

                ec.Emit(OpCodes.Br, ec.ConditionalAccess.EndLabel);
                ec.MarkLabel(NullOperatorLabel);

                return;
            }

            if (a_expr.HasConditionalAccess())
            {
                var lt = new LocalTemporary(a_expr.Type);
                lt.EmitAssign(ec, a_expr, false, false);

                Arguments [0].Expr = lt;
            }
        }
Example #2
0
        public void EmitLoad(EmitContext ec, bool boxInstance)
        {
            var instance_type = instance.Type;

            //
            // Push the instance expression
            //
            if (addressRequired)
            {
                //
                // If the expression implements IMemoryLocation, then
                // we can optimize and use AddressOf on the
                // return.
                //
                // If not we have to use some temporary storage for
                // it.
                var iml = instance as IMemoryLocation;
                if (iml != null)
                {
                    iml.AddressOf(ec, AddressOp.Load);
                }
                else
                {
                    LocalTemporary temp = new LocalTemporary(instance_type);
                    instance.Emit(ec);
                    temp.Store(ec);
                    temp.AddressOf(ec, AddressOp.Load);
                }

                return;
            }

            instance.Emit(ec);

            // Only to make verifier happy
            if (boxInstance && ExpressionAnalyzer.RequiresBoxing(instance))
            {
                ec.Emit(OpCodes.Box, instance_type);
            }
        }
Example #3
0
        protected override Expression DoResolve(ResolveContext rc)
        {
            var src = source.Resolve(rc);

            if (src == null)
            {
                return(null);
            }

            if (InternalType.HasNoType(src.Type))
            {
                rc.Report.Error(8131, source.Location, "Deconstruct assignment requires an expression with a type on the right-hand-side");
                return(null);
            }

            var src_type = src.Type;

            if (src_type.IsTupleType)
            {
                if (src_type.Arity != targetExprs.Count)
                {
                    rc.Report.Error(8132, loc, "Cannot deconstruct a tuple of `{0}' elements into `{1}' variables",
                                    src_type.Arity.ToString(), targetExprs.Count.ToString());
                    return(null);
                }

                var tupleLiteral = src as TupleLiteral;
                if (tupleLiteral == null && !ExpressionAnalyzer.IsInexpensiveLoad(src))
                {
                    var expr_variable = LocalVariable.CreateCompilerGenerated(source.Type, rc.CurrentBlock, loc);
                    source   = new CompilerAssign(expr_variable.CreateReferenceExpression(rc, loc), source, loc);
                    instance = expr_variable.CreateReferenceExpression(rc, loc);
                }

                for (int i = 0; i < targetExprs.Count; ++i)
                {
                    var tle = src_type.TypeArguments [i];

                    var lv = variablesToInfer? [i];
                    if (lv != null)
                    {
                        if (InternalType.HasNoType(tle))
                        {
                            rc.Report.Error(8130, Location, "Cannot infer the type of implicitly-typed deconstruction variable `{0}'", lv.Name);
                            lv.Type = InternalType.ErrorType;
                            continue;
                        }

                        lv.Type = tle;
                        lv.PrepareAssignmentAnalysis((BlockContext)rc);
                    }


                    var element_src = tupleLiteral == null ? new MemberAccess(instance, NamedTupleSpec.GetElementPropertyName(i)) : tupleLiteral.Elements [i].Expr;
                    targetExprs [i] = new SimpleAssign(targetExprs [i], element_src).Resolve(rc);
                }

                eclass = ExprClass.Value;

                // TODO: The type is same only if there is no target element conversion
                // var res = (/*byte*/ b, /*short*/ s) = (2, 4);
                type = src.Type;
                return(this);
            }

            if (src_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
            {
                rc.Report.Error(8133, loc, "Cannot deconstruct dynamic objects");
                return(null);
            }

            /*
             * var args = new Arguments (targetExprs.Count);
             * foreach (var t in targetExprs) {
             *      args.Add (new Argument (t, Argument.AType.Out));
             * }
             *
             * var invocation = new Invocation (new MemberAccess (src, "Deconstruct"), args);
             * var res = invocation.Resolve (rc);
             */

            throw new NotImplementedException("Custom deconstruct");
        }
Example #4
0
        public void Emit(EmitContext ec, bool conditionalAccess)
        {
            Label NullOperatorLabel;

            Nullable.Unwrap unwrap;

            if (conditionalAccess && Expression.IsNeverNull(instance))
            {
                conditionalAccess = false;
            }

            if (conditionalAccess)
            {
                NullOperatorLabel = ec.DefineLabel();
                unwrap            = instance as Nullable.Unwrap;
            }
            else
            {
                NullOperatorLabel = new Label();
                unwrap            = null;
            }

            IMemoryLocation instance_address       = null;
            bool            conditional_access_dup = false;

            if (unwrap != null)
            {
                unwrap.Store(ec);
                unwrap.EmitCheck(ec);
                ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel);
            }
            else
            {
                if (conditionalAccess && addressRequired)
                {
                    //
                    // Don't allocate temp variable when instance load is cheap and load and load-address
                    // operate on same memory
                    //
                    instance_address = instance as VariableReference;
                    if (instance_address == null)
                    {
                        instance_address = instance as LocalTemporary;
                    }

                    if (instance_address == null)
                    {
                        EmitLoad(ec, false);
                        ec.Emit(OpCodes.Dup);
                        ec.EmitLoadFromPtr(instance.Type);

                        conditional_access_dup = true;
                    }
                    else
                    {
                        instance.Emit(ec);
                    }
                }
                else
                {
                    EmitLoad(ec, !conditionalAccess);

                    if (conditionalAccess)
                    {
                        conditional_access_dup = !ExpressionAnalyzer.IsInexpensiveLoad(instance);
                        if (conditional_access_dup)
                        {
                            ec.Emit(OpCodes.Dup);
                        }
                    }
                }

                if (conditionalAccess)
                {
                    if (instance.Type.Kind == MemberKind.TypeParameter)
                    {
                        ec.Emit(OpCodes.Box, instance.Type);
                    }

                    ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel);

                    if (conditional_access_dup)
                    {
                        ec.Emit(OpCodes.Pop);
                    }
                }
            }

            if (conditionalAccess)
            {
                if (!ec.ConditionalAccess.Statement)
                {
                    var t = ec.ConditionalAccess.Type;
                    if (t.IsNullableType)
                    {
                        Nullable.LiftedNull.Create(t, Location.Null).Emit(ec);
                    }
                    else
                    {
                        ec.EmitNull();

                        if (t.IsGenericParameter)
                        {
                            ec.Emit(OpCodes.Unbox_Any, t);
                        }
                    }
                }

                ec.Emit(OpCodes.Br, ec.ConditionalAccess.EndLabel);
                ec.MarkLabel(NullOperatorLabel);

                if (instance_address != null)
                {
                    instance_address.AddressOf(ec, AddressOp.Load);
                }
                else if (unwrap != null)
                {
                    unwrap.Emit(ec);
                    if (addressRequired)
                    {
                        var tmp = ec.GetTemporaryLocal(unwrap.Type);
                        ec.Emit(OpCodes.Stloc, tmp);
                        ec.Emit(OpCodes.Ldloca, tmp);
                        ec.FreeTemporaryLocal(tmp, unwrap.Type);
                    }
                }
                else if (!conditional_access_dup)
                {
                    instance.Emit(ec);
                }
            }
        }
Example #5
0
        protected override Expression DoResolve(ResolveContext rc)
        {
            var src = source.Resolve(rc);

            if (src == null)
            {
                return(null);
            }

            if (InternalType.HasNoType(src.Type))
            {
                rc.Report.Error(8131, source.Location, "Deconstruct assignment requires an expression with a type on the right-hand-side");
                return(null);
            }

            var src_type = src.Type;

            if (src_type.IsTupleType)
            {
                int target_count;

                if (targetExprs == null)
                {
                    target_count = variables.Count;
                    targetExprs  = new List <Expression> (target_count);
                }
                else
                {
                    target_count = targetExprs.Count;
                }

                if (src_type.Arity != target_count)
                {
                    rc.Report.Error(8132, loc, "Cannot deconstruct a tuple of `{0}' elements into `{1}' variables",
                                    src_type.Arity.ToString(CultureInfo.InvariantCulture), target_count.ToString(CultureInfo.InvariantCulture));
                    return(null);
                }

                var tupleLiteral = src as TupleLiteral;
                if (tupleLiteral == null && !ExpressionAnalyzer.IsInexpensiveLoad(src))
                {
                    var expr_variable = LocalVariable.CreateCompilerGenerated(source.Type, rc.CurrentBlock, loc);
                    source   = new CompilerAssign(expr_variable.CreateReferenceExpression(rc, loc), source, loc);
                    instance = expr_variable.CreateReferenceExpression(rc, loc);
                }

                var element_srcs = new List <Expression> ();
                var src_names    = new List <string> ();
                for (int i = 0; i < target_count; ++i)
                {
                    var element_src = tupleLiteral == null ? new MemberAccess(instance, NamedTupleSpec.GetElementPropertyName(i)) : tupleLiteral.Elements [i].Expr;
                    element_srcs.Add(element_src);
                    if (element_src is VariableReference)
                    {
                        src_names.Add((element_src as VariableReference)?.Name);
                    }
                }

                for (int i = 0; i < target_count; ++i)
                {
                    var tle = src_type.TypeArguments [i];

                    if (variables != null)
                    {
                        var variable = variables [i].Variable;

                        if (variable.Type == InternalType.Discard)
                        {
                            variables [i] = null;
                            targetExprs.Add(EmptyExpressionStatement.Instance);
                            continue;
                        }

                        var variable_type = variables [i].TypeExpression;

                        targetExprs.Add(new LocalVariableReference(variable, variable.Location));

                        if (variable_type is VarExpr)
                        {
                            if (InternalType.HasNoType(tle))
                            {
                                rc.Report.Error(8130, Location, "Cannot infer the type of implicitly-typed deconstruction variable `{0}'", variable.Name);
                                tle = InternalType.ErrorType;
                            }

                            variable.Type = tle;
                        }
                        else
                        {
                            variable.Type = variable_type.ResolveAsType(rc);
                        }

                        variable.PrepareAssignmentAnalysis((BlockContext)rc);
                    }

                    var element_target = (targetExprs [i] as SimpleName)?.LookupNameExpression(rc, MemberLookupRestrictions.None);

                    if (element_target != null && src_names.Contains((element_target as VariableReference)?.Name))
                    {
                        var tempType = element_target.Resolve(rc).Type;

                        var temp = new LocalTemporary(tempType);
                        tempExprs.Add(new SimpleAssign(temp, element_srcs [i]).Resolve(rc));
                        targetExprs [i] = new SimpleAssign(targetExprs [i], temp).Resolve(rc);
                    }
                    else
                    {
                        targetExprs [i] = new SimpleAssign(targetExprs [i], element_srcs [i]).Resolve(rc);
                    }
                }

                eclass = ExprClass.Value;

                // TODO: The type is same only if there is no target element conversion
                // var res = (/*byte*/ b, /*short*/ s) = (2, 4);
                type = src.Type;
                return(this);
            }

            if (src_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
            {
                rc.Report.Error(8133, loc, "Cannot deconstruct dynamic objects");
                return(null);
            }

            /*
             * var args = new Arguments (targetExprs.Count);
             * foreach (var t in targetExprs) {
             *      args.Add (new Argument (t, Argument.AType.Out));
             * }
             *
             * var invocation = new Invocation (new MemberAccess (src, "Deconstruct"), args);
             * var res = invocation.Resolve (rc);
             */

            throw new NotImplementedException("Custom deconstruct");
        }