2003-04-28 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / codegen.cs
index ef1da7938f6aeb21ddf93c4b71a4edabba7bae3e..b10dc6be02c81b9267e52687c8eb5461763bdb49 100755 (executable)
@@ -217,6 +217,17 @@ namespace Mono.CSharp {
                /// </summary>
                public bool InTry;
 
+               /// <summary>
+               ///   Whether we are inside an iterator block.
+               /// </summary>
+               public bool InIterator;
+               
+               /// <summary>
+               ///   Whether remapping of locals, parameters and fields is turned on.
+               ///   Used by iterators and anonymous methods.
+               /// </summary>
+               public bool RemapToProxy;
+
                /// <summary>
                ///   Whether we are in a Catch block
                /// </summary>
@@ -227,6 +238,11 @@ namespace Mono.CSharp {
                /// </summary>
                public bool InUnsafe;
 
+               /// <summary>
+               ///  Whether we are inside an anonymous method.
+               /// </summary>
+               public bool InAnonymousMethod;
+               
                /// <summary>
                ///   Location for this EmitContext
                /// </summary>
@@ -262,6 +278,8 @@ namespace Mono.CSharp {
                        ConstantCheckState = true;
                        
                        IsStatic = (code_flags & Modifiers.STATIC) != 0;
+                       InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
+                       RemapToProxy = InIterator;
                        ReturnType = return_type;
                        IsConstructor = is_constructor;
                        CurrentBlock = null;
@@ -412,7 +430,7 @@ namespace Mono.CSharp {
                                CurrentFile = loc.File;
 
                        if (block != null){
-                               try {
+                           try {
                                int errors = Report.Errors;
 
                                block.EmitMeta (this, block);
@@ -447,13 +465,16 @@ namespace Mono.CSharp {
                                                        block.UsageWarning ();
                                        }
                                }
-                               } catch {
+                           } catch {
                                        Console.WriteLine ("Exception caught by the compiler while compiling:");
                                        Console.WriteLine ("   Block that caused the problem begin at: " + loc);
-                                       Console.WriteLine ("                     Block being compiled: [{0},{1}]",
-                                                          CurrentBlock.StartLocation, CurrentBlock.EndLocation);
+                                       
+                                       if (CurrentBlock != null){
+                                               Console.WriteLine ("                     Block being compiled: [{0},{1}]",
+                                                                  CurrentBlock.StartLocation, CurrentBlock.EndLocation);
+                                       }
                                        throw;
-                               }
+                           }
                        }
 
                        if (ReturnType != null && !has_ret){
@@ -462,8 +483,10 @@ namespace Mono.CSharp {
                                // correctly and emit an error instead of a warning.
                                //
                                //
-                               Report.Error (161, loc, "Not all code paths return a value");
-                               return;
+                               if (!InIterator){
+                                       Report.Error (161, loc, "Not all code paths return a value");
+                                       return;
+                               }
                        }
 
                        if (HasReturnLabel)
@@ -473,6 +496,9 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Ret);
                        } else {
                                if (!InTry){
+                                       if (InIterator)
+                                               has_ret = true;
+                                       
                                        if (!has_ret || HasReturnLabel)
                                                ig.Emit (OpCodes.Ret);
                                }
@@ -567,6 +593,34 @@ namespace Mono.CSharp {
                        return return_value;
                }
 
+               //
+               // Creates a field `name' with the type `t' on the proxy class
+               //
+               public FieldBuilder MapVariable (string name, Type t)
+               {
+                       if (InIterator){
+                               return IteratorHandler.Current.MapVariable (name, t);
+                       }
+
+                       throw new Exception ("MapVariable for an unknown state");
+               }
+
+               //
+               // Emits the proper object to address fields on a remapped
+               // variable/parameter to field in anonymous-method/iterator proxy classes.
+               //
+               public void EmitThis ()
+               {
+                       ig.Emit (OpCodes.Ldarg_0);
+
+                       if (!IsStatic){
+                               if (InIterator)
+                                       ig.Emit (OpCodes.Ldfld, IteratorHandler.Current.this_field);
+                               else
+                                       throw new Exception ("EmitThis for an unknown state");
+                       }
+               }
+
                /// <summary>
                ///   A dynamic This that is shared by all variables in a emitcontext.
                ///   Created on demand.