+
+ 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);
+ }
+ }