[mcs] C#7 out variable declaration
[mono.git] / mcs / mcs / expression.cs
index f805523b76e0a16f41bd3320409ad98aba4cab8e..bb6255ce48740f0641084d38c0b30a7c82497e7f 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;
 
@@ -2362,6 +2368,11 @@ namespace Mono.CSharp
                        eclass = ExprClass.Value;
                        TypeSpec etype = expr.Type;
 
+                       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 +2459,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;
@@ -2547,12 +2562,18 @@ 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)
                {
+                       if (rc.HasAny (ResolveContext.Options.BaseInitializer | ResolveContext.Options.FieldInitializerScope)) {
+                               rc.Report.Error (8200, loc, "Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers");
+                       } else if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) {
+                               rc.Report.Error (8201, loc, "Out variable and pattern variable declarations are not allowed within a query clause");
+                       }
+
                        var var_expr = VariableType as VarExpr;
                        if (var_expr != null) {
                                type = InternalType.VarOutType;
@@ -3105,9 +3126,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 +3464,7 @@ namespace Mono.CSharp
                        }
                }
 
-               static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
+               public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
                {
                        switch (op) {
                        case Operator.Addition:
@@ -7555,14 +7576,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);
@@ -9959,7 +9987,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 +9995,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 +10036,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 +10508,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 +10979,18 @@ namespace Mono.CSharp
 
                #region IBaseMembersProvider Members
 
-               IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
+               IList<MemberSpec> 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 +11431,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);
                                }
 
@@ -12160,21 +12204,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 +12297,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 +12315,8 @@ namespace Mono.CSharp
                                temp.Release (ec);
 
                        if (sf != null)
-                               sf.IsAvailableForReuse = true;
-
+                               sf.PrepareCleanup (ec);
+                       
                        return true;
                }
 
@@ -12347,6 +12394,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);
@@ -12693,4 +12741,68 @@ 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 ();
+               }
+       }
 }