Merge pull request #949 from ermshiperete/bug-novell-463149
[mono.git] / mcs / mcs / anonymous.cs
index 27b1485f56a92473f0ca42559ea8b3edb8b4620d..9431e499d0c83fea6d33649604e2d2c268211085 100644 (file)
@@ -214,6 +214,11 @@ namespace Mono.CSharp {
                                hoisted_this.EmitAssign (ec, source, false, false);
                        }
 
+                       protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+                       {
+                               return false;
+                       }
+
                        protected override void CloneTo (CloneContext clonectx, Statement target)
                        {
                                // Nothing to clone
@@ -1262,7 +1267,7 @@ namespace Mono.CSharp {
                                throw new InternalErrorException (e, loc);
                        }
 
-                       if (!ec.IsInProbingMode) {
+                       if (!ec.IsInProbingMode && !etree_conversion) {
                                compatibles.Add (type, am ?? EmptyExpression.Null);
                        }
 
@@ -1339,13 +1344,6 @@ namespace Mono.CSharp {
                        if (!DoResolveParameters (ec))
                                return null;
 
-#if !STATIC
-                       // FIXME: The emitted code isn't very careful about reachability
-                       // so, ensure we have a 'ret' at the end
-                       BlockContext bc = ec as BlockContext;
-                       if (bc != null && bc.CurrentBranching != null && bc.CurrentBranching.CurrentUsageVector.IsUnreachable)
-                               bc.NeedReturnLabel ();
-#endif
                        return this;
                }
 
@@ -1521,12 +1519,28 @@ namespace Mono.CSharp {
                        }
 
                        var bc = ec as BlockContext;
-                       if (bc != null)
+
+                       if (bc != null) {
                                aec.AssignmentInfoOffset = bc.AssignmentInfoOffset;
+                               aec.EnclosingLoop = bc.EnclosingLoop;
+                               aec.EnclosingLoopOrSwitch = bc.EnclosingLoopOrSwitch;
+                               aec.Switch = bc.Switch;
+                       }
 
                        var errors = ec.Report.Errors;
 
-                       bool res = Block.Resolve (ec.CurrentBranching, aec, null);
+                       bool res = Block.Resolve (aec);
+
+                       if (res && errors == ec.Report.Errors) {
+                               MarkReachable (new Reachability ());
+
+                               if (!CheckReachableExit (ec.Report)) {
+                                       return null;
+                               }
+
+                               if (bc != null)
+                                       bc.AssignmentInfoOffset = aec.AssignmentInfoOffset;
+                       }
 
                        if (am != null && am.ReturnTypeInference != null) {
                                am.ReturnTypeInference.FixAllTypes (ec);
@@ -1557,6 +1571,48 @@ namespace Mono.CSharp {
                        return false;
                }
 
+               bool CheckReachableExit (Report report)
+               {
+                       if (block.HasReachableClosingBrace && ReturnType.Kind != MemberKind.Void) {
+                               // FIXME: Flow-analysis on MoveNext generated code
+                               if (!IsIterator) {
+                                       report.Error (1643, StartLocation,
+                                                       "Not all code paths return a value in anonymous method of type `{0}'", GetSignatureForError ());
+
+                                       return false;
+                               }
+                       }
+
+                       return true;
+               }
+
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       // We are reachable, mark block body reachable too
+                       MarkReachable (new Reachability ());
+
+                       CheckReachableExit (fc.Report);
+
+                       var das = fc.BranchDefiniteAssignment ();
+                       var prev_pb = fc.ParametersBlock;
+                       fc.ParametersBlock = Block;
+                       var da_ontrue = fc.DefiniteAssignmentOnTrue;
+                       var da_onfalse = fc.DefiniteAssignmentOnFalse;
+
+                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
+                       block.FlowAnalysis (fc);
+
+                       fc.ParametersBlock = prev_pb;
+                       fc.DefiniteAssignment = das;
+                       fc.DefiniteAssignmentOnTrue = da_ontrue;
+                       fc.DefiniteAssignmentOnFalse = da_onfalse;
+               }
+
+               public override void MarkReachable (Reachability rc)
+               {
+                       block.MarkReachable (rc);
+               }
+
                public void SetHasThisAccess ()
                {
                        ExplicitBlock b = block;
@@ -1666,6 +1722,7 @@ namespace Mono.CSharp {
 
                        Modifiers modifiers;
                        TypeDefinition parent = null;
+                       TypeParameters hoisted_tparams = null;
 
                        var src_block = Block.Original.Explicit;
                        if (src_block.HasCapturedVariable || src_block.HasCapturedThis) {
@@ -1697,6 +1754,7 @@ namespace Mono.CSharp {
                                                        // use ldftn on non-boxed instances either to share mutated state
                                                        //
                                                        parent = sm_parent.Parent.PartialContainer;
+                                                       hoisted_tparams = sm_parent.OriginalTypeParameters;
                                                } else if (sm is IteratorStorey) {
                                                        //
                                                        // For iterators we can host everything in one class
@@ -1714,6 +1772,9 @@ namespace Mono.CSharp {
                                modifiers = Modifiers.STATIC | Modifiers.PRIVATE;
                        }
 
+                       if (storey == null && hoisted_tparams == null)
+                               hoisted_tparams = ec.CurrentTypeParameters;
+
                        if (parent == null)
                                parent = ec.CurrentTypeDefinition.Parent.PartialContainer;
 
@@ -1721,9 +1782,7 @@ namespace Mono.CSharp {
                                "m", null, parent.PartialContainer.CounterAnonymousMethods++);
 
                        MemberName member_name;
-                       if (storey == null && ec.CurrentTypeParameters != null) {
-
-                               var hoisted_tparams = ec.CurrentTypeParameters;
+                       if (hoisted_tparams != null) {
                                var type_params = new TypeParameters (hoisted_tparams.Count);
                                for (int i = 0; i < hoisted_tparams.Count; ++i) {
                                    type_params.Add (hoisted_tparams[i].CreateHoistedCopy (null));
@@ -1844,8 +1903,17 @@ namespace Mono.CSharp {
 
                                ec.Emit (OpCodes.Ldftn, TypeBuilder.GetMethod (t.GetMetaInfo (), (MethodInfo) delegate_method.GetMetaInfo ()));
                        } else {
-                               if (delegate_method.IsGeneric)
-                                       delegate_method = delegate_method.MakeGenericMethod (ec.MemberContext, method.TypeParameters);
+                               if (delegate_method.IsGeneric) {
+                                       TypeParameterSpec[] tparams;
+                                       var sm = ec.CurrentAnonymousMethod == null ? null : ec.CurrentAnonymousMethod.Storey as StateMachine;
+                                       if (sm != null && sm.OriginalTypeParameters != null) {
+                                               tparams = sm.CurrentTypeParameters.Types;
+                                       } else {
+                                               tparams = method.TypeParameters;
+                                       }
+
+                                       delegate_method = delegate_method.MakeGenericMethod (ec.MemberContext, tparams);
+                               }
 
                                ec.Emit (OpCodes.Ldftn, delegate_method);
                        }
@@ -2106,7 +2174,6 @@ namespace Mono.CSharp {
 
                        equals.Block = equals_block;
                        equals.Define ();
-                       equals.PrepareEmit ();
                        Members.Add (equals);
 
                        //
@@ -2161,7 +2228,6 @@ namespace Mono.CSharp {
                        hashcode_block.AddStatement (new Return (hash_variable, loc));
                        hashcode.Block = hashcode_top;
                        hashcode.Define ();
-                       hashcode.PrepareEmit ();
                        Members.Add (hashcode);
 
                        //
@@ -2172,7 +2238,6 @@ namespace Mono.CSharp {
                        tostring_block.AddStatement (new Return (string_concat, loc));
                        tostring.Block = tostring_block;
                        tostring.Define ();
-                       tostring.PrepareEmit ();
                        Members.Add (tostring);
 
                        return true;