[mcs] Fixes codegen for pattern probing with value-type variables
[mono.git] / mcs / mcs / expression.cs
index 2968ee08584f544f7869efba43e4007b9f259888..732ee3ee934c355a27e73efa58f02e1f32bfb803 100644 (file)
@@ -718,8 +718,11 @@ namespace Mono.CSharp
 
                Expression ResolveAddressOf (ResolveContext ec)
                {
-                       if (!ec.IsUnsafe)
+                       if (ec.CurrentIterator != null) {
+                               UnsafeInsideIteratorError (ec, loc);
+                       } else if (!ec.IsUnsafe) {
                                UnsafeError (ec, loc);
+                       }
 
                        Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
                        if (Expr == null || Expr.eclass != ExprClass.Variable) {
@@ -737,7 +740,7 @@ namespace Mono.CSharp
                                is_fixed = vr.IsFixed;
                                vr.SetHasAddressTaken ();
 
-                               if (vr.IsHoisted) {
+                               if (vr.IsHoisted && ec.CurrentIterator == null) {
                                        AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
                                }
                        } else {
@@ -984,8 +987,11 @@ namespace Mono.CSharp
                        if (expr == null)
                                return null;
 
-                       if (!ec.IsUnsafe)
+                       if (ec.CurrentIterator != null) {
+                               UnsafeInsideIteratorError (ec, loc);
+                       } else if (!ec.IsUnsafe) {
                                UnsafeError (ec, loc);
+                       }
 
                        var pc = expr.Type as PointerContainer;
 
@@ -1484,6 +1490,11 @@ namespace Mono.CSharp
                        expr.EmitSideEffect (ec);
                }
 
+               public override void EmitPrepare (EmitContext ec)
+               {
+                       expr.EmitPrepare (ec);
+               }
+
                public override void FlowAnalysis (FlowAnalysisContext fc)
                {
                        expr.FlowAnalysis (fc);
@@ -1529,7 +1540,7 @@ namespace Mono.CSharp
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
                        if (Variable != null)
-                               throw new NotSupportedException ();
+                               ec.Report.Error (8122, loc, "An expression tree cannot contain a pattern matching operator");
 
                        Arguments args = Arguments.CreateForExpressionTree (ec, null,
                                expr.CreateExpressionTree (ec),
@@ -1584,6 +1595,14 @@ namespace Mono.CSharp
                        ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
                }
 
+               public override void EmitPrepare (EmitContext ec)
+               {
+                       base.EmitPrepare (ec);
+
+                       if (Variable != null)
+                               Variable.CreateBuilder (ec);
+               }
+
                void EmitPatternMatch (EmitContext ec)
                {
                        var no_match = ec.DefineLabel ();
@@ -1657,8 +1676,6 @@ namespace Mono.CSharp
 
                void EmitLoad (EmitContext ec)
                {
-                       Label no_value_label = new Label ();
-
                        if (expr_unwrap != null) {
                                expr_unwrap.EmitCheck (ec);
 
@@ -1666,37 +1683,91 @@ namespace Mono.CSharp
                                        return;
 
                                ec.Emit (OpCodes.Dup);
-                               no_value_label = ec.DefineLabel ();
+                               var no_value_label = ec.DefineLabel ();
                                ec.Emit (OpCodes.Brfalse_S, no_value_label);
+
+                               if (Variable.HoistedVariant != null)
+                                       ec.EmitThis ();
+
                                expr_unwrap.Emit (ec);
-                       } else {
-                               expr.Emit (ec);
 
-                               // Only to make verifier happy
-                               if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
-                                       ec.Emit (OpCodes.Box, expr.Type);
+                               if (Variable.HoistedVariant != null) {
+                                       Variable.HoistedVariant.EmitAssignFromStack (ec);
+                               } else {
+                                       //
+                                       // It's ok to have variable builder created out of order. It simplifies emit
+                                       // of statements like while (condition) { }
+                                       //
+                                       if (!Variable.Created)
+                                               Variable.CreateBuilder (ec);
 
-                               ec.Emit (OpCodes.Isinst, probe_type_expr);
+                                       Variable.EmitAssign (ec);
+                               }
+
+                               ec.MarkLabel (no_value_label);
+                               return;
+                       }
+
+                       expr.Emit (ec);
+
+                       bool vtype_variable = Variable != null && (probe_type_expr.IsGenericParameter || TypeSpec.IsValueType (ProbeType.Type));
+                       LocalBuilder expr_copy = null;
+
+                       if (vtype_variable && !ExpressionAnalyzer.IsInexpensiveLoad (expr)) {
+                               expr_copy = ec.GetTemporaryLocal (expr.Type);
+                               ec.Emit (OpCodes.Stloc, expr_copy);
+                               ec.Emit (OpCodes.Ldloc, expr_copy);
+                       } else if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type)) {
+                               //
+                               // Only to make verifier happy
+                               //
+                               ec.Emit (OpCodes.Box, expr.Type);
                        }
 
+                       ec.Emit (OpCodes.Isinst, probe_type_expr);
+
                        if (Variable != null) {
-                               bool value_on_stack;
-                               if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
-                                       ec.Emit (OpCodes.Dup);
+                               ec.Emit (OpCodes.Dup);
+
+                               var nonmatching_label = ec.DefineLabel ();
+                               ec.Emit (OpCodes.Brfalse_S, nonmatching_label);
+
+                               if (vtype_variable) {
+                                       if (expr_copy != null) {
+                                               ec.Emit (OpCodes.Ldloc, expr_copy);
+                                               ec.FreeTemporaryLocal (expr_copy, expr.Type);
+                                       } else {
+                                               expr.Emit (ec);
+                                       }
+
                                        ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
-                                       value_on_stack = true;
                                } else {
-                                       value_on_stack = false;
+                                       // Already on the stack
                                }
 
-                               Variable.CreateBuilder (ec);
-                               Variable.EmitAssign (ec);
+                               if (Variable.HoistedVariant != null) {
+                                       var temp = new LocalTemporary (ProbeType.Type);
+                                       temp.Store (ec);
+                                       Variable.HoistedVariant.EmitAssign (ec, temp, false, false);
+                                       temp.Release (ec);
+
+                                       if (!vtype_variable)
+                                               Variable.HoistedVariant.Emit (ec);
+                               } else {
+                                       //
+                                       // It's ok to have variable builder created out of order. It simplifies emit
+                                       // of statements like while (condition) { }
+                                       //
+                                       if (!Variable.Created)
+                                               Variable.CreateBuilder (ec);
+
+                                       Variable.EmitAssign (ec);
 
-                               if (expr_unwrap != null) {
-                                       ec.MarkLabel (no_value_label);
-                               } else if (!value_on_stack) {
-                                       Variable.Emit (ec);
+                                       if (!vtype_variable)
+                                               Variable.Emit (ec);
                                }
+
+                               ec.MarkLabel (nonmatching_label);
                        }
                }
 
@@ -1733,6 +1804,21 @@ namespace Mono.CSharp
                                fc.SetVariableAssigned (Variable.VariableInfo, true);
                }
 
+               public override void FlowAnalysisConditional (FlowAnalysisContext fc)
+               {
+                       if (Variable == null) {
+                               base.FlowAnalysisConditional (fc);
+                               return;
+                       }
+
+                       expr.FlowAnalysis (fc);
+
+                       fc.DefiniteAssignmentOnTrue = fc.BranchDefiniteAssignment ();
+                       fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
+
+                       fc.SetVariableAssigned (Variable.VariableInfo, fc.DefiniteAssignmentOnTrue);
+               }
+
                protected override void ResolveProbeType (ResolveContext rc)
                {
                        if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
@@ -1843,6 +1929,15 @@ namespace Mono.CSharp
 
                Expression ResolveResultExpression (ResolveContext ec)
                {
+                       if (Variable != null) {
+                               if (expr is NullLiteral) {
+                                       ec.Report.Error (8117, loc, "Cannot use null as pattern matching operand");
+                                       return this;
+                               }
+
+                               CheckExpressionVariable (ec);
+                       }
+
                        TypeSpec d = expr.Type;
                        bool d_is_nullable = false;
 
@@ -1850,7 +1945,7 @@ namespace Mono.CSharp
                        // If E is a method group or the null literal, or if the type of E is a reference
                        // type or a nullable type and the value of E is null, the result is false
                        //
-                       if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
+                       if (expr.IsNull)
                                return CreateConstantResult (ec, false);
 
                        if (d.IsNullableType) {
@@ -1864,6 +1959,11 @@ namespace Mono.CSharp
                        TypeSpec t = probe_type_expr;
                        bool t_is_nullable = false;
                        if (t.IsNullableType) {
+                               if (Variable != null) {
+                                       ec.Report.Error (8116, loc, "The nullable type `{0}' pattern matching is not allowed. Consider using underlying type `{1}'",
+                                                                        t.GetSignatureForError (), Nullable.NullableInfo.GetUnderlyingType (t).GetSignatureForError ());
+                               }
+
                                var ut = Nullable.NullableInfo.GetUnderlyingType (t);
                                if (!ut.IsGenericParameter) {
                                        t = ut;
@@ -1908,9 +2008,13 @@ namespace Mono.CSharp
                                        return ResolveGenericParameter (ec, d, tps);
 
                                if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
-                                       ec.Report.Warning (1981, 3, loc,
-                                               "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
-                                               OperatorName, t.GetSignatureForError ());
+                                       if (Variable != null) {
+                                               ec.Report.Error (8208, loc, "The type `{0}' pattern matching is not allowed", t.GetSignatureForError ());
+                                       } else {
+                                               ec.Report.Warning (1981, 3, loc,
+                                                       "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
+                                                       OperatorName, t.GetSignatureForError ());
+                                       }
                                }
 
                                if (TypeManager.IsGenericParameter (d))
@@ -2362,6 +2466,12 @@ namespace Mono.CSharp
                        eclass = ExprClass.Value;
                        TypeSpec etype = expr.Type;
 
+                       if (expr is TupleLiteral && TupleLiteral.ContainsNoTypeElement (etype)) {
+                               ec.Report.Error (8307, expr.Location, "The first operand of an `as' operator may not be a tuple literal without a natural type");
+                               type = InternalType.ErrorType;
+                               return this;
+                       }
+
                        if (type == null) {
                                type = InternalType.ErrorType;
                                return this;
@@ -2453,8 +2563,12 @@ namespace Mono.CSharp
                                return null;
                        }
 
-                       if (type.IsPointer && !ec.IsUnsafe) {
-                               UnsafeError (ec, loc);
+                       if (type.IsPointer) {
+                               if (ec.CurrentIterator != null) {
+                                       UnsafeInsideIteratorError (ec, loc);
+                               } else if (!ec.IsUnsafe) {
+                                       UnsafeError (ec, loc);
+                               }
                        }
 
                        eclass = ExprClass.Value;
@@ -2531,7 +2645,8 @@ namespace Mono.CSharp
 
                public void AddressOf (EmitContext ec, AddressOp mode)
                {
-                       Variable.CreateBuilder (ec);
+                       if (!Variable.Created)
+                               Variable.CreateBuilder (ec);
 
                        if (Initializer != null) {
                                lvr.EmitAssign (ec, Initializer, false, false);
@@ -2552,12 +2667,14 @@ namespace Mono.CSharp
 
                public override Expression CreateExpressionTree (ResolveContext rc)
                {
-                       rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
+                       rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
                        return null;
                }
 
                bool DoResolveCommon (ResolveContext rc)
                {
+                       CheckExpressionVariable (rc);
+
                        var var_expr = VariableType as VarExpr;
                        if (var_expr != null) {
                                type = InternalType.VarOutType;
@@ -2602,6 +2719,11 @@ namespace Mono.CSharp
                {
                        throw new NotImplementedException ();
                }
+
+               public override void EmitPrepare (EmitContext ec)
+               {
+                       Variable.CreateBuilder (ec);
+               }
        }
        
        //
@@ -3448,7 +3570,7 @@ namespace Mono.CSharp
                        }
                }
 
-               static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
+               public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
                {
                        switch (op) {
                        case Operator.Addition:
@@ -6469,18 +6591,19 @@ namespace Mono.CSharp
                                return;
                        }
 
+                       bool dereference = IsRef && !(source is ReferenceExpression);
                        New n_source = source as New;
                        if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
                                if (!n_source.Emit (ec, this)) {
                                        if (leave_copy) {
                                                EmitLoad (ec);
-                                               if (IsRef)
+                                               if (dereference)
                                                        ec.EmitLoadFromPtr (type);
                                        }
                                        return;
                                }
                        } else {
-                               if (IsRef)
+                               if (dereference)
                                        EmitLoad (ec);
 
                                source.Emit (ec);
@@ -6488,13 +6611,13 @@ namespace Mono.CSharp
 
                        if (leave_copy) {
                                ec.Emit (OpCodes.Dup);
-                               if (IsRef) {
+                               if (dereference) {
                                        temp = new LocalTemporary (Type);
                                        temp.Store (ec);
                                }
                        }
 
-                       if (IsRef)
+                       if (dereference)
                                ec.EmitStoreFromPtr (type);
                        else
                                Variable.EmitAssign (ec);
@@ -6578,7 +6701,7 @@ namespace Mono.CSharp
                }
 
                public override bool IsRef {
-                       get { return false; }
+                       get { return local_info.IsByRef; }
                }
 
                public override string Name {
@@ -6619,7 +6742,11 @@ namespace Mono.CSharp
                                        AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
                                } else if (local_info.IsFixed) {
                                        ec.Report.Error (1764, loc,
-                                               "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
+                                               "Cannot use fixed variable `{0}' inside an anonymous method, lambda expression or query expression",
+                                               GetSignatureForError ());
+                               } else if (local_info.IsByRef) {
+                                       ec.Report.Error (8175, loc,
+                                               "Cannot use by-reference variable `{0}' inside an anonymous method, lambda expression, or query expression",
                                                GetSignatureForError ());
                                }
 
@@ -7041,10 +7168,48 @@ namespace Mono.CSharp
                protected override Expression DoResolve (ResolveContext rc)
                {
                        ResolveConditionalAccessReceiver (rc);
-                       return DoResolveInvocation (rc);
+                       return DoResolveInvocation (rc, null);
+               }
+
+               public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
+               {
+                       var sn = expr as SimpleName;
+                       if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) {
+                               var targets = new List<Expression> (arguments.Count);
+                               var variables = new List<LocalVariable> (arguments.Count);
+                               foreach (var arg in arguments) {
+                                       var arg_sn = arg.Expr as SimpleName;
+                                       if (arg_sn == null || arg_sn.Arity != 0) {
+                                               rc.Report.Error (8199, loc, "The syntax `var (...)' as an lvalue is reserved");
+                                               return ErrorExpression.Instance;
+                                       }
+
+                                       var lv = new LocalVariable (rc.CurrentBlock, arg_sn.Name, arg.Expr.Location);
+                                       rc.CurrentBlock.AddLocalName (lv);
+                                       variables.Add (lv);
+
+                                       targets.Add (new LocalVariableReference (lv, arg_sn.Location));
+                               }
+
+                               var res = new TupleDeconstruct (targets, variables, right_side, loc);
+                               return res.Resolve (rc);
+                       }
+
+                       if (right_side != null) {
+                               if (eclass != ExprClass.Unresolved)
+                                       return this;
+
+                               var res = DoResolveInvocation (rc, right_side);
+                               if (res == null)
+                                       return null;
+
+                               return res;
+                       }
+
+                       return base.DoResolveLValue (rc, right_side);
                }
 
-               Expression DoResolveInvocation (ResolveContext ec)
+               Expression DoResolveInvocation (ResolveContext ec, Expression rhs)
                {
                        Expression member_expr;
                        var atn = expr as ATypeNameExpression;
@@ -7140,6 +7305,17 @@ namespace Mono.CSharp
                        IsSpecialMethodInvocation (ec, method, loc);
                        
                        eclass = ExprClass.Value;
+
+                       if (type.Kind == MemberKind.ByRef) {
+                               if (rhs == null && arguments?.ContainsEmitWithAwait () == true) {
+                                       ec.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
+                                               GetSignatureForError ());
+                               }
+
+                               if (rhs != EmptyExpression.OutAccess)
+                                       return ByRefDereference.Create (this).Resolve (ec);
+                       }
+
                        return this;
                }
 
@@ -7273,7 +7449,14 @@ namespace Mono.CSharp
                        else
                                mg.EmitCall (ec, arguments, false);
                }
-               
+
+               public override void EmitPrepare (EmitContext ec)
+               {
+                       mg.EmitPrepare (ec);
+
+                       arguments?.EmitPrepare (ec);
+               }
+
                public override void EmitStatement (EmitContext ec)
                {
                        if (mg.IsConditionallyExcluded)
@@ -7440,6 +7623,10 @@ namespace Mono.CSharp
                
                protected override Expression DoResolve (ResolveContext ec)
                {
+                       if (RequestedType is TupleTypeExpr) {
+                               ec.Report.Error (8181, loc, "Tuple type cannot be used in an object creation expression. Use a tuple literal expression instead.");
+                       }
+
                        type = RequestedType.ResolveAsType (ec);
                        if (type == null)
                                return null;
@@ -7560,14 +7747,21 @@ namespace Mono.CSharp
                        bool is_value_type = type.IsStructOrEnum;
                        VariableReference vr = target as VariableReference;
 
+                       bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
+
                        if (target != null && is_value_type && (vr != null || method == null)) {
+                               if (prepare_await) {
+                                       arguments = arguments.Emit (ec, false, true);
+                                       prepare_await = false;
+                               }
+                               
                                target.AddressOf (ec, AddressOp.Store);
                        } else if (vr != null && vr.IsRef) {
                                vr.EmitLoad (ec);
                        }
 
                        if (arguments != null) {
-                               if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
+                               if (prepare_await)
                                        arguments = arguments.Emit (ec, false, true);
 
                                arguments.Emit (ec);
@@ -8597,9 +8791,7 @@ namespace Mono.CSharp
                        array_element_type = best_type_inference.InferredTypeArguments[0];
                        best_type_inference = null;
 
-                       if (array_element_type == null ||
-                               array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
-                               arguments.Count != rank.Dimension) {
+                       if (array_element_type == null || InternalType.HasNoType (array_element_type) || arguments.Count != rank.Dimension) {
                                ec.Report.Error (826, loc,
                                        "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
                                return null;
@@ -8842,7 +9034,7 @@ namespace Mono.CSharp
                        if (eclass == ExprClass.Unresolved)
                                ResolveBase (ec);
 
-                       if (type.IsClass){
+                       if (type.IsClass || type.IsReadOnly) {
                                if (right_side == EmptyExpression.UnaryAddress)
                                        ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
                                else if (right_side == EmptyExpression.OutAccess)
@@ -10485,8 +10677,12 @@ namespace Mono.CSharp
                        }
 
                        type = ac.Element;
-                       if (type.IsPointer && !ec.IsUnsafe) {
-                               UnsafeError (ec, ea.Location);
+                       if (type.IsPointer) {
+                               if (ec.CurrentIterator != null) {
+                                       UnsafeInsideIteratorError (ec, ea.Location);
+                               } else if (!ec.IsUnsafe) {
+                                       UnsafeError (ec, ea.Location);
+                               }
                        }
 
                        if (conditional_access_receiver)
@@ -11404,7 +11600,10 @@ namespace Mono.CSharp
                                if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
                                        return null;
 
-                               if (!ec.IsUnsafe) {
+                               var rc = ec as ResolveContext;
+                               if (rc?.CurrentIterator != null) {
+                                       UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
+                               } else if (!ec.IsUnsafe) {
                                        UnsafeError (ec.Module.Compiler.Report, loc);
                                }
 
@@ -11448,6 +11647,39 @@ namespace Mono.CSharp
                }
        }
 
+       class ReferenceTypeExpr : TypeExpr
+       {
+               FullNamedExpression element;
+
+               public ReferenceTypeExpr (FullNamedExpression element, Location loc)
+               {
+                       this.element = element;
+                       this.loc = loc;
+               }
+
+               public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
+               {
+                       type = element.ResolveAsType (mc);
+                       if (type == null)
+                               return null;
+
+                       eclass = ExprClass.Type;
+                       type = ReferenceContainer.MakeType (mc.Module, type);
+
+                       return type;
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       return "ref " + element.GetSignatureForError ();
+               }
+
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
+       }
+
        class FixedBufferPtr : Expression
        {
                readonly Expression array;
@@ -12174,21 +12406,23 @@ namespace Mono.CSharp
                                args);
                }
 
-               protected override Expression DoResolve (ResolveContext ec)
+               protected override Expression DoResolve (ResolveContext rc)
                {
-                       Expression e = base.DoResolve (ec);
+                       Expression e = base.DoResolve (rc);
                        if (type == null)
                                return null;
 
                        if (type.IsDelegate) {
-                               ec.Report.Error (1958, Initializers.Location,
+                               rc.Report.Error (1958, Initializers.Location,
                                        "Object and collection initializers cannot be used to instantiate a delegate");
                        }
 
-                       Expression previous = ec.CurrentInitializerVariable;
-                       ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
-                       initializers.Resolve (ec);
-                       ec.CurrentInitializerVariable = previous;
+                       Expression previous = rc.CurrentInitializerVariable;
+                       rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
+                       using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
+                               initializers.Resolve (rc);
+                       }
+                       rc.CurrentInitializerVariable = previous;
 
                        dynamic = e as DynamicExpressionStatement;
                        if (dynamic != null)
@@ -12483,7 +12717,7 @@ namespace Mono.CSharp
                        }
 
                        type = e.Type;
-                       if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
+                       if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || type.IsPointer || (e is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
                                Error_InvalidInitializer (ec, type.GetSignatureForError ());
                                return null;
                        }
@@ -12709,4 +12943,210 @@ namespace Mono.CSharp
                        return value;
                }
        }
+
+       class ThrowExpression : ExpressionStatement
+       {
+               Expression expr;
+
+               public ThrowExpression (Expression expr, Location loc)
+               {
+                       this.expr = expr;
+                       this.loc = loc;
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       var target = (ThrowExpression)t;
+                       target.expr = expr.Clone (clonectx);
+               }
+
+               public override bool ContainsEmitWithAwait ()
+               {
+                       return expr.ContainsEmitWithAwait ();
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext rc)
+               {
+                       rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
+                       return expr;
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
+
+                       if (expr == null)
+                               return null;
+
+                       expr = Throw.ConvertType (rc, expr);
+
+                       eclass = ExprClass.Value;
+                       type = InternalType.ThrowExpr;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       EmitStatement (ec);
+               }
+
+               public override void EmitStatement (EmitContext ec)
+               {
+                       expr.Emit (ec);
+
+                       ec.Emit (OpCodes.Throw);
+               }
+
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       expr.FlowAnalysis (fc);
+               }
+
+               public override Reachability MarkReachable (Reachability rc)
+               {
+                       return Reachability.CreateUnreachable ();
+               }
+       }
+
+       class ReferenceExpression : CompositeExpression
+       {
+               public ReferenceExpression (Expression expr, Location loc)
+                       : base (expr)
+               {
+                       this.loc = loc;
+               }
+
+               static bool CanBeByRef (Expression expr)
+               {
+                       if (expr is IAssignMethod)
+                               return true;
+
+                       var invocation = expr as Invocation;
+                       if (invocation?.Type.Kind == MemberKind.ByRef)
+                               return true;
+
+                       return false;
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext rc)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       var res = expr.DoResolveLValue (rc, EmptyExpression.OutAccess);
+                       if (res == null || !CanBeByRef (res)) {
+                               if (res?.Type != InternalType.ErrorType)
+                                       rc.Report.Error (8156, expr.Location, "An expression cannot be used in this context because it may not be returned by reference");
+                               return ErrorExpression.Instance;
+                       }
+
+                       type = res.Type;
+                       var type_container = type as ReferenceContainer;
+                       if (type_container != null)
+                               type = type_container.Element;
+
+                       expr = res;
+                       eclass = ExprClass.Value;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       var ml = expr as IMemoryLocation;
+                       if (ml != null)
+                               ml.AddressOf (ec, AddressOp.LoadStore);
+                       else
+                               expr.Emit (ec);
+               }
+
+               public override void Error_ValueCannotBeConverted (ResolveContext rc, TypeSpec target, bool expl)
+               {
+                       rc.Report.Error (8173, loc, "The expression must be of type `{0}' because it is being assigned by reference", target.GetSignatureForError ());
+               }
+       }
+
+       class ByRefDereference : CompositeExpression, IMemoryLocation, IAssignMethod
+       {
+               bool prepared;
+               LocalTemporary temporary;
+
+               private ByRefDereference (Expression expr)
+                       : base (expr)
+               {
+               }
+
+               public static Expression Create (Expression expr)
+               {
+                       var rc = expr.Type as ReferenceContainer;
+                       if (rc == null)
+                               return expr;
+
+                       return new ByRefDereference (expr) {
+                               type = rc.Element
+                       };
+               }
+
+               public void AddressOf (EmitContext ec, AddressOp mode)
+               {
+                       expr.Emit (ec);
+               }
+
+               public void Emit (EmitContext ec, bool leave_copy)
+               {
+                       Emit (ec);
+                       if (leave_copy) {
+                               ec.Emit (OpCodes.Dup);
+                               temporary = new LocalTemporary (type);
+                               temporary.Store (ec);
+                       }
+               }
+
+               public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
+               {
+                       prepared = isCompound;
+
+                       expr.Emit (ec);
+
+                       if (isCompound)
+                               ec.Emit (OpCodes.Dup);
+                       
+                       source.Emit (ec);
+                       if (leave_copy) {
+                               throw new NotImplementedException ("leave_copy");
+                       }
+                       
+                       ec.EmitStoreFromPtr (type);
+                       
+                       if (temporary != null) {
+                               temporary.Emit (ec);
+                               temporary.Release (ec);
+                       }
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       eclass = ExprClass.Variable;
+                       return this;
+               }
+
+               public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
+               {
+                       return DoResolve (rc);
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       if (!prepared)
+                               base.Emit(ec);
+                       
+                       ec.EmitLoadFromPtr (type);
+               }
+
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
+       }
 }