[mcs] C#7 throw expression
[mono.git] / mcs / mcs / anonymous.cs
index 1063fb1b07774bbf529adea254919c0cd18f71f1..6cec0e1da6dc57513c0af368e3ec08a8f5ac6848 100644 (file)
@@ -343,7 +343,7 @@ namespace Mono.CSharp {
                        }
 
                        if (hoisted == null) {
-                               hoisted = new HoistedLocalVariable (this, localVariable, GetVariableMangledName (localVariable));
+                               hoisted = new HoistedLocalVariable (this, localVariable, GetVariableMangledName (ec, localVariable));
                                localVariable.HoistedVariant = hoisted;
 
                                if (hoisted_locals == null)
@@ -526,7 +526,7 @@ namespace Mono.CSharp {
                                fexpr.EmitAssign (ec, source, false, false);
                                Instance = fexpr;
                        } else {
-                               var local = TemporaryVariableReference.Create (source.Type, block, Location);
+                               var local = TemporaryVariableReference.Create (source.Type, block, Location, writeToSymbolFile: true);
                                if (source.Type.IsStruct) {
                                        local.LocalInfo.CreateBuilder (ec);
                                } else {
@@ -667,7 +667,7 @@ namespace Mono.CSharp {
                        return f_ind;
                }
 
-               protected virtual string GetVariableMangledName (LocalVariable local_info)
+               protected virtual string GetVariableMangledName (ResolveContext rc, LocalVariable local_info)
                {
                        //
                        // No need to mangle anonymous method hoisted variables cause they
@@ -1154,7 +1154,8 @@ namespace Mono.CSharp {
                                        prev = null;
                                }
 
-                               var body = CompatibleMethodBody (ec, tic, null, delegate_type);
+                               HashSet<LocalVariable> undeclaredVariables = null;
+                               var body = CompatibleMethodBody (ec, tic, null, delegate_type, ref undeclaredVariables);
                                if (body != null) {
                                        am = body.Compatible (ec, body);
                                } else {
@@ -1164,6 +1165,10 @@ namespace Mono.CSharp {
                                if (TypeInferenceReportPrinter != null) {
                                        ec.Report.SetPrinter (prev);
                                }
+
+                               if (undeclaredVariables != null) {
+                                       body.Block.TopBlock.SetUndeclaredVariables (undeclaredVariables);
+                               }
                        }
 
                        if (am == null)
@@ -1188,6 +1193,9 @@ namespace Mono.CSharp {
                        if (compatibles.TryGetValue (type, out am))
                                return am;
 
+                       if (type == InternalType.ErrorType)
+                               return null;
+
                        TypeSpec delegate_type = CompatibleChecks (ec, type);
                        if (delegate_type == null)
                                return null;
@@ -1206,8 +1214,8 @@ namespace Mono.CSharp {
                        // we satisfy the rule by setting the return type on the EmitContext
                        // to be the delegate type return type.
                        //
-
-                       var body = CompatibleMethodBody (ec, null, return_type, delegate_type);
+                       HashSet<LocalVariable> undeclaredVariables = null;
+                       var body = CompatibleMethodBody (ec, null, return_type, delegate_type, ref undeclaredVariables);
                        if (body == null)
                                return null;
 
@@ -1265,6 +1273,15 @@ namespace Mono.CSharp {
                                throw;
                        } catch (Exception e) {
                                throw new InternalErrorException (e, loc);
+                       } finally {
+                               //
+                               // LocalVariable is not stateless and it's not easy to clone because it's
+                               // cached in toplevel block. Unsetting any initialized variables should
+                               // be enough
+                               //
+                               if (undeclaredVariables != null) {
+                                       body.Block.TopBlock.SetUndeclaredVariables (undeclaredVariables);
+                               }
                        }
 
                        if (!ec.IsInProbingMode && !etree_conversion) {
@@ -1384,13 +1401,13 @@ namespace Mono.CSharp {
                        return ExprClassName;
                }
 
-               AnonymousMethodBody CompatibleMethodBody (ResolveContext ec, TypeInferenceContext tic, TypeSpec return_type, TypeSpec delegate_type)
+               AnonymousMethodBody CompatibleMethodBody (ResolveContext ec, TypeInferenceContext tic, TypeSpec return_type, TypeSpec delegate_type, ref HashSet<LocalVariable> undeclaredVariables)
                {
                        ParametersCompiled p = ResolveParameters (ec, tic, delegate_type);
                        if (p == null)
                                return null;
 
-                       ParametersBlock b = ec.IsInProbingMode ? (ParametersBlock) Block.PerformClone () : Block;
+                       ParametersBlock b = ec.IsInProbingMode ? (ParametersBlock) Block.PerformClone (ref undeclaredVariables) : Block;
 
                        if (b.IsAsync) {
                                var rt = return_type;
@@ -1578,6 +1595,15 @@ namespace Mono.CSharp {
                        if (res && errors != ec.Report.Errors)
                                return null;
 
+                       if (block.IsAsync && block.Original.ParametersBlock.HasCapturedThis && ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.block.IsAsync) {
+                               //
+                               // We'll do ldftn to load the fabricated m_X method but
+                               // because we are inside struct the method can be hoisted
+                               // anywhere in the parent scope
+                               //
+                               ec.CurrentBlock.ParametersBlock.HasReferenceToStoreyForInstanceLambdas = true;
+                       }
+
                        return res ? this : null;
                }
 
@@ -1626,9 +1652,10 @@ namespace Mono.CSharp {
                        fc.TryFinally = prev_tf;
                }
 
-               public override void MarkReachable (Reachability rc)
+               public override Reachability MarkReachable (Reachability rc)
                {
                        block.MarkReachable (rc);
+                       return rc;
                }
 
                public void SetHasThisAccess ()
@@ -1781,6 +1808,8 @@ namespace Mono.CSharp {
                                                        parent = storey = sm;
                                                }
                                        }
+                               } else if (src_block.ParametersBlock.HasReferenceToStoreyForInstanceLambdas) {
+                                       src_block.ParametersBlock.StateMachine.AddParentStoreyReference (ec, storey);
                                }
 
                                modifiers = storey != null ? Modifiers.INTERNAL : Modifiers.PRIVATE;
@@ -1920,17 +1949,16 @@ namespace Mono.CSharp {
 
                        var delegate_method = method.Spec;
                        if (storey != null && storey.MemberName.IsGeneric) {
-                               TypeSpec t = storey.Instance.Type;
-
                                //
                                // Mutate anonymous method instance type if we are in nested
                                // hoisted generic anonymous method storey
                                //
                                if (ec.IsAnonymousStoreyMutateRequired) {
-                                       t = storey.Mutator.Mutate (t);
+                                       ec.Emit (OpCodes.Ldftn, delegate_method);
+                               } else {
+                                       TypeSpec t = storey.Instance.Type;
+                                       ec.Emit (OpCodes.Ldftn, TypeBuilder.GetMethod (t.GetMetaInfo (), (MethodInfo) delegate_method.GetMetaInfo ()));
                                }
-
-                               ec.Emit (OpCodes.Ldftn, TypeBuilder.GetMethod (t.GetMetaInfo (), (MethodInfo) delegate_method.GetMetaInfo ()));
                        } else {
                                if (delegate_method.IsGeneric) {
                                        TypeParameterSpec[] tparams;