2 // anonymous.cs: Support for anonymous methods
5 // Miguel de Icaza (miguel@ximain.com)
7 // (C) 2003, 2004 Novell, Inc.
9 // TODO: Ideally, we should have the helper classes emited as a hierarchy to map
10 // their nesting, and have the visibility set to private, instead of NestedAssembly
17 using System.Collections;
18 using System.Reflection;
19 using System.Reflection.Emit;
21 namespace Mono.CSharp {
23 public class AnonymousMethod : Expression {
24 // Used to generate unique method names.
25 static int anonymous_method_count;
27 // An array list of AnonymousMethodParameter or null
28 public Parameters Parameters;
31 // The block that makes up the body for the anonymous mehtod
33 public ToplevelBlock Block;
36 // The container block for this anonymous method.
38 public Block ContainingBlock;
41 // The implicit method we create
47 // The emit context for the anonymous method
48 public EmitContext aec;
49 public InternalParameters amp;
53 // The modifiers applied to the method, we aggregate them
55 int method_modifiers = Modifiers.PRIVATE;
58 // During the resolve stage of the anonymous method body,
59 // we discover the actual scope where we are hosted, or
60 // null to host the method in the same class
62 public ScopeInfo Scope;
65 // Points to our container anonymous method if its present
67 public AnonymousMethod ContainerAnonymousMethod;
69 public AnonymousMethod (Parameters parameters, ToplevelBlock container, ToplevelBlock block, Location l)
71 Parameters = parameters;
76 // The order is important: this setups the CaptureContext tree hierarchy.
78 container.SetHaveAnonymousMethods (l, this);
79 block.SetHaveAnonymousMethods (l, this);
82 public override Expression DoResolve (EmitContext ec)
85 // Set class type, set type
88 eclass = ExprClass.Value;
91 // This hack means `The type is not accessible
92 // anywhere', we depend on special conversion
95 type = TypeManager.anonymous_method_type;
100 public override void Emit (EmitContext ec)
102 // nothing, as we only exist to not do anything.
106 // Creates the host for the anonymous method
108 bool CreateMethodHost (EmitContext ec, Type return_type)
111 // Crude hack follows: we replace the TypeBuilder during the
112 // definition to get the method hosted in the right class
115 TypeBuilder current_type = ec.TypeContainer.TypeBuilder;
116 TypeBuilder type_host = (Scope == null ) // || Scope.ScopeTypeBuilder == null)
117 ? current_type : Scope.ScopeTypeBuilder;
119 if (current_type == null)
120 throw new Exception ("The current_type is null");
122 if (type_host == null)
123 throw new Exception (String.Format ("Type host is null, Scope is {0}", Scope == null ? "null" : "Not null"));
125 if (current_type == type_host && ec.IsStatic){
127 method_modifiers |= Modifiers.STATIC;
132 method = new Method (
133 (TypeContainer) ec.TypeContainer,
134 new TypeExpression (return_type, loc),
135 method_modifiers, false, new MemberName ("<#AnonymousMethod>" + anonymous_method_count++),
136 Parameters, null, loc);
137 method.Block = Block;
140 // Swap the TypeBuilder while we define the method, then restore
142 if (current_type != null)
143 ec.TypeContainer.TypeBuilder = type_host;
144 bool res = method.Define ();
145 if (current_type != null)
146 ec.TypeContainer.TypeBuilder = current_type;
150 void Error_ParameterMismatch (Type t)
152 Report.Error (1661, loc, "Anonymous method could not be converted to delegate `" +
153 "{0}' since there is a parameter mismatch", t);
157 // Returns true if this anonymous method can be implicitly
158 // converted to the delegate type `delegate_type'
160 public Expression Compatible (EmitContext ec, Type delegate_type, bool probe)
163 // At this point its the first time we know the return type that is
164 // needed for the anonymous method. We create the method here.
167 invoke_mb = (MethodInfo) Delegate.GetInvokeMethod (ec, delegate_type, loc);
168 ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
170 if (Parameters == null){
174 // We provide a set of inaccessible parameters
177 for (i = 0; i < invoke_pd.Count; i++){
178 if (invoke_pd.ParameterModifier (i) == Parameter.Modifier.PARAMS)
181 int n = invoke_pd.Count - (params_idx != -1 ? 1 : 0);
182 Parameter [] fixedpars = new Parameter [n];
184 for (i = j = 0; i < invoke_pd.Count; i++){
185 if (invoke_pd.ParameterModifier (i) == Parameter.Modifier.PARAMS)
187 fixedpars [j] = new Parameter (
188 new TypeExpression (invoke_pd.ParameterType (i), loc),
189 "+" + j, invoke_pd.ParameterModifier (i), null, loc);
193 Parameter variable = null;
194 if (params_idx != -1){
195 variable = new Parameter (
196 new TypeExpression (invoke_pd.ParameterType (params_idx), loc),
197 "+" + params_idx, invoke_pd.ParameterModifier (params_idx), null, loc);
200 Parameters = new Parameters (fixedpars, variable);
204 // First, parameter types of `delegate_type' must be compatible
205 // with the anonymous method.
207 amp = new InternalParameters (Parameters.GetParameterInfo (ec), Parameters);
209 if (amp.Count != invoke_pd.Count){
211 Report.Error (1593, loc,
212 "Anonymous method has {0} parameters, while delegate requires {1}",
213 amp.Count, invoke_pd.Count);
214 Error_ParameterMismatch (delegate_type);
219 for (int i = 0; i < amp.Count; i++){
220 Parameter.Modifier amp_mod = amp.ParameterModifier (i);
222 if ((amp_mod & (Parameter.Modifier.OUT | Parameter.Modifier.REF)) != 0){
224 Error_ParameterMismatch (delegate_type);
225 Report.Error (1677, loc, "Parameter '{0}' should not be declared with the '{1}' keyword",
226 i+1, amp.ModifierDesc (i));
231 if (amp_mod != invoke_pd.ParameterModifier (i)){
233 Report.Error (1676, loc,
234 "Signature mismatch in parameter modifier for parameter #0", i + 1);
235 Error_ParameterMismatch (delegate_type);
240 if (amp.ParameterType (i) != invoke_pd.ParameterType (i)){
242 Report.Error (1678, loc,
243 "Signature mismatch in parameter {0}: need `{1}' got `{2}'", i + 1,
244 TypeManager.CSharpName (invoke_pd.ParameterType (i)),
245 TypeManager.CSharpName (amp.ParameterType (i)));
246 Error_ParameterMismatch (delegate_type);
253 // If we are only probing, return ourselves
259 // Second: the return type of the delegate must be compatible with
260 // the anonymous type. Instead of doing a pass to examine the block
261 // we satisfy the rule by setting the return type on the EmitContext
262 // to be the delegate type return type.
265 //MethodBuilder builder = method_data.MethodBuilder;
266 //ILGenerator ig = builder.GetILGenerator ();
269 aec = new EmitContext (
270 ec.TypeContainer, ec.DeclSpace, loc, null,
271 invoke_mb.ReturnType,
272 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
273 (ec.InUnsafe ? Modifiers.UNSAFE : 0) |
274 (ec.IsStatic ? Modifiers.STATIC : 0),
275 /* No constructor */ false);
277 aec.CurrentAnonymousMethod = this;
278 ContainerAnonymousMethod = ec.CurrentAnonymousMethod;
279 ContainingBlock = ec.CurrentBlock;
281 if (aec.ResolveTopBlock (ec, Block, amp, loc, out unreachable))
282 return new AnonymousDelegate (this, delegate_type, loc).Resolve (ec);
287 public MethodBuilder GetMethodBuilder ()
289 return method.MethodData.MethodBuilder;
292 public bool EmitMethod (EmitContext ec)
294 if (!CreateMethodHost (ec, invoke_mb.ReturnType))
297 MethodBuilder builder = GetMethodBuilder ();
298 ILGenerator ig = builder.GetILGenerator ();
301 Parameters.LabelParameters (aec, builder);
304 // Adjust based on the computed state of the
305 // method from CreateMethodHost
307 aec.MethodIsStatic = (method_modifiers & Modifiers.STATIC) != 0;
309 aec.EmitMeta (Block, amp);
310 aec.EmitResolvedTopBlock (Block, unreachable);
314 public static void Error_AddressOfCapturedVar (string name, Location loc)
316 Report.Error (1686, loc,
317 "Variable {0} is captured in an anonymous method and its address is also being taken: they are exclusive", name);
322 // This will emit the code for the delegate, as well delegate creation on the host
324 public class AnonymousDelegate : DelegateCreation {
327 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
334 public override Expression DoResolve (EmitContext ec)
336 eclass = ExprClass.Value;
341 public override void Emit (EmitContext ec)
343 if (!am.EmitMethod (ec))
347 // Now emit the delegate creation.
349 if ((am.method.ModFlags & Modifiers.STATIC) == 0)
350 delegate_instance_expression = new AnonymousInstance (am);
352 Expression ml = Expression.MemberLookup (ec, type, ".ctor", loc);
353 constructor_method = ((MethodGroupExpr) ml).Methods [0];
354 delegate_method = am.GetMethodBuilder ();
358 class AnonymousInstance : Expression {
361 public AnonymousInstance (AnonymousMethod am)
364 eclass = ExprClass.Value;
367 public override Expression DoResolve (EmitContext ec)
372 public override void Emit (EmitContext ec)
374 am.aec.EmitMethodHostInstance (ec, am);
379 class CapturedParameter {
381 public FieldBuilder FieldBuilder;
384 public CapturedParameter (Type type, int idx)
392 // Here we cluster all the variables captured on a given scope, we also
393 // keep some extra information that might be required on each scope.
395 public class ScopeInfo {
396 public CaptureContext CaptureContext;
397 public ScopeInfo ParentScope;
398 public Block ScopeBlock;
399 public bool NeedThis = false;
400 public bool HostsParameters = false;
402 // For tracking the number of scopes created.
407 ArrayList locals = new ArrayList ();
408 ArrayList children = new ArrayList ();
411 // The types and fields generated
413 public TypeBuilder ScopeTypeBuilder;
414 public ConstructorBuilder ScopeConstructor;
415 public FieldBuilder THIS;
416 public FieldBuilder ParentLink;
419 // Points to the object of type `ScopeTypeBuilder' that
420 // holds the data for the scope
422 public LocalBuilder ScopeInstance;
425 public ScopeInfo (CaptureContext cc, Block b)
434 public void AddLocal (LocalInfo li)
436 if (locals.Contains (li))
442 public bool IsCaptured (LocalInfo li)
444 return locals.Contains (li);
447 internal void AddChild (ScopeInfo si)
449 if (children.Contains (si))
453 // If any of the current children should be a children of `si', move them there
455 ArrayList move_queue = null;
456 foreach (ScopeInfo child in children){
457 if (child.ScopeBlock.IsChildOf (si.ScopeBlock)){
458 if (move_queue == null)
459 move_queue = new ArrayList ();
460 move_queue.Add (child);
461 child.ParentScope = si;
468 if (move_queue != null){
469 foreach (ScopeInfo child in move_queue){
470 children.Remove (child);
475 static int indent = 0;
479 for (int i = 0; i < indent; i++)
485 //Console.WriteLine (Environment.StackTrace);
487 Console.WriteLine ("START");
490 Console.WriteLine ("NeedThis=" + NeedThis);
491 foreach (LocalInfo li in locals){
493 Console.WriteLine ("var {0}", li.Name);
496 foreach (ScopeInfo si in children)
500 Console.WriteLine ("END");
503 public string MakeHelperName ()
505 return String.Format ("<>AnonHelp<{0}>", id);
508 public void EmitScopeConstructor ()
510 Type [] constructor_types = TypeManager.NoTypes;
511 Parameters constructor_parameters = Parameters.EmptyReadOnlyParameters;
512 ScopeConstructor = ScopeTypeBuilder.DefineConstructor (
513 MethodAttributes.Public | MethodAttributes.HideBySig |
514 MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
515 CallingConventions.HasThis, constructor_types);
516 InternalParameters parameter_info = new InternalParameters (constructor_types, constructor_parameters);
517 TypeManager.RegisterMethod (ScopeConstructor, parameter_info, constructor_types);
519 ILGenerator cig = ScopeConstructor.GetILGenerator ();
520 cig.Emit (OpCodes.Ldarg_0);
521 cig.Emit (OpCodes.Call, TypeManager.object_ctor);
522 cig.Emit (OpCodes.Ret);
525 public void EmitScopeType (EmitContext ec)
529 if (ScopeTypeBuilder != null)
532 TypeBuilder container = ec.TypeContainer.TypeBuilder;
534 ScopeTypeBuilder = container.DefineNestedType (
535 MakeHelperName (), TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.NestedAssembly,
536 TypeManager.object_type, null);
539 THIS = ScopeTypeBuilder.DefineField ("<>THIS", container, FieldAttributes.Assembly);
541 if (ParentScope != null){
542 if (ParentScope.ScopeTypeBuilder == null){
543 throw new Exception (String.Format ("My parent has not been initialized {0} and {1}", ParentScope, this));
546 ParentLink = ScopeTypeBuilder.DefineField ("<>parent", ParentScope.ScopeTypeBuilder,
547 FieldAttributes.Assembly);
550 if (NeedThis && ParentScope != null)
551 throw new Exception ("I was not expecting THIS && having a parent");
553 foreach (LocalInfo info in locals){
554 info.FieldBuilder = ScopeTypeBuilder.DefineField (
555 info.Name, info.VariableType, FieldAttributes.Assembly);
558 if (HostsParameters){
559 Hashtable captured_parameters = CaptureContext.captured_parameters;
561 foreach (DictionaryEntry de in captured_parameters){
562 string name = (string) de.Key;
563 CapturedParameter cp = (CapturedParameter) de.Value;
566 fb = ScopeTypeBuilder.DefineField ("<p:" + name + ">", cp.Type, FieldAttributes.Assembly);
567 cp.FieldBuilder = fb;
571 EmitScopeConstructor ();
572 foreach (ScopeInfo si in children){
573 si.EmitScopeType (ec);
577 public void CloseTypes ()
579 RootContext.RegisterCompilerGeneratedType (ScopeTypeBuilder);
580 foreach (ScopeInfo si in children)
585 // Emits the initialization code for the scope
587 public void EmitInitScope (EmitContext ec)
589 ILGenerator ig = ec.ig;
594 if (ScopeConstructor == null)
595 throw new Exception ("ScopeConstructor is null for" + this.ToString ());
597 ig.Emit (OpCodes.Newobj, (ConstructorInfo) ScopeConstructor);
598 ScopeInstance = ig.DeclareLocal (ScopeTypeBuilder);
599 ig.Emit (OpCodes.Stloc, ScopeInstance);
602 ig.Emit (OpCodes.Ldloc, ScopeInstance);
603 ig.Emit (OpCodes.Ldarg_0);
604 ig.Emit (OpCodes.Stfld, THIS);
608 // Copy the parameter values, if any
610 int extra = ec.IsStatic ? 0 : 1;
611 if (HostsParameters){
612 Hashtable captured_parameters = CaptureContext.captured_parameters;
614 foreach (DictionaryEntry de in captured_parameters){
615 CapturedParameter cp = (CapturedParameter) de.Value;
617 ig.Emit (OpCodes.Ldloc, ScopeInstance);
618 ParameterReference.EmitLdArg (ig, cp.Idx + extra);
619 ig.Emit (OpCodes.Stfld, cp.FieldBuilder);
623 if (ParentScope != null){
624 if (!ParentScope.inited)
625 ParentScope.EmitInitScope (ec);
628 // Only emit initialization in our capturecontext world
630 if (ParentScope.CaptureContext == CaptureContext){
631 ig.Emit (OpCodes.Ldloc, ScopeInstance);
632 ig.Emit (OpCodes.Ldloc, ParentScope.ScopeInstance);
633 ig.Emit (OpCodes.Stfld, ParentLink);
635 ig.Emit (OpCodes.Ldloc, ScopeInstance);
636 ig.Emit (OpCodes.Ldarg_0);
637 ig.Emit (OpCodes.Stfld, ParentLink);
643 static void DoPath (StringBuilder sb, ScopeInfo start)
645 if (start.ParentScope != null){
646 DoPath (sb, start.ParentScope);
649 sb.Append ((start.id).ToString ());
652 public override string ToString ()
654 StringBuilder sb = new StringBuilder ();
657 if (CaptureContext != null){
658 sb.Append (CaptureContext.ToString ());
665 return sb.ToString ();
670 // CaptureContext objects are created on demand if a method has
671 // anonymous methods and kept on the ToplevelBlock.
673 // If they exist, all ToplevelBlocks in the containing block are
674 // linked together (children pointing to their parents).
676 public class CaptureContext {
677 public static int count;
682 // Points to the toplevel block that owns this CaptureContext
684 ToplevelBlock toplevel_owner;
685 Hashtable scopes = new Hashtable ();
686 bool have_captured_vars = false;
687 bool referenced_this = false;
688 ScopeInfo topmost = null;
693 Hashtable captured_fields = new Hashtable ();
694 Hashtable captured_variables = new Hashtable ();
695 public Hashtable captured_parameters = new Hashtable ();
696 public AnonymousMethod Host;
698 public CaptureContext (ToplevelBlock toplevel_owner, Location loc, AnonymousMethod host)
701 this.toplevel_owner = toplevel_owner;
708 void DoPath (StringBuilder sb, CaptureContext cc)
710 if (cc.ParentCaptureContext != null){
711 DoPath (sb, cc.ParentCaptureContext);
714 sb.Append (cc_id.ToString ());
717 public override string ToString ()
719 StringBuilder sb = new StringBuilder ();
723 return sb.ToString ();
726 public ToplevelBlock ParentToplevel {
728 return toplevel_owner.Container;
732 public CaptureContext ParentCaptureContext {
734 ToplevelBlock parent = ParentToplevel;
736 return (parent == null) ? null : parent.CaptureContext;
740 // Returns the deepest of two scopes
741 public ScopeInfo Deepest (ScopeInfo a, ScopeInfo b)
753 // If they Scopes are on the same CaptureContext, we do the double
754 // checks just so if there is an invariant change in the future,
755 // we get the exception at the end
757 for (p = a; p != null; p = p.ParentScope)
761 for (p = b; p != null; p = p.ParentScope)
765 CaptureContext ca = a.CaptureContext;
766 CaptureContext cb = b.CaptureContext;
768 for (CaptureContext c = ca; c != null; c = c.ParentCaptureContext)
772 for (CaptureContext c = cb; c != null; c = c.ParentCaptureContext)
775 throw new Exception ("Should never be reached");
778 void AdjustMethodScope (AnonymousMethod am, ScopeInfo scope)
780 am.Scope = Deepest (am.Scope, scope);
783 void LinkScope (ScopeInfo scope, int id)
785 ScopeInfo parent = (ScopeInfo) scopes [id];
786 scope.ParentScope = parent;
787 parent.AddChild (scope);
789 if (scope == topmost)
793 public void AddLocal (AnonymousMethod am, LocalInfo li)
795 if (li.Block.Toplevel != toplevel_owner){
796 ParentCaptureContext.AddLocal (am, li);
799 int block_id = li.Block.ID;
801 if (scopes [block_id] == null){
802 scope = new ScopeInfo (this, li.Block);
803 scopes [block_id] = scope;
805 scope = (ScopeInfo) scopes [block_id];
807 if (topmost == null){
812 for (Block b = scope.ScopeBlock.Parent; b != null; b = b.Parent){
813 if (scopes [b.ID] != null){
814 LinkScope (scope, b.ID);
819 if (scope.ParentScope == null && ParentCaptureContext != null){
820 CaptureContext pcc = ParentCaptureContext;
822 for (Block b = am.ContainingBlock; b != null; b = b.Parent){
823 if (pcc.scopes [b.ID] != null){
824 pcc.LinkScope (scope, b.ID);
835 AdjustMethodScope (Host, topmost);
840 AdjustMethodScope (am, scope);
842 if (captured_variables [li] != null)
845 have_captured_vars = true;
846 captured_variables [li] = li;
851 // Retursn the CaptureContext for the block that defines the parameter `name'
853 static CaptureContext _ContextForParameter (ToplevelBlock current, string name)
855 ToplevelBlock container = current.Container;
856 if (container != null){
857 CaptureContext cc = _ContextForParameter (container, name);
861 if (current.IsParameterReference (name))
862 return current.ToplevelBlockCaptureContext;
866 static CaptureContext ContextForParameter (ToplevelBlock current, string name)
868 CaptureContext cc = _ContextForParameter (current, name);
870 throw new Exception (String.Format ("request for parameteter {0} failed: not found", name));
875 // Records the captured parameter at the appropriate CaptureContext
877 public void AddParameter (EmitContext ec, AnonymousMethod am, string name, Type t, int idx)
879 CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
881 cc.AddParameterToContext (am, name, t, idx);
885 // Records the parameters in the context
887 void AddParameterToContext (AnonymousMethod am, string name, Type t, int idx)
889 if (captured_parameters == null)
890 captured_parameters = new Hashtable ();
891 if (captured_parameters [name] != null)
893 captured_parameters [name] = new CapturedParameter (t, idx);
895 if (topmost == null){
897 // Create one ScopeInfo, if there are none.
899 topmost = new ScopeInfo (this, toplevel_owner);
900 scopes [toplevel_owner.ID] = topmost;
903 // If the topmost ScopeInfo is not at the topblock level, insert
904 // a new ScopeInfo there.
906 // FIXME: This code probably should be evolved to be like the code
909 if (topmost.ScopeBlock != toplevel_owner){
910 ScopeInfo par_si = new ScopeInfo (this, toplevel_owner);
911 ScopeInfo old_top = topmost;
912 scopes [toplevel_owner.ID] = topmost;
913 topmost.ParentScope = par_si;
915 topmost.AddChild (old_top);
919 topmost.HostsParameters = true;
920 AdjustMethodScope (am, topmost);
924 // Captured fields are only recorded on the topmost CaptureContext, because that
925 // one is the one linked to the owner of instance fields
927 public void AddField (FieldExpr fe)
929 if (fe.FieldInfo.IsStatic)
930 throw new Exception ("Attempt to register a static field as a captured field");
932 CaptureContext parent = ParentCaptureContext;
934 parent.AddField (fe);
936 captured_fields [fe] = fe;
939 public void CaptureThis ()
941 CaptureContext parent = ParentCaptureContext;
943 parent.CaptureThis ();
944 referenced_this = true;
947 public bool HaveCapturedVariables {
949 return have_captured_vars;
953 public bool HaveCapturedFields {
955 CaptureContext parent = ParentCaptureContext;
957 return parent.HaveCapturedFields;
958 return captured_fields.Count > 0;
962 public bool IsCaptured (LocalInfo local)
964 foreach (ScopeInfo si in scopes.Values){
965 if (si.IsCaptured (local))
972 // Returns whether the parameter is captured
974 public bool IsParameterCaptured (string name)
976 if (ParentCaptureContext != null && ParentCaptureContext.IsParameterCaptured (name))
979 if (captured_parameters != null)
980 return captured_parameters [name] != null;
984 public void EmitAnonymousHelperClasses (EmitContext ec)
986 if (topmost != null){
987 topmost.NeedThis = HaveCapturedFields || referenced_this;
988 topmost.EmitScopeType (ec);
992 public void CloseAnonymousHelperClasses ()
995 topmost.CloseTypes ();
998 ScopeInfo GetScopeFromBlock (EmitContext ec, Block b)
1002 si = (ScopeInfo) scopes [b.ID];
1004 throw new Exception ("Si is null for block " + b.ID);
1005 si.EmitInitScope (ec);
1011 // Emits the opcodes necessary to load the instance of the captured
1014 public void EmitCapturedVariableInstance (EmitContext ec, LocalInfo li, AnonymousMethod am)
1016 ILGenerator ig = ec.ig;
1019 if (li.Block.Toplevel == toplevel_owner){
1020 si = GetScopeFromBlock (ec, li.Block);
1021 ig.Emit (OpCodes.Ldloc, si.ScopeInstance);
1026 ig.Emit (OpCodes.Ldarg_0);
1028 while (si.ScopeBlock.ID != li.Block.ID){
1029 if (si.ParentLink != null)
1030 ig.Emit (OpCodes.Ldfld, si.ParentLink);
1031 si = si.ParentScope;
1034 Console.WriteLine ("Target: {0} {1}", li.Block.ID, li.Name);
1035 while (si.ScopeBlock.ID != li.Block.ID){
1036 Console.WriteLine ("Trying: {0}", si.ScopeBlock.ID);
1037 si = si.ParentScope;
1040 throw new Exception (
1041 String.Format ("Never found block {0} starting at {1} while looking up {2}",
1042 li.Block.ID, am.Scope.ScopeBlock.ID, li.Name));
1049 // Internal routine that loads the instance to reach parameter `name'
1051 void EmitParameterInstance (EmitContext ec, string name)
1053 CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
1055 cc.EmitParameterInstance (ec, name);
1059 CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
1060 if (par_info != null){
1062 // FIXME: implementing this.
1065 ILGenerator ig = ec.ig;
1069 if (ec.CurrentBlock.Toplevel == toplevel_owner){
1070 si = GetScopeFromBlock (ec, toplevel_owner);
1071 ig.Emit (OpCodes.Ldloc, si.ScopeInstance);
1075 si = ec.CurrentAnonymousMethod.Scope;
1076 ig.Emit (OpCodes.Ldarg_0);
1078 while (si.ParentLink != null) {
1079 ig.Emit (OpCodes.Ldfld, si.ParentLink);
1080 si = si.ParentScope;
1086 // Emits the code necessary to load the parameter named `name' within
1087 // an anonymous method.
1089 public void EmitParameter (EmitContext ec, string name)
1091 CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
1093 cc.EmitParameter (ec, name);
1096 EmitParameterInstance (ec, name);
1097 CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
1098 if (par_info != null){
1100 // FIXME: implementing this.
1103 ec.ig.Emit (OpCodes.Ldfld, par_info.FieldBuilder);
1107 // Implements the assignment of `source' to the paramenter named `name' within
1108 // an anonymous method.
1110 public void EmitAssignParameter (EmitContext ec, string name, Expression source, bool leave_copy, bool prepare_for_load)
1112 CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
1114 cc.EmitAssignParameter (ec, name, source, leave_copy, prepare_for_load);
1117 ILGenerator ig = ec.ig;
1118 CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
1120 EmitParameterInstance (ec, name);
1123 ig.Emit (OpCodes.Dup);
1124 ig.Emit (OpCodes.Stfld, par_info.FieldBuilder);
1128 // Emits the address for the parameter named `name' within
1129 // an anonymous method.
1131 public void EmitAddressOfParameter (EmitContext ec, string name)
1133 CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name);
1135 cc.EmitAddressOfParameter (ec, name);
1138 EmitParameterInstance (ec, name);
1139 CapturedParameter par_info = (CapturedParameter) captured_parameters [name];
1140 ec.ig.Emit (OpCodes.Ldflda, par_info.FieldBuilder);
1144 // The following methods are only invoked on the host for the
1145 // anonymous method.
1147 public void EmitMethodHostInstance (EmitContext target, AnonymousMethod am)
1149 ILGenerator ig = target.ig;
1150 ScopeInfo si = am.Scope;
1153 ig.Emit (OpCodes.Ldarg_0);
1157 si.EmitInitScope (target);
1158 ig.Emit (OpCodes.Ldloc, si.ScopeInstance);
1161 ArrayList all_scopes = new ArrayList ();
1163 public void AddScope (ScopeInfo si)
1165 all_scopes.Add (si);
1166 toplevel_owner.RegisterCaptureContext (this);
1170 // Links any scopes that were not linked previously
1172 public void AdjustScopes ()
1174 foreach (ScopeInfo scope in all_scopes){
1175 if (scope.ParentScope != null)
1178 for (Block b = scope.ScopeBlock.Parent; b != null; b = b.Parent){
1179 if (scopes [b.ID] != null){
1180 LinkScope (scope, b.ID);
1185 if (scope.ParentScope == null && ParentCaptureContext != null){
1186 CaptureContext pcc = ParentCaptureContext;
1188 for (Block b = Host.ContainingBlock; b != null; b = b.Parent){
1189 if (pcc.scopes [b.ID] != null){
1190 pcc.LinkScope (scope, b.ID);