[mcs] Fixes codegen for type pattern matching in probing expressions over hoisted...
[mono.git] / mcs / mcs / expression.cs
index da37657867ed0e59f43a1d9eefdd010e977e9ae8..896980968d82efd168067c2664980380ecbe842c 100644 (file)
@@ -1687,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
@@ -1708,19 +1715,29 @@ namespace Mono.CSharp
                                        value_on_stack = false;
                                }
 
-                               //
-                               // It's ok to have variable builder create out of order. It simplified emit
-                               // of statements like while (condition) { }
-                               //
-                               if (!Variable.Created)
-                                       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);
 
-                               if (expr_unwrap != null) {
-                                       ec.MarkLabel (no_value_label);
-                               } else if (!value_on_stack) {
-                                       Variable.Emit (ec);
+                                       Variable.EmitAssign (ec);
+
+                                       if (expr_unwrap != null) {
+                                               ec.MarkLabel (no_value_label);
+                                       } else if (!value_on_stack) {
+                                               Variable.Emit (ec);
+                                       }
                                }
                        }
                }
@@ -2420,6 +2437,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;
@@ -7108,6 +7131,33 @@ namespace Mono.CSharp
                        return DoResolveInvocation (rc);
                }
 
+               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);
+                       }
+
+                       return base.DoResolveLValue (rc, right_side);
+               }
+
                Expression DoResolveInvocation (ResolveContext ec)
                {
                        Expression member_expr;
@@ -7504,6 +7554,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;
@@ -8668,9 +8722,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;
@@ -12563,7 +12615,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;
                        }