X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fexpression.cs;h=89207a3b54a26868eeadd5b13ed7110a4e9f768e;hb=1004d95b6b70e8b67a2b6782e0832faab9fa269a;hp=f805523b76e0a16f41bd3320409ad98aba4cab8e;hpb=c69ede50f2ab8deaee1b9970e025c0365a6496d6;p=mono.git diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index f805523b76e..89207a3b54a 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -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 (); @@ -1668,8 +1687,15 @@ namespace Mono.CSharp ec.Emit (OpCodes.Dup); no_value_label = ec.DefineLabel (); ec.Emit (OpCodes.Brfalse_S, no_value_label); + + if (Variable.HoistedVariant != null) + ec.EmitThis (); + expr_unwrap.Emit (ec); } else { + if (Variable?.HoistedVariant != null) + ec.EmitThis (); + expr.Emit (ec); // Only to make verifier happy @@ -1689,13 +1715,29 @@ namespace Mono.CSharp value_on_stack = false; } - Variable.CreateBuilder (ec); - Variable.EmitAssign (ec); + if (Variable.HoistedVariant != null) { + Variable.HoistedVariant.EmitAssignFromStack (ec); + + if (expr_unwrap != null) { + ec.MarkLabel (no_value_label); + } else if (!value_on_stack) { + 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 (expr_unwrap != null) { + ec.MarkLabel (no_value_label); + } else if (!value_on_stack) { + Variable.Emit (ec); + } } } } @@ -1733,6 +1775,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 +1900,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 +1916,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 +1930,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 +1979,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 +2437,17 @@ 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; + } + if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) { if (TypeManager.IsGenericParameter (type)) { ec.Report.Error (413, loc, @@ -2448,8 +2534,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; @@ -2526,7 +2616,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); @@ -2547,12 +2638,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; @@ -2597,6 +2690,11 @@ namespace Mono.CSharp { throw new NotImplementedException (); } + + public override void EmitPrepare (EmitContext ec) + { + Variable.CreateBuilder (ec); + } } // @@ -3105,9 +3203,9 @@ namespace Mono.CSharp public override Expression ConvertResult (ResolveContext ec, Binary b) { if (left != null) { - b.left = EmptyCast.Create (b.left, left); + b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left); } else if (right != null) { - b.right = EmptyCast.Create (b.right, right); + b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right); } TypeSpec r_type = ReturnType; @@ -3443,7 +3541,7 @@ namespace Mono.CSharp } } - static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op) + public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op) { switch (op) { case Operator.Addition: @@ -6464,18 +6562,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); @@ -6483,13 +6582,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); @@ -6573,7 +6672,7 @@ namespace Mono.CSharp } public override bool IsRef { - get { return false; } + get { return local_info.IsByRef; } } public override string Name { @@ -6614,7 +6713,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 ()); } @@ -7036,10 +7139,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 (arguments.Count); + var variables = new List (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; @@ -7135,6 +7276,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; } @@ -7268,7 +7420,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) @@ -7435,6 +7594,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; @@ -7555,14 +7718,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); @@ -8592,9 +8762,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; @@ -8837,7 +9005,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) @@ -9959,7 +10127,7 @@ namespace Mono.CSharp TypeSpec nested = null; while (expr_type != null) { - nested = MemberCache.FindNestedType (expr_type, Name, Arity); + nested = MemberCache.FindNestedType (expr_type, Name, Arity, false); if (nested == null) { if (expr_type == tnew_expr) { Error_IdentifierNotFound (rc, expr_type); @@ -9967,7 +10135,7 @@ namespace Mono.CSharp } expr_type = tnew_expr; - nested = MemberCache.FindNestedType (expr_type, Name, Arity); + nested = MemberCache.FindNestedType (expr_type, Name, Arity, false); ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc); break; } @@ -10008,7 +10176,7 @@ namespace Mono.CSharp public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type) { - var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity)); + var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false); if (nested != null) { Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location); @@ -10480,8 +10648,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) @@ -10947,9 +11119,18 @@ namespace Mono.CSharp #region IBaseMembersProvider Members - IList OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType) + IList OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type) { - return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false); + var baseType = type.BaseType; + var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false); + + if (members == null && !type.IsInterface) { + var tps = queried_type as TypeParameterSpec; + if (tps != null) + members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias); + } + + return members; } IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member) @@ -11390,7 +11571,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); } @@ -11434,6 +11618,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; @@ -12160,21 +12377,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) @@ -12251,6 +12470,7 @@ namespace Mono.CSharp throw new NotImplementedException (); sf = ec.GetTemporaryField (type); + sf.AutomaticallyReuse = false; sf.EmitAssign (ec, temp, false, false); temp_target = sf; temp.Release (ec); @@ -12268,8 +12488,8 @@ namespace Mono.CSharp temp.Release (ec); if (sf != null) - sf.IsAvailableForReuse = true; - + sf.PrepareCleanup (ec); + return true; } @@ -12347,6 +12567,7 @@ namespace Mono.CSharp int errors = ec.Report.Errors; type.CreateContainer (); type.DefineContainer (); + type.ExpandBaseInterfaces (); type.Define (); if ((ec.Report.Errors - errors) == 0) { parent.Module.AddAnonymousType (type); @@ -12467,7 +12688,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; } @@ -12693,4 +12914,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); + } + } }