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 abstract class CompilerGeneratedClass : Class
25 GenericMethod generic_method;
26 static int next_index = 0;
28 private static MemberName MakeProxyName (GenericMethod generic, Location loc)
30 string name = MakeName ("CompilerGenerated");
31 if (generic != null) {
32 TypeArguments args = new TypeArguments (loc);
33 foreach (TypeParameter tparam in generic.CurrentTypeParameters)
34 args.Add (new SimpleName (tparam.Name, loc));
35 return new MemberName (name, args, loc);
37 return new MemberName (name, loc);
40 public static string MakeName (string prefix)
42 return String.Format ("<>c__{0}{1}", prefix, ++next_index);
45 protected CompilerGeneratedClass (TypeContainer parent, GenericMethod generic,
46 int mod, Location loc)
47 : base (parent.NamespaceEntry, parent,
48 MakeProxyName (generic, loc), mod, null)
50 this.generic_method = generic;
52 if (generic != null) {
53 ArrayList list = new ArrayList ();
54 foreach (TypeParameter tparam in generic.TypeParameters) {
55 if (tparam.Constraints != null)
56 list.Add (tparam.Constraints.Clone ());
58 SetParameterInfo (list);
61 parent.AddCompilerGeneratedClass (this);
64 protected override bool DefineNestedTypes ()
66 RootContext.RegisterCompilerGeneratedType (TypeBuilder);
67 return base.DefineNestedTypes ();
70 protected override bool DoDefineMembers ()
72 members_defined = true;
74 if (!base.DoDefineMembers ())
77 if (CompilerGenerated != null) {
78 foreach (CompilerGeneratedClass c in CompilerGenerated) {
79 if (!c.DefineMembers ())
80 throw new InternalErrorException ();
87 protected override bool DoResolveMembers ()
89 if (CompilerGenerated != null) {
90 foreach (CompilerGeneratedClass c in CompilerGenerated) {
91 if (!c.ResolveMembers ())
96 return base.DoResolveMembers ();
99 public GenericMethod GenericMethod {
100 get { return generic_method; }
103 public TypeExpr InflateType (Type it)
106 if (generic_method == null)
107 return new TypeExpression (it, Location);
109 if (it.IsGenericParameter && (it.DeclaringMethod != null)) {
110 int pos = it.GenericParameterPosition;
111 it = CurrentTypeParameters [pos].Type;
112 } else if (it.IsGenericType) {
113 Type[] args = it.GetGenericArguments ();
115 TypeArguments inflated = new TypeArguments (Location);
116 foreach (Type t in args)
117 inflated.Add (InflateType (t));
119 return new ConstructedType (it, inflated, Location);
120 } else if (it.IsArray) {
121 TypeExpr et_expr = InflateType (it.GetElementType ());
122 int rank = it.GetArrayRank ();
124 Type et = et_expr.ResolveAsTypeTerminal (this, false).Type;
125 it = et.MakeArrayType (rank);
129 return new TypeExpression (it, Location);
132 public Field CaptureVariable (string name, TypeExpr type)
135 throw new InternalErrorException ("Helper class already defined!");
137 throw new ArgumentNullException ();
139 return new CapturedVariableField (this, name, type);
142 bool members_defined;
144 internal void CheckMembersDefined ()
147 throw new InternalErrorException ("Helper class already defined!");
150 protected class CapturedVariableField : Field
152 public CapturedVariableField (CompilerGeneratedClass helper, string name,
154 : base (helper, type, Modifiers.INTERNAL, name, null, helper.Location)
156 helper.AddField (this);
161 public class ScopeInfo : CompilerGeneratedClass
163 protected readonly RootScopeInfo RootScope;
164 new public readonly TypeContainer Parent;
165 public readonly int ID = ++next_id;
166 public Block ScopeBlock;
170 public static ScopeInfo CreateScope (Block block)
172 ToplevelBlock toplevel = block.Toplevel;
173 AnonymousContainer ac = toplevel.AnonymousContainer;
175 Report.Debug (128, "CREATE SCOPE", block, block.ScopeInfo, toplevel, ac);
178 return new ScopeInfo (block, toplevel.RootScope.Parent,
179 toplevel.RootScope.GenericMethod);
181 Report.Debug (128, "CREATE SCOPE #1", ac, ac.Host, ac.Scope, ac.Block,
182 ac.Container, ac.ContainerAnonymousMethod,
186 ScopeInfo parent = null;
188 for (b = ac.Block; b != null; b = b.Parent) {
189 if (b.ScopeInfo != null) {
190 parent = b.ScopeInfo;
195 Report.Debug (128, "CREATE SCOPE #2", parent);
197 ScopeInfo new_scope = new ScopeInfo (block, parent, null);
199 Report.Debug (128, "CREATE SCOPE #3", new_scope);
204 protected ScopeInfo (Block block, TypeContainer parent, GenericMethod generic)
205 : base (parent, generic, 0, block.StartLocation)
208 RootScope = block.Toplevel.RootScope;
211 Report.Debug (128, "NEW SCOPE", this, block,
212 block.Parent, block.Toplevel);
214 RootScope.AddScope (this);
217 protected ScopeInfo (ToplevelBlock toplevel, TypeContainer parent,
218 GenericMethod generic, Location loc)
219 : base (parent, generic, 0, loc)
222 RootScope = (RootScopeInfo) this;
223 ScopeBlock = toplevel;
225 Report.Debug (128, "NEW ROOT SCOPE", this, toplevel, loc);
228 protected ScopeInitializer scope_initializer;
230 Hashtable locals = new Hashtable ();
231 Hashtable captured_scopes = new Hashtable ();
232 Hashtable captured_params;
234 protected CapturedScope[] CapturedScopes {
236 CapturedScope[] list = new CapturedScope [captured_scopes.Count];
237 captured_scopes.Values.CopyTo (list, 0);
242 protected CapturedVariable GetCapturedScope (ScopeInfo scope)
244 return (CapturedVariable) captured_scopes [scope];
247 public void EmitScopeInstance (EmitContext ec)
249 if (scope_initializer == null) {
251 // This is needed if someone overwrites the Emit method
252 // of Statement and manually calls Block.Emit without
253 // this snippet first:
255 // ec.EmitScopeInitFromBlock (The_Block);
256 // The_Block.Emit (ec);
258 throw new InternalErrorException ();
261 scope_initializer.Emit (ec);
264 public ExpressionStatement GetScopeInitializer (EmitContext ec)
266 Report.Debug (128, "GET SCOPE INITIALIZER",
267 this, GetType (), scope_initializer, ScopeBlock);
269 if (scope_initializer == null) {
270 scope_initializer = CreateScopeInitializer ();
271 if (scope_initializer.Resolve (ec) == null)
272 throw new InternalErrorException ();
275 return scope_initializer;
278 public Type GetScopeType (EmitContext ec)
283 TypeArguments targs = new TypeArguments (Location);
285 if (ec.DeclContainer.Parent.IsGeneric)
286 foreach (TypeParameter t in ec.DeclContainer.Parent.TypeParameters)
287 targs.Add (new TypeParameterExpr (t, Location));
288 if (ec.DeclContainer.IsGeneric)
289 foreach (TypeParameter t in ec.DeclContainer.CurrentTypeParameters)
290 targs.Add (new TypeParameterExpr (t, Location));
292 Report.Debug (128, "GET SCOPE TYPE", this, TypeBuilder, targs,
293 ec.DeclContainer, ec.DeclContainer.GetType (),
294 ec.DeclContainer.Parent.Name);
296 TypeExpr te = new ConstructedType (TypeBuilder, targs, Location);
297 te = te.ResolveAsTypeTerminal (ec, false);
298 if ((te == null) || (te.Type == null))
303 protected override bool DoDefineMembers ()
305 Report.Debug (64, "SCOPE INFO DEFINE MEMBERS", this, GetType (), IsGeneric,
306 Parent.IsGeneric, GenericMethod);
308 foreach (CapturedScope child in CapturedScopes) {
309 if (!child.DefineMembers ())
313 return base.DoDefineMembers ();
316 protected override bool DoResolveMembers ()
318 Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
319 Parent.IsGeneric, GenericMethod);
321 return base.DoResolveMembers ();
324 public Variable CaptureScope (ScopeInfo child)
326 CheckMembersDefined ();
327 Report.Debug (128, "CAPTURE SCOPE", this, GetType (), child, child.GetType ());
329 throw new InternalErrorException ();
330 CapturedScope captured = (CapturedScope) captured_scopes [child];
331 if (captured == null) {
332 captured = new CapturedScope (this, child);
333 captured_scopes.Add (child, captured);
338 public Variable AddLocal (LocalInfo local)
340 Report.Debug (128, "CAPTURE LOCAL", this, local);
341 Variable var = (Variable) locals [local];
343 var = new CapturedLocal (this, local);
344 locals.Add (local, var);
345 local.IsCaptured = true;
350 public Variable GetCapturedVariable (LocalInfo local)
352 return (Variable) locals [local];
355 public bool HostsParameters {
356 get { return captured_params != null; }
359 public Variable GetCapturedParameter (Parameter par)
361 if (captured_params != null)
362 return (Variable) captured_params [par];
367 public bool IsParameterCaptured (string name)
369 if (captured_params != null)
370 return captured_params [name] != null;
374 public Variable AddParameter (Parameter par, int idx)
376 if (captured_params == null)
377 captured_params = new Hashtable ();
379 Variable var = (Variable) captured_params [par];
381 var = new CapturedParameter (this, par, idx);
382 captured_params.Add (par, var);
383 par.IsCaptured = true;
389 protected string MakeFieldName (string local_name)
391 return "<" + ID + ":" + local_name + ">";
394 protected virtual ScopeInitializer CreateScopeInitializer ()
396 return new ScopeInitializer (this);
399 protected abstract class CapturedVariable : Variable
401 public readonly ScopeInfo Scope;
402 public readonly string Name;
404 public FieldExpr FieldInstance;
405 protected Field field;
407 protected CapturedVariable (ScopeInfo scope, string name)
413 protected CapturedVariable (ScopeInfo scope, string name, Type type)
416 this.field = scope.CaptureVariable (
417 scope.MakeFieldName (name), scope.RootScope.InflateType (type));
421 get { return field; }
424 public override Type Type {
425 get { return Field.MemberType; }
428 public override bool HasInstance {
432 public override bool NeedsTemporary {
436 protected FieldInfo GetField (EmitContext ec)
438 if ((ec.CurrentBlock != null) &&
439 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel))
440 return Field.FieldBuilder;
442 return FieldInstance.FieldInfo;
445 public override void EmitInstance (EmitContext ec)
447 Scope.EmitScopeInstance (ec);
450 public override void Emit (EmitContext ec)
452 ec.ig.Emit (OpCodes.Ldfld, GetField (ec));
455 public override void EmitAssign (EmitContext ec)
457 ec.ig.Emit (OpCodes.Stfld, GetField (ec));
460 public override void EmitAddressOf (EmitContext ec)
462 ec.ig.Emit (OpCodes.Ldflda, GetField (ec));
466 protected class CapturedParameter : CapturedVariable {
467 public readonly Parameter Parameter;
468 public readonly int Idx;
470 public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
471 : base (scope, par.Name, par.ParameterType)
473 this.Parameter = par;
477 public override string ToString ()
479 return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
480 Parameter.Name, Idx);
484 protected class CapturedLocal : CapturedVariable {
485 public readonly LocalInfo Local;
487 public CapturedLocal (ScopeInfo scope, LocalInfo local)
488 : base (scope, local.Name, local.VariableType)
493 public override string ToString ()
495 return String.Format ("{0} ({1}:{2})", GetType (), Field,
500 protected class CapturedThis : CapturedVariable {
501 public CapturedThis (RootScopeInfo host)
502 : base (host, "<>THIS", host.ParentType)
506 protected class CapturedScope : CapturedVariable {
507 public readonly ScopeInfo ChildScope;
509 public CapturedScope (ScopeInfo root, ScopeInfo child)
510 : base (root, "scope" + child.ID)
512 this.ChildScope = child;
515 public bool DefineMembers ()
517 Type type = ChildScope.IsGeneric ?
518 ChildScope.CurrentType : ChildScope.TypeBuilder;
519 Report.Debug (128, "CAPTURED SCOPE DEFINE MEMBERS", this, Scope,
520 ChildScope, Name, type);
522 throw new InternalErrorException ();
523 field = Scope.CaptureVariable (
524 Scope.MakeFieldName (Name), Scope.InflateType (type));
528 public override string ToString ()
530 return String.Format ("CapturedScope ({1} captured in {0})",
535 static void DoPath (StringBuilder sb, ScopeInfo start)
537 sb.Append ((start.ID).ToString ());
540 public override string ToString ()
542 StringBuilder sb = new StringBuilder ();
548 return sb.ToString ();
551 protected class ScopeInitializer : ExpressionStatement
554 CapturedVariable captured_scope;
555 LocalBuilder scope_instance;
556 ConstructorInfo scope_ctor;
560 public ScopeInitializer (ScopeInfo scope)
563 this.loc = scope.Location;
564 eclass = ExprClass.Value;
567 public ScopeInfo Scope {
568 get { return scope; }
571 public override Expression DoResolve (EmitContext ec)
573 if (scope_ctor != null)
576 Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
577 ec, ec.CurrentBlock);
579 type = Scope.GetScopeType (ec);
581 throw new InternalErrorException ();
583 if (!DoResolveInternal (ec))
584 throw new InternalErrorException ();
589 protected virtual bool DoResolveInternal (EmitContext ec)
591 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookupFinal (
592 ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
593 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
595 throw new InternalErrorException ();
597 scope_ctor = (ConstructorInfo) mg.Methods [0];
599 Report.Debug (128, "RESOLVE THE INIT", this, Scope, Scope.RootScope,
600 Scope.RootScope.GetType ());
602 ScopeInfo host = Scope.RootScope;
603 if ((Scope != host) && (Scope.RootScope is IteratorHost)) {
604 captured_scope = host.GetCapturedScope (Scope);
605 Type root = host.GetScopeType (ec);
606 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
607 type, root, captured_scope.Field.Name, loc);
609 throw new InternalErrorException ();
611 fe.InstanceExpression = this;
612 captured_scope.FieldInstance = fe;
614 Report.Debug (128, "RESOLVE THE INIT #1", this,
617 scope_instance = ec.ig.DeclareLocal (type);
619 foreach (CapturedLocal local in Scope.locals.Values) {
620 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
621 ec.ContainerType, type, local.Field.Name, loc);
622 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
623 Scope, ec, ec.ContainerType, type,
624 local.Field, local.Field.Name, loc, fe);
626 throw new InternalErrorException ();
628 fe.InstanceExpression = this;
629 local.FieldInstance = fe;
632 if (Scope.HostsParameters) {
633 foreach (CapturedParameter cp in Scope.captured_params.Values) {
634 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
635 ec.ContainerType, type, cp.Field.Name, loc);
637 throw new InternalErrorException ();
639 fe.InstanceExpression = this;
640 cp.FieldInstance = fe;
644 foreach (CapturedScope scope in Scope.CapturedScopes) {
645 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
646 ec.ContainerType, type, scope.Field.Name, loc);
647 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #3", this, Scope,
648 scope, ec, ec.ContainerType, type,
649 scope.Field, scope.Field.Name, loc, fe);
651 throw new InternalErrorException ();
653 fe.InstanceExpression = this;
654 scope.FieldInstance = fe;
660 protected virtual void EmitParameterReference (EmitContext ec,
661 CapturedParameter cp)
663 int extra = ec.MethodIsStatic ? 0 : 1;
664 ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
670 protected virtual void DoEmit (EmitContext ec)
672 if ((ec.CurrentBlock != null) &&
673 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)) {
674 ec.ig.Emit (OpCodes.Ldarg_0);
676 if (ec.CurrentAnonymousMethod != null) {
677 ScopeInfo host = ec.CurrentAnonymousMethod.Scope;
678 Variable captured = host.GetCapturedScope (scope);
679 Report.Debug (128, "EMIT SCOPE INSTANCE #2",
680 ec.CurrentAnonymousMethod, host,
682 if (captured != null)
685 } else if (scope_instance != null)
686 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
688 Report.Debug (128, "DO EMIT", this, Scope, ec,
689 scope_instance, captured_scope);
690 captured_scope.EmitInstance (ec);
691 captured_scope.Emit (ec);
695 protected void DoEmitInstance (EmitContext ec)
697 Report.Debug (128, "DO EMIT INSTANCE", this, Scope, ec,
698 scope_instance, captured_scope);
700 if (scope_instance != null)
701 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
703 captured_scope.EmitInstance (ec);
706 protected virtual void EmitScopeConstructor (EmitContext ec)
708 ec.ig.Emit (OpCodes.Newobj, scope_ctor);
711 public override void Emit (EmitContext ec)
714 throw new InternalErrorException (
715 "Scope {0} not initialized yet", scope);
720 public override void EmitStatement (EmitContext ec)
725 DoEmitStatement (ec);
729 protected virtual void DoEmitStatement (EmitContext ec)
731 Report.Debug (128, "EMIT SCOPE INITIALIZER STATEMENT", this, id,
732 Scope, scope_instance, ec);
734 ec.ig.Emit (OpCodes.Nop);
735 ec.ig.Emit (OpCodes.Ldc_I4, id);
736 ec.ig.Emit (OpCodes.Pop);
737 ec.ig.Emit (OpCodes.Nop);
739 if (scope_instance == null)
740 ec.ig.Emit (OpCodes.Ldarg_0);
741 EmitScopeConstructor (ec);
742 if (scope_instance != null)
743 ec.ig.Emit (OpCodes.Stloc, scope_instance);
745 captured_scope.EmitAssign (ec);
747 if (Scope.HostsParameters) {
748 foreach (CapturedParameter cp in Scope.captured_params.Values) {
749 Report.Debug (128, "EMIT SCOPE INIT #6", this,
750 ec, ec.IsStatic, Scope, cp, cp.Field.Name);
752 EmitParameterReference (ec, cp);
753 ec.ig.Emit (OpCodes.Stfld, cp.FieldInstance.FieldInfo);
757 if (Scope is IteratorHost)
760 foreach (CapturedScope scope in Scope.CapturedScopes) {
761 ScopeInfo child = scope.ChildScope;
763 Report.Debug (128, "EMIT SCOPE INIT #5", this, Scope,
764 scope.Scope, scope.ChildScope);
766 ExpressionStatement init = child.GetScopeInitializer (ec);
767 init.EmitStatement (ec);
770 scope.ChildScope.EmitScopeInstance (ec);
771 scope.EmitAssign (ec);
777 public class RootScopeInfo : ScopeInfo
779 public RootScopeInfo (ToplevelBlock toplevel, TypeContainer parent,
780 GenericMethod generic, Location loc)
781 : base (toplevel, parent, generic, loc)
783 scopes = new ArrayList ();
786 TypeExpr parent_type;
787 CapturedVariableField parent_link;
788 CapturedThis this_variable;
789 protected ArrayList scopes;
791 public virtual bool IsIterator {
792 get { return false; }
795 public RootScopeInfo ParentHost {
796 get { return Parent as RootScopeInfo; }
799 public Type ParentType {
800 get { return parent_type.Type; }
803 public Field ParentLink {
804 get { return parent_link; }
807 protected CapturedThis THIS {
808 get { return this_variable; }
811 public Variable CaptureThis ()
813 if (ParentHost != null)
814 return ParentHost.CaptureThis ();
816 CheckMembersDefined ();
817 if (this_variable == null)
818 this_variable = new CapturedThis (this);
819 return this_variable;
822 public void AddScope (ScopeInfo scope)
828 public void LinkScopes ()
830 Report.Debug (128, "LINK SCOPES", this, linked, scopes);
836 if (ParentHost != null)
837 ParentHost.LinkScopes ();
839 foreach (ScopeInfo si in scopes) {
841 throw new InternalErrorException ();
842 if (si.DefineType () == null)
843 throw new InternalErrorException ();
844 if (!si.ResolveType ())
845 throw new InternalErrorException ();
848 foreach (ScopeInfo si in scopes) {
849 if (!si.ResolveMembers ())
850 throw new InternalErrorException ();
851 if (!si.DefineMembers ())
852 throw new InternalErrorException ();
856 protected override ScopeInitializer CreateScopeInitializer ()
858 return new RootScopeInitializer (this);
861 protected override bool DefineNestedTypes ()
863 if (Parent.IsGeneric) {
864 parent_type = new ConstructedType (
865 Parent.TypeBuilder, Parent.TypeParameters, Location);
866 parent_type = parent_type.ResolveAsTypeTerminal (this, false);
867 if ((parent_type == null) || (parent_type.Type == null))
870 parent_type = new TypeExpression (Parent.TypeBuilder, Location);
873 CompilerGeneratedClass parent = Parent as CompilerGeneratedClass;
875 parent_link = new CapturedVariableField (this, "<>parent", parent_type);
877 return base.DefineNestedTypes ();
880 protected override bool DoDefineMembers ()
882 ArrayList args = new ArrayList ();
883 if (this is IteratorHost)
884 args.Add (new Parameter (
885 TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
889 if (Parent is CompilerGeneratedClass)
890 pfield = parent_link;
892 pfield = this_variable != null ? this_variable.Field : null;
894 args.Add (new Parameter (
895 pfield.MemberType, "parent", Parameter.Modifier.NONE,
898 Parameter[] ctor_params = new Parameter [args.Count];
899 args.CopyTo (ctor_params, 0);
900 Constructor ctor = new Constructor (
901 this, MemberName.Name, Modifiers.PUBLIC,
902 new Parameters (ctor_params),
903 new GeneratedBaseInitializer (Location),
905 AddConstructor (ctor);
907 ctor.Block = new ToplevelBlock (null, Location);
908 ctor.Block.AddStatement (new TheCtor (this));
910 return base.DoDefineMembers ();
913 protected virtual void EmitScopeConstructor (EmitContext ec)
915 int pos = (this is IteratorHost) ? 2 : 1;
918 if (Parent is CompilerGeneratedClass)
919 pfield = parent_link;
921 pfield = this_variable != null ? this_variable.Field : null;
923 if (pfield != null) {
924 ec.ig.Emit (OpCodes.Ldarg_0);
925 ec.ig.Emit (OpCodes.Ldarg, pos);
926 ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
931 protected class TheCtor : Statement
935 public TheCtor (RootScopeInfo host)
940 public override bool Resolve (EmitContext ec)
945 protected override void DoEmit (EmitContext ec)
947 host.EmitScopeConstructor (ec);
951 protected class RootScopeInitializer : ScopeInitializer
955 public RootScopeInitializer (RootScopeInfo host)
961 public RootScopeInfo Host {
965 protected override bool DoResolveInternal (EmitContext ec)
967 Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
968 this, Host, Host.ParentType, loc);
970 if (Host.THIS != null) {
971 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
972 ec.ContainerType, type, Host.THIS.Field.Name, loc);
974 throw new InternalErrorException ();
976 fe.InstanceExpression = this;
977 Host.THIS.FieldInstance = fe;
980 return base.DoResolveInternal (ec);
983 protected virtual bool IsGetEnumerator {
984 get { return false; }
987 protected override void EmitScopeConstructor (EmitContext ec)
989 if (host.THIS != null) {
990 ec.ig.Emit (OpCodes.Ldarg_0);
992 ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
993 else if (host.THIS.Type.IsValueType)
994 Expression.LoadFromPtr (ec.ig, host.THIS.Type);
995 } else if (host.ParentLink != null)
996 ec.ig.Emit (OpCodes.Ldarg_0);
998 base.EmitScopeConstructor (ec);
1004 public interface IAnonymousContainer
1010 GenericMethod GenericMethod {
1014 RootScopeInfo RootScope {
1023 public interface IAnonymousHost
1026 // Invoked if a yield statement is found in the body
1031 // Invoked if an anonymous method is found in the body
1033 void AddAnonymousMethod (AnonymousMethodExpression anonymous);
1036 public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
1038 public readonly AnonymousMethodExpression Parent;
1039 public readonly TypeContainer Host;
1040 public readonly Parameters Parameters;
1042 public ToplevelBlock Block;
1043 protected AnonymousMethod anonymous;
1045 protected readonly Block container;
1046 protected readonly GenericMethod generic;
1048 public Block Container {
1049 get { return container; }
1052 public GenericMethod GenericMethod {
1053 get { return generic; }
1056 public AnonymousMethod AnonymousMethod {
1057 get { return anonymous; }
1060 public RootScopeInfo RootScope {
1061 get { return root_scope; }
1064 public AnonymousMethodExpression (AnonymousMethodExpression parent,
1065 GenericMethod generic, TypeContainer host,
1066 Parameters parameters, Block container,
1069 this.Parent = parent;
1070 this.generic = parent != null ? null : generic;
1072 this.Parameters = parameters;
1073 this.container = container;
1076 Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host,
1080 parent.AddAnonymousMethod (this);
1084 RootScopeInfo root_scope;
1086 static int next_index;
1088 void IAnonymousHost.SetYields ()
1090 throw new InvalidOperationException ();
1093 public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
1095 if (children == null)
1096 children = new ArrayList ();
1097 children.Add (anonymous);
1100 public bool CreateAnonymousHelpers ()
1102 Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
1103 this, Host, container, loc);
1105 if (container != null)
1106 root_scope = container.Toplevel.CreateRootScope (Host);
1108 if (children != null) {
1109 foreach (AnonymousMethodExpression child in children) {
1110 if (!child.CreateAnonymousHelpers ())
1118 public override string ExprClassName {
1120 return "anonymous method";
1124 void Error_ParameterMismatch (Type t)
1126 Report.Error (1661, loc, "Anonymous method could not be converted to delegate `" +
1127 "{0}' since there is a parameter mismatch",
1128 TypeManager.CSharpName (t));
1131 public bool ImplicitStandardConversionExists (Type delegate_type)
1133 if (Parameters == null)
1136 MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1137 Host.TypeBuilder, delegate_type, loc);
1138 MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1139 ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
1141 if (Parameters.Count != invoke_pd.Count)
1144 for (int i = 0; i < Parameters.Count; ++i) {
1145 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i))
1152 // Returns true if this anonymous method can be implicitly
1153 // converted to the delegate type `delegate_type'
1155 public Expression Compatible (EmitContext ec, Type delegate_type)
1157 if (anonymous != null)
1158 return anonymous.AnonymousDelegate;
1160 if (!ec.IsAnonymousMethodAllowed) {
1161 Report.Error (1706, loc,
1162 "Anonymous methods are not allowed in the " +
1163 "attribute declaration");
1167 if (!TypeManager.IsDelegateType (delegate_type)){
1168 Report.Error (1660, loc,
1169 "Cannot convert anonymous method block to type " +
1170 "`{0}' because it is not a delegate type",
1171 TypeManager.CSharpName (delegate_type));
1176 // At this point its the first time we know the return type that is
1177 // needed for the anonymous method. We create the method here.
1180 MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1181 ec.ContainerType, delegate_type, loc);
1182 MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1183 ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
1185 Parameters parameters;
1186 if (Parameters == null) {
1188 // We provide a set of inaccessible parameters
1190 Parameter [] fixedpars = new Parameter [invoke_pd.Count];
1192 for (int i = 0; i < invoke_pd.Count; i++) {
1193 Parameter.Modifier i_mod = invoke_pd.ParameterModifier (i);
1194 if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1195 Report.Error (1688, loc, "Cannot convert anonymous " +
1196 "method block without a parameter list " +
1197 "to delegate type `{0}' because it has " +
1198 "one or more `out' parameters.",
1199 TypeManager.CSharpName (delegate_type));
1202 fixedpars [i] = new Parameter (
1203 invoke_pd.ParameterType (i), "+" + (++next_index),
1204 invoke_pd.ParameterModifier (i), null, loc);
1207 parameters = new Parameters (fixedpars);
1208 if (!parameters.Resolve (ec))
1211 if (Parameters.Count != invoke_pd.Count) {
1212 Report.SymbolRelatedToPreviousError (delegate_type);
1213 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1214 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1215 Error_ParameterMismatch (delegate_type);
1219 for (int i = 0; i < Parameters.Count; ++i) {
1220 Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1221 if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1222 if (p_mod == Parameter.Modifier.NONE)
1223 Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1224 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1226 Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1227 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1228 Error_ParameterMismatch (delegate_type);
1232 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1233 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1235 TypeManager.CSharpName (Parameters.ParameterType (i)),
1236 TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1237 Error_ParameterMismatch (delegate_type);
1242 parameters = Parameters;
1246 // Second: the return type of the delegate must be compatible with
1247 // the anonymous type. Instead of doing a pass to examine the block
1248 // we satisfy the rule by setting the return type on the EmitContext
1249 // to be the delegate type return type.
1252 //MethodBuilder builder = method_data.MethodBuilder;
1253 //ILGenerator ig = builder.GetILGenerator ();
1255 Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1256 Container, Block, invoke_mb.ReturnType, delegate_type,
1257 TypeManager.IsGenericType (delegate_type), loc);
1259 anonymous = new AnonymousMethod (
1260 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
1261 GenericMethod, parameters, Container, Block, invoke_mb.ReturnType,
1262 delegate_type, loc);
1264 if (!anonymous.Resolve (ec))
1267 return anonymous.AnonymousDelegate;
1270 public override Expression DoResolve (EmitContext ec)
1273 // Set class type, set type
1276 eclass = ExprClass.Value;
1279 // This hack means `The type is not accessible
1280 // anywhere', we depend on special conversion
1283 type = TypeManager.anonymous_method_type;
1285 if ((Parameters != null) && !Parameters.Resolve (ec))
1291 public override void Emit (EmitContext ec)
1293 // nothing, as we only exist to not do anything.
1296 public bool IsIterator {
1297 get { return false; }
1301 public abstract class AnonymousContainer : IAnonymousContainer
1303 public readonly Location Location;
1305 // An array list of AnonymousMethodParameter or null
1306 public readonly Parameters Parameters;
1309 // The block that makes up the body for the anonymous mehtod
1311 public readonly ToplevelBlock Block;
1313 public readonly int ModFlags;
1314 public Type ReturnType;
1315 public readonly TypeContainer Host;
1318 // The implicit method we create
1320 protected Method method;
1321 protected EmitContext aec;
1323 // The emit context for the anonymous method
1324 protected bool unreachable;
1325 protected readonly Block container;
1326 protected readonly GenericMethod generic;
1329 // Points to our container anonymous method if its present
1331 public readonly AnonymousContainer ContainerAnonymousMethod;
1333 protected AnonymousContainer (AnonymousContainer parent, TypeContainer host,
1334 GenericMethod generic, Parameters parameters,
1335 Block container, ToplevelBlock block,
1336 Type return_type, int mod, Location loc)
1338 this.ContainerAnonymousMethod = parent;
1339 this.ReturnType = return_type;
1340 this.ModFlags = mod;
1343 this.container = container;
1344 this.generic = parent != null ? null : generic;
1345 this.Parameters = parameters;
1347 this.Location = loc;
1349 block.AnonymousContainer = this;
1352 public Method Method {
1353 get { return method; }
1356 public abstract RootScopeInfo RootScope {
1360 public abstract ScopeInfo Scope {
1364 public abstract string GetSignatureForError ();
1366 public virtual bool Resolve (EmitContext ec)
1368 Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1369 RootScope, Parameters, ec.IsStatic);
1371 if (ReturnType != null) {
1372 TypeExpr return_type_expr;
1373 if (RootScope != null)
1374 return_type_expr = RootScope.InflateType (ReturnType);
1376 return_type_expr = new TypeExpression (ReturnType, Location);
1377 return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
1378 if ((return_type_expr == null) || (return_type_expr.Type == null))
1380 ReturnType = return_type_expr.Type;
1383 aec = new EmitContext (
1384 ec.ResolveContext, ec.TypeContainer,
1385 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1386 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1387 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1389 aec.CurrentAnonymousMethod = this;
1390 aec.IsFieldInitializer = ec.IsFieldInitializer;
1391 aec.IsStatic = ec.IsStatic;
1393 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1394 RootScope, Parameters, Block);
1397 if (!aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable))
1400 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #3", this, ec, aec, Block);
1402 method = DoCreateMethodHost (ec);
1407 if (!method.ResolveMembers ())
1409 return method.Define ();
1412 protected abstract Method DoCreateMethodHost (EmitContext ec);
1414 public Block Container {
1415 get { return container; }
1418 public GenericMethod GenericMethod {
1419 get { return generic; }
1422 public abstract bool IsIterator {
1426 protected class AnonymousMethodMethod : Method
1428 public readonly AnonymousContainer AnonymousMethod;
1429 public readonly ScopeInfo Scope;
1431 public AnonymousMethodMethod (AnonymousContainer am, ScopeInfo scope,
1432 GenericMethod generic, TypeExpr return_type,
1433 int mod, MemberName name, Parameters parameters)
1434 : base (scope != null ? scope : am.Host,
1435 generic, return_type, mod, false, name, parameters, null)
1437 this.AnonymousMethod = am;
1440 if (scope != null) {
1441 scope.CheckMembersDefined ();
1442 scope.AddMethod (this);
1444 ModFlags |= Modifiers.STATIC;
1445 am.Host.AddMethod (this);
1450 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1452 EmitContext aec = AnonymousMethod.aec;
1454 aec.MethodIsStatic = Scope == null;
1460 public class AnonymousMethod : AnonymousContainer
1462 public readonly Type DelegateType;
1465 // The value return by the Compatible call, this ensure that
1466 // the code works even if invoked more than once (Resolve called
1467 // more than once, due to the way Convert.ImplicitConversion works
1469 Expression anonymous_delegate;
1470 RootScopeInfo root_scope;
1473 public AnonymousMethod (AnonymousMethod parent, RootScopeInfo root_scope,
1474 TypeContainer host, GenericMethod generic,
1475 Parameters parameters, Block container,
1476 ToplevelBlock block, Type return_type, Type delegate_type,
1478 : base (parent, host, generic, parameters, container, block,
1479 return_type, 0, loc)
1481 this.DelegateType = delegate_type;
1482 this.root_scope = root_scope;
1485 public override RootScopeInfo RootScope {
1486 get { return root_scope; }
1489 public override ScopeInfo Scope {
1490 get { return scope; }
1493 public override bool IsIterator {
1494 get { return false; }
1497 public Expression AnonymousDelegate {
1498 get { return anonymous_delegate; }
1501 public override string GetSignatureForError ()
1503 return TypeManager.CSharpName (DelegateType);
1507 // Creates the host for the anonymous method
1509 protected override Method DoCreateMethodHost (EmitContext ec)
1511 string name = CompilerGeneratedClass.MakeName ("AnonymousMethod");
1512 MemberName member_name;
1514 Report.Debug (128, "CREATE METHOD HOST #0", RootScope);
1519 Report.Debug (128, "CREATE METHOD HOST #1", this, Block, Block.ScopeInfo,
1520 RootScope, Location);
1522 for (b = Block.Parent; b != null; b = b.Parent) {
1523 Report.Debug (128, "CREATE METHOD HOST #2", this, Block,
1525 if (b.ScopeInfo != null) {
1526 scope = b.ScopeInfo;
1532 scope.CheckMembersDefined ();
1534 ArrayList scopes = new ArrayList ();
1536 for (b = b.Parent; b != null; b = b.Parent) {
1537 if (b.ScopeInfo != null)
1538 scopes.Add (b.ScopeInfo);
1542 Report.Debug (128, "CREATE METHOD HOST #1", this, scope, scopes);
1544 foreach (ScopeInfo si in scopes)
1545 scope.CaptureScope (si);
1547 Report.Debug (128, "CREATE METHOD HOST", this, Block, container,
1548 RootScope, scope, scopes, Location,
1549 ContainerAnonymousMethod);
1551 GenericMethod generic_method = null;
1553 if (TypeManager.IsGenericType (DelegateType)) {
1554 TypeArguments args = new TypeArguments (Location);
1556 Type dt = DelegateType.GetGenericTypeDefinition ();
1558 Type[] tparam = TypeManager.GetTypeArguments (dt);
1559 for (int i = 0; i < tparam.Length; i++)
1560 args.Add (new SimpleName (tparam [i].Name, Location));
1562 member_name = new MemberName (name, args, Location);
1564 Report.Debug (128, "CREATE METHOD HOST #5", this, DelegateType,
1565 TypeManager.GetTypeArguments (DelegateType),
1568 generic_method = new GenericMethod (
1569 Host.NamespaceEntry, scope, member_name,
1570 new TypeExpression (ReturnType, Location), Parameters);
1572 generic_method.SetParameterInfo (null);
1575 member_name = new MemberName (name, Location);
1577 return new AnonymousMethodMethod (
1578 this, scope, generic_method, new TypeExpression (ReturnType, Location),
1579 Modifiers.INTERNAL, member_name, Parameters);
1582 public override bool Resolve (EmitContext ec)
1584 if (!base.Resolve (ec))
1587 anonymous_delegate = new AnonymousDelegate (
1588 this, DelegateType, Location).Resolve (ec);
1589 if (anonymous_delegate == null)
1595 public MethodInfo GetMethodBuilder (EmitContext ec)
1597 MethodInfo builder = method.MethodBuilder;
1598 if ((Scope != null) && Scope.IsGeneric) {
1599 Type scope_type = Scope.GetScopeType (ec);
1600 if (scope_type == null)
1601 throw new InternalErrorException ();
1603 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1604 ec.ContainerType, scope_type, builder.Name, Location);
1607 throw new InternalErrorException ();
1608 builder = (MethodInfo) mg.Methods [0];
1612 if (!DelegateType.IsGenericType)
1615 Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1616 return builder.MakeGenericMethod (targs);
1622 public static void Error_AddressOfCapturedVar (string name, Location loc)
1624 Report.Error (1686, loc,
1625 "Local variable `{0}' or its members cannot have their " +
1626 "address taken and be used inside an anonymous method block",
1632 // This will emit the code for the delegate, as well delegate creation on the host
1634 public class AnonymousDelegate : DelegateCreation {
1637 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1644 public override Expression DoResolve (EmitContext ec)
1646 eclass = ExprClass.Value;
1651 public override void Emit (EmitContext ec)
1653 ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE");
1654 ec.ig.Emit (OpCodes.Pop);
1657 // Now emit the delegate creation.
1659 if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1660 Report.Debug (128, "EMIT ANONYMOUS DELEGATE", this, am, am.Scope, loc);
1661 delegate_instance_expression = am.Scope.GetScopeInitializer (ec);
1663 if (delegate_instance_expression == null)
1664 throw new InternalErrorException ();
1667 Expression ml = Expression.MemberLookup (
1668 ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
1669 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
1672 constructor_method = ((MethodGroupExpr) ml).Methods [0];
1673 delegate_method = am.GetMethodBuilder (ec);
1676 ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE DONE");
1677 ec.ig.Emit (OpCodes.Pop);
1679 Report.Debug (128, "EMIT ANONYMOUS DELEGATE DONE", this, am, am.Scope, loc);