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 (DeclSpace 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.PartialContainer.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 Parameters InflateParameters (Parameters ps)
105 if (generic_method == null)
112 Parameter[] inflated_params = new Parameter [n];
113 Type[] inflated_types = new Type [n];
115 for (int i = 0; i < n; ++i) {
116 Parameter p = ps [i];
117 Type it = InflateType (p.ExternalType ()).ResolveAsTypeTerminal (this, false).Type;
118 inflated_types [i] = it;
119 inflated_params [i] = new Parameter (it, p.Name, p.ModFlags, p.OptAttributes, p.Location);
121 return new Parameters (inflated_params, inflated_types);
124 public TypeExpr InflateType (Type it)
127 if (generic_method == null)
128 return new TypeExpression (it, Location);
130 if (it.IsGenericParameter && (it.DeclaringMethod != null)) {
131 int pos = it.GenericParameterPosition;
132 it = CurrentTypeParameters [pos].Type;
133 } else if (it.IsGenericType) {
134 Type[] args = it.GetGenericArguments ();
136 TypeArguments inflated = new TypeArguments (Location);
137 foreach (Type t in args)
138 inflated.Add (InflateType (t));
140 return new ConstructedType (it, inflated, Location);
141 } else if (it.IsArray) {
142 TypeExpr et_expr = InflateType (it.GetElementType ());
143 int rank = it.GetArrayRank ();
145 Type et = et_expr.ResolveAsTypeTerminal (this, false).Type;
146 it = et.MakeArrayType (rank);
150 return new TypeExpression (it, Location);
153 public Field CaptureVariable (string name, TypeExpr type)
156 throw new InternalErrorException ("Helper class already defined!");
158 throw new ArgumentNullException ();
160 return new CapturedVariableField (this, name, type);
163 bool members_defined;
165 internal void CheckMembersDefined ()
168 throw new InternalErrorException ("Helper class already defined!");
171 protected class CapturedVariableField : Field
173 public CapturedVariableField (CompilerGeneratedClass helper, string name,
175 : base (helper, type, Modifiers.INTERNAL, name, null, helper.Location)
177 helper.AddField (this);
182 public class ScopeInfo : CompilerGeneratedClass
184 protected readonly RootScopeInfo RootScope;
185 new public readonly DeclSpace Parent;
186 public readonly int ID = ++next_id;
187 public Block ScopeBlock;
191 public static ScopeInfo CreateScope (Block block)
193 ToplevelBlock toplevel = block.Toplevel;
194 AnonymousContainer ac = toplevel.AnonymousContainer;
196 Report.Debug (128, "CREATE SCOPE", block, block.ScopeInfo, toplevel, ac);
199 return new ScopeInfo (block, toplevel.RootScope.Parent,
200 toplevel.RootScope.GenericMethod);
202 Report.Debug (128, "CREATE SCOPE #1", ac, ac.Host, ac.Scope, ac.Block,
203 ac.Container, ac.ContainerAnonymousMethod,
207 ScopeInfo parent = null;
209 for (b = ac.Block; b != null; b = b.Parent) {
210 if (b.ScopeInfo != null) {
211 parent = b.ScopeInfo;
216 Report.Debug (128, "CREATE SCOPE #2", parent);
218 ScopeInfo new_scope = new ScopeInfo (block, parent, null);
220 Report.Debug (128, "CREATE SCOPE #3", new_scope);
225 protected ScopeInfo (Block block, DeclSpace parent, GenericMethod generic)
226 : base (parent, generic, 0, block.StartLocation)
229 RootScope = block.Toplevel.RootScope;
232 Report.Debug (128, "NEW SCOPE", this, block,
233 block.Parent, block.Toplevel);
235 RootScope.AddScope (this);
238 protected ScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
239 GenericMethod generic, Location loc)
240 : base (parent, generic, 0, loc)
243 RootScope = (RootScopeInfo) this;
244 ScopeBlock = toplevel;
246 Report.Debug (128, "NEW ROOT SCOPE", this, toplevel, loc);
249 protected ScopeInitializer scope_initializer;
251 Hashtable locals = new Hashtable ();
252 Hashtable captured_scopes = new Hashtable ();
253 Hashtable captured_params;
255 protected CapturedScope[] CapturedScopes {
257 CapturedScope[] list = new CapturedScope [captured_scopes.Count];
258 captured_scopes.Values.CopyTo (list, 0);
263 protected CapturedVariable GetCapturedScope (ScopeInfo scope)
265 return (CapturedVariable) captured_scopes [scope];
268 public void EmitScopeInstance (EmitContext ec)
270 if (scope_initializer == null) {
272 // This is needed if someone overwrites the Emit method
273 // of Statement and manually calls Block.Emit without
274 // this snippet first:
276 // ec.EmitScopeInitFromBlock (The_Block);
277 // The_Block.Emit (ec);
279 throw new InternalErrorException ();
282 scope_initializer.Emit (ec);
285 public ExpressionStatement GetScopeInitializer (EmitContext ec)
287 Report.Debug (128, "GET SCOPE INITIALIZER",
288 this, GetType (), scope_initializer, ScopeBlock);
290 if (scope_initializer == null) {
291 scope_initializer = CreateScopeInitializer ();
292 if (scope_initializer.Resolve (ec) == null)
293 throw new InternalErrorException ();
296 return scope_initializer;
299 public Type GetScopeType (EmitContext ec)
304 TypeArguments targs = new TypeArguments (Location);
306 if (ec.DeclContainer.Parent.IsGeneric)
307 foreach (TypeParameter t in ec.DeclContainer.Parent.TypeParameters)
308 targs.Add (new TypeParameterExpr (t, Location));
309 if (ec.DeclContainer.IsGeneric)
310 foreach (TypeParameter t in ec.DeclContainer.CurrentTypeParameters)
311 targs.Add (new TypeParameterExpr (t, Location));
313 Report.Debug (128, "GET SCOPE TYPE", this, TypeBuilder, targs,
314 ec.DeclContainer, ec.DeclContainer.GetType (),
315 ec.DeclContainer.Parent.Name);
317 TypeExpr te = new ConstructedType (TypeBuilder, targs, Location);
318 te = te.ResolveAsTypeTerminal (ec, false);
319 if ((te == null) || (te.Type == null))
324 protected override bool DoDefineMembers ()
326 Report.Debug (64, "SCOPE INFO DEFINE MEMBERS", this, GetType (), IsGeneric,
327 Parent.IsGeneric, GenericMethod);
329 foreach (CapturedScope child in CapturedScopes) {
330 if (!child.DefineMembers ())
334 return base.DoDefineMembers ();
337 protected override bool DoResolveMembers ()
339 Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
340 Parent.IsGeneric, GenericMethod);
342 return base.DoResolveMembers ();
345 public Variable CaptureScope (ScopeInfo child)
347 CheckMembersDefined ();
348 Report.Debug (128, "CAPTURE SCOPE", this, GetType (), child, child.GetType ());
350 throw new InternalErrorException ();
351 CapturedScope captured = (CapturedScope) captured_scopes [child];
352 if (captured == null) {
353 captured = new CapturedScope (this, child);
354 captured_scopes.Add (child, captured);
359 public Variable AddLocal (LocalInfo local)
361 Report.Debug (128, "CAPTURE LOCAL", this, local);
362 Variable var = (Variable) locals [local];
364 var = new CapturedLocal (this, local);
365 locals.Add (local, var);
366 local.IsCaptured = true;
371 public Variable GetCapturedVariable (LocalInfo local)
373 return (Variable) locals [local];
376 public bool HostsParameters {
377 get { return captured_params != null; }
380 public Variable GetCapturedParameter (Parameter par)
382 if (captured_params != null)
383 return (Variable) captured_params [par];
388 public bool IsParameterCaptured (string name)
390 if (captured_params != null)
391 return captured_params [name] != null;
395 public Variable AddParameter (Parameter par, int idx)
397 if (captured_params == null)
398 captured_params = new Hashtable ();
400 Variable var = (Variable) captured_params [par];
402 var = new CapturedParameter (this, par, idx);
403 captured_params.Add (par, var);
404 par.IsCaptured = true;
410 protected string MakeFieldName (string local_name)
412 return "<" + ID + ":" + local_name + ">";
415 protected virtual ScopeInitializer CreateScopeInitializer ()
417 return new ScopeInitializer (this);
420 protected abstract class CapturedVariable : Variable
422 public readonly ScopeInfo Scope;
423 public readonly string Name;
425 public FieldExpr FieldInstance;
426 protected Field field;
428 protected CapturedVariable (ScopeInfo scope, string name)
434 protected CapturedVariable (ScopeInfo scope, string name, Type type)
437 this.field = scope.CaptureVariable (
438 scope.MakeFieldName (name), scope.RootScope.InflateType (type));
442 get { return field; }
445 public override Type Type {
446 get { return Field.MemberType; }
449 public override bool HasInstance {
453 public override bool NeedsTemporary {
457 protected FieldInfo GetField (EmitContext ec)
459 if ((ec.CurrentBlock != null) &&
460 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel))
461 return Field.FieldBuilder;
463 return FieldInstance.FieldInfo;
466 public override void EmitInstance (EmitContext ec)
468 Scope.EmitScopeInstance (ec);
471 public override void Emit (EmitContext ec)
473 ec.ig.Emit (OpCodes.Ldfld, GetField (ec));
476 public override void EmitAssign (EmitContext ec)
478 ec.ig.Emit (OpCodes.Stfld, GetField (ec));
481 public override void EmitAddressOf (EmitContext ec)
483 ec.ig.Emit (OpCodes.Ldflda, GetField (ec));
487 protected class CapturedParameter : CapturedVariable {
488 public readonly Parameter Parameter;
489 public readonly int Idx;
491 public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
492 : base (scope, par.Name, par.ParameterType)
494 this.Parameter = par;
498 public override string ToString ()
500 return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
501 Parameter.Name, Idx);
505 protected class CapturedLocal : CapturedVariable {
506 public readonly LocalInfo Local;
508 public CapturedLocal (ScopeInfo scope, LocalInfo local)
509 : base (scope, local.Name, local.VariableType)
514 public override string ToString ()
516 return String.Format ("{0} ({1}:{2})", GetType (), Field,
521 protected class CapturedThis : CapturedVariable {
522 public CapturedThis (RootScopeInfo host)
523 : base (host, "<>THIS", host.ParentType)
527 protected class CapturedScope : CapturedVariable {
528 public readonly ScopeInfo ChildScope;
530 public CapturedScope (ScopeInfo root, ScopeInfo child)
531 : base (root, "scope" + child.ID)
533 this.ChildScope = child;
536 public bool DefineMembers ()
538 Type type = ChildScope.IsGeneric ?
539 ChildScope.CurrentType : ChildScope.TypeBuilder;
540 Report.Debug (128, "CAPTURED SCOPE DEFINE MEMBERS", this, Scope,
541 ChildScope, Name, type);
543 throw new InternalErrorException ();
544 field = Scope.CaptureVariable (
545 Scope.MakeFieldName (Name), Scope.InflateType (type));
549 public override string ToString ()
551 return String.Format ("CapturedScope ({1} captured in {0})",
556 static void DoPath (StringBuilder sb, ScopeInfo start)
558 sb.Append ((start.ID).ToString ());
561 public override string ToString ()
563 StringBuilder sb = new StringBuilder ();
569 return sb.ToString ();
572 protected class ScopeInitializer : ExpressionStatement
575 CapturedVariable captured_scope;
576 LocalBuilder scope_instance;
577 ConstructorInfo scope_ctor;
581 public ScopeInitializer (ScopeInfo scope)
584 this.loc = scope.Location;
585 eclass = ExprClass.Value;
588 public ScopeInfo Scope {
589 get { return scope; }
592 public override Expression DoResolve (EmitContext ec)
594 if (scope_ctor != null)
597 Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
598 ec, ec.CurrentBlock);
600 type = Scope.GetScopeType (ec);
602 throw new InternalErrorException ();
604 if (!DoResolveInternal (ec))
605 throw new InternalErrorException ();
610 protected virtual bool DoResolveInternal (EmitContext ec)
612 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookupFinal (
613 ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
614 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
616 throw new InternalErrorException ();
618 scope_ctor = (ConstructorInfo) mg.Methods [0];
620 Report.Debug (128, "RESOLVE THE INIT", this, Scope, Scope.RootScope,
621 Scope.RootScope.GetType ());
623 ScopeInfo host = Scope.RootScope;
624 if ((Scope != host) && (Scope.RootScope is IteratorHost)) {
625 captured_scope = host.GetCapturedScope (Scope);
626 Type root = host.GetScopeType (ec);
627 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
628 type, root, captured_scope.Field.Name, loc);
630 throw new InternalErrorException ();
632 fe.InstanceExpression = this;
633 captured_scope.FieldInstance = fe;
635 Report.Debug (128, "RESOLVE THE INIT #1", this,
638 scope_instance = ec.ig.DeclareLocal (type);
640 foreach (CapturedLocal local in Scope.locals.Values) {
641 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
642 ec.ContainerType, type, local.Field.Name, loc);
643 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
644 Scope, ec, ec.ContainerType, type,
645 local.Field, local.Field.Name, loc, fe);
647 throw new InternalErrorException ();
649 fe.InstanceExpression = this;
650 local.FieldInstance = fe;
653 if (Scope.HostsParameters) {
654 foreach (CapturedParameter cp in Scope.captured_params.Values) {
655 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
656 ec.ContainerType, type, cp.Field.Name, loc);
658 throw new InternalErrorException ();
660 fe.InstanceExpression = this;
661 cp.FieldInstance = fe;
665 foreach (CapturedScope scope in Scope.CapturedScopes) {
666 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
667 ec.ContainerType, type, scope.Field.Name, loc);
668 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #3", this, Scope,
669 scope, ec, ec.ContainerType, type,
670 scope.Field, scope.Field.Name, loc, fe);
672 throw new InternalErrorException ();
674 fe.InstanceExpression = this;
675 scope.FieldInstance = fe;
681 protected virtual void EmitParameterReference (EmitContext ec,
682 CapturedParameter cp)
684 int extra = ec.MethodIsStatic ? 0 : 1;
685 ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
691 protected virtual void DoEmit (EmitContext ec)
693 if ((ec.CurrentBlock != null) &&
694 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)) {
695 ec.ig.Emit (OpCodes.Ldarg_0);
697 if (ec.CurrentAnonymousMethod != null) {
698 ScopeInfo host = ec.CurrentAnonymousMethod.Scope;
699 Variable captured = host.GetCapturedScope (scope);
700 Report.Debug (128, "EMIT SCOPE INSTANCE #2",
701 ec.CurrentAnonymousMethod, host,
703 if (captured != null)
706 } else if (scope_instance != null)
707 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
709 Report.Debug (128, "DO EMIT", this, Scope, ec,
710 scope_instance, captured_scope);
711 captured_scope.EmitInstance (ec);
712 captured_scope.Emit (ec);
716 protected void DoEmitInstance (EmitContext ec)
718 Report.Debug (128, "DO EMIT INSTANCE", this, Scope, ec,
719 scope_instance, captured_scope);
721 if (scope_instance != null)
722 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
724 captured_scope.EmitInstance (ec);
727 protected virtual void EmitScopeConstructor (EmitContext ec)
729 ec.ig.Emit (OpCodes.Newobj, scope_ctor);
732 public override void Emit (EmitContext ec)
735 throw new InternalErrorException (
736 "Scope {0} not initialized yet", scope);
741 public override void EmitStatement (EmitContext ec)
746 DoEmitStatement (ec);
750 protected virtual void DoEmitStatement (EmitContext ec)
752 Report.Debug (128, "EMIT SCOPE INITIALIZER STATEMENT", this, id,
753 Scope, scope_instance, ec);
755 ec.ig.Emit (OpCodes.Nop);
756 ec.ig.Emit (OpCodes.Ldc_I4, id);
757 ec.ig.Emit (OpCodes.Pop);
758 ec.ig.Emit (OpCodes.Nop);
760 if (scope_instance == null)
761 ec.ig.Emit (OpCodes.Ldarg_0);
762 EmitScopeConstructor (ec);
763 if (scope_instance != null)
764 ec.ig.Emit (OpCodes.Stloc, scope_instance);
766 captured_scope.EmitAssign (ec);
768 if (Scope.HostsParameters) {
769 foreach (CapturedParameter cp in Scope.captured_params.Values) {
770 Report.Debug (128, "EMIT SCOPE INIT #6", this,
771 ec, ec.IsStatic, Scope, cp, cp.Field.Name);
773 EmitParameterReference (ec, cp);
774 ec.ig.Emit (OpCodes.Stfld, cp.FieldInstance.FieldInfo);
778 if (Scope is IteratorHost)
781 foreach (CapturedScope scope in Scope.CapturedScopes) {
782 ScopeInfo child = scope.ChildScope;
784 Report.Debug (128, "EMIT SCOPE INIT #5", this, Scope,
785 scope.Scope, scope.ChildScope);
787 ExpressionStatement init = child.GetScopeInitializer (ec);
788 init.EmitStatement (ec);
791 scope.ChildScope.EmitScopeInstance (ec);
792 scope.EmitAssign (ec);
798 public class RootScopeInfo : ScopeInfo
800 public RootScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
801 GenericMethod generic, Location loc)
802 : base (toplevel, parent, generic, loc)
804 scopes = new ArrayList ();
807 TypeExpr parent_type;
808 CapturedVariableField parent_link;
809 CapturedThis this_variable;
810 protected ArrayList scopes;
812 public virtual bool IsIterator {
813 get { return false; }
816 public RootScopeInfo ParentHost {
817 get { return Parent.PartialContainer as RootScopeInfo; }
820 public Type ParentType {
821 get { return parent_type.Type; }
824 public Field ParentLink {
825 get { return parent_link; }
828 protected CapturedThis THIS {
829 get { return this_variable; }
832 public Variable CaptureThis ()
834 if (ParentHost != null)
835 return ParentHost.CaptureThis ();
837 CheckMembersDefined ();
838 if (this_variable == null)
839 this_variable = new CapturedThis (this);
840 return this_variable;
843 public void AddScope (ScopeInfo scope)
849 public void LinkScopes ()
851 Report.Debug (128, "LINK SCOPES", this, linked, scopes);
857 if (ParentHost != null)
858 ParentHost.LinkScopes ();
860 foreach (ScopeInfo si in scopes) {
862 throw new InternalErrorException ();
863 if (si.DefineType () == null)
864 throw new InternalErrorException ();
865 if (!si.ResolveType ())
866 throw new InternalErrorException ();
869 foreach (ScopeInfo si in scopes) {
870 if (!si.ResolveMembers ())
871 throw new InternalErrorException ();
872 if (!si.DefineMembers ())
873 throw new InternalErrorException ();
877 protected override ScopeInitializer CreateScopeInitializer ()
879 return new RootScopeInitializer (this);
882 protected override bool DefineNestedTypes ()
884 if (Parent.IsGeneric) {
885 parent_type = new ConstructedType (
886 Parent.TypeBuilder, Parent.TypeParameters, Location);
887 parent_type = parent_type.ResolveAsTypeTerminal (this, false);
888 if ((parent_type == null) || (parent_type.Type == null))
891 parent_type = new TypeExpression (Parent.TypeBuilder, Location);
894 CompilerGeneratedClass parent = Parent.PartialContainer as CompilerGeneratedClass;
896 parent_link = new CapturedVariableField (this, "<>parent", parent_type);
898 return base.DefineNestedTypes ();
901 protected override bool DoDefineMembers ()
903 ArrayList args = new ArrayList ();
904 if (this is IteratorHost)
905 args.Add (new Parameter (
906 TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
910 if (Parent is CompilerGeneratedClass)
911 pfield = parent_link;
913 pfield = this_variable != null ? this_variable.Field : null;
915 args.Add (new Parameter (
916 pfield.MemberType, "parent", Parameter.Modifier.NONE,
919 Parameter[] ctor_params = new Parameter [args.Count];
920 args.CopyTo (ctor_params, 0);
921 Constructor ctor = new Constructor (
922 this, MemberName.Name, Modifiers.PUBLIC,
923 new Parameters (ctor_params),
924 new GeneratedBaseInitializer (Location),
926 AddConstructor (ctor);
928 ctor.Block = new ToplevelBlock (null, Location);
929 ctor.Block.AddStatement (new TheCtor (this));
931 return base.DoDefineMembers ();
934 protected virtual void EmitScopeConstructor (EmitContext ec)
936 int pos = (this is IteratorHost) ? 2 : 1;
939 if (Parent is CompilerGeneratedClass)
940 pfield = parent_link;
942 pfield = this_variable != null ? this_variable.Field : null;
944 if (pfield != null) {
945 ec.ig.Emit (OpCodes.Ldarg_0);
946 ec.ig.Emit (OpCodes.Ldarg, pos);
947 ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
952 protected class TheCtor : Statement
956 public TheCtor (RootScopeInfo host)
961 public override bool Resolve (EmitContext ec)
966 protected override void DoEmit (EmitContext ec)
968 host.EmitScopeConstructor (ec);
972 protected class RootScopeInitializer : ScopeInitializer
976 public RootScopeInitializer (RootScopeInfo host)
982 public RootScopeInfo Host {
986 protected override bool DoResolveInternal (EmitContext ec)
988 Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
989 this, Host, Host.ParentType, loc);
991 if (Host.THIS != null) {
992 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
993 ec.ContainerType, type, Host.THIS.Field.Name, loc);
995 throw new InternalErrorException ();
997 fe.InstanceExpression = this;
998 Host.THIS.FieldInstance = fe;
1001 return base.DoResolveInternal (ec);
1004 protected virtual bool IsGetEnumerator {
1005 get { return false; }
1008 protected override void EmitScopeConstructor (EmitContext ec)
1010 if (host.THIS != null) {
1011 ec.ig.Emit (OpCodes.Ldarg_0);
1012 if (IsGetEnumerator)
1013 ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
1014 else if (host.THIS.Type.IsValueType)
1015 Expression.LoadFromPtr (ec.ig, host.THIS.Type);
1016 } else if (host.ParentLink != null)
1017 ec.ig.Emit (OpCodes.Ldarg_0);
1019 base.EmitScopeConstructor (ec);
1025 public interface IAnonymousContainer
1031 GenericMethod GenericMethod {
1035 RootScopeInfo RootScope {
1044 public interface IAnonymousHost
1047 // Invoked if a yield statement is found in the body
1052 // Invoked if an anonymous method is found in the body
1054 void AddAnonymousMethod (AnonymousMethodExpression anonymous);
1057 public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
1059 public readonly AnonymousMethodExpression Parent;
1060 public readonly TypeContainer Host;
1061 public readonly Parameters Parameters;
1063 public ToplevelBlock Block;
1064 protected AnonymousMethod anonymous;
1066 protected readonly Block container;
1067 protected readonly GenericMethod generic;
1069 public Block Container {
1070 get { return container; }
1073 public GenericMethod GenericMethod {
1074 get { return generic; }
1077 public AnonymousMethod AnonymousMethod {
1078 get { return anonymous; }
1081 public RootScopeInfo RootScope {
1082 get { return root_scope; }
1085 public AnonymousMethodExpression (AnonymousMethodExpression parent,
1086 GenericMethod generic, TypeContainer host,
1087 Parameters parameters, Block container,
1090 this.Parent = parent;
1091 this.generic = parent != null ? null : generic;
1093 this.Parameters = parameters;
1094 this.container = container;
1097 Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host,
1101 parent.AddAnonymousMethod (this);
1105 RootScopeInfo root_scope;
1107 static int next_index;
1109 void IAnonymousHost.SetYields ()
1111 throw new InvalidOperationException ();
1114 public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
1116 if (children == null)
1117 children = new ArrayList ();
1118 children.Add (anonymous);
1121 public bool CreateAnonymousHelpers ()
1123 Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
1124 this, Host, container, loc);
1126 if (container != null)
1127 root_scope = container.Toplevel.CreateRootScope (Host);
1129 if (children != null) {
1130 foreach (AnonymousMethodExpression child in children) {
1131 if (!child.CreateAnonymousHelpers ())
1139 public override string ExprClassName {
1141 return "anonymous method";
1145 void Error_ParameterMismatch (Type t)
1147 Report.Error (1661, loc, "Anonymous method could not be converted to delegate `" +
1148 "{0}' since there is a parameter mismatch",
1149 TypeManager.CSharpName (t));
1152 public bool ImplicitStandardConversionExists (Type delegate_type)
1154 if (Parameters == null)
1157 MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1158 Host.TypeBuilder, delegate_type, loc);
1159 MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1160 ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
1162 if (Parameters.Count != invoke_pd.Count)
1165 for (int i = 0; i < Parameters.Count; ++i) {
1166 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i))
1173 // Returns true if this anonymous method can be implicitly
1174 // converted to the delegate type `delegate_type'
1176 public Expression Compatible (EmitContext ec, Type delegate_type)
1178 if (anonymous != null)
1179 return anonymous.AnonymousDelegate;
1181 if (!ec.IsAnonymousMethodAllowed) {
1182 Report.Error (1706, loc,
1183 "Anonymous methods are not allowed in the " +
1184 "attribute declaration");
1188 if (!TypeManager.IsDelegateType (delegate_type)){
1189 Report.Error (1660, loc,
1190 "Cannot convert anonymous method block to type " +
1191 "`{0}' because it is not a delegate type",
1192 TypeManager.CSharpName (delegate_type));
1197 // At this point its the first time we know the return type that is
1198 // needed for the anonymous method. We create the method here.
1201 MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1202 ec.ContainerType, delegate_type, loc);
1203 MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1204 ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
1206 Parameters parameters;
1207 if (Parameters == null) {
1209 // We provide a set of inaccessible parameters
1211 Parameter [] fixedpars = new Parameter [invoke_pd.Count];
1213 for (int i = 0; i < invoke_pd.Count; i++) {
1214 Parameter.Modifier i_mod = invoke_pd.ParameterModifier (i);
1215 if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1216 Report.Error (1688, loc, "Cannot convert anonymous " +
1217 "method block without a parameter list " +
1218 "to delegate type `{0}' because it has " +
1219 "one or more `out' parameters.",
1220 TypeManager.CSharpName (delegate_type));
1223 fixedpars [i] = new Parameter (
1224 invoke_pd.ParameterType (i), "+" + (++next_index),
1225 invoke_pd.ParameterModifier (i), null, loc);
1228 parameters = new Parameters (fixedpars);
1229 if (!parameters.Resolve (ec))
1232 if (Parameters.Count != invoke_pd.Count) {
1233 Report.SymbolRelatedToPreviousError (delegate_type);
1234 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1235 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1236 Error_ParameterMismatch (delegate_type);
1240 for (int i = 0; i < Parameters.Count; ++i) {
1241 Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1242 if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1243 if (p_mod == Parameter.Modifier.NONE)
1244 Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1245 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1247 Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1248 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1249 Error_ParameterMismatch (delegate_type);
1253 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1254 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1256 TypeManager.CSharpName (Parameters.ParameterType (i)),
1257 TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1258 Error_ParameterMismatch (delegate_type);
1263 parameters = Parameters;
1267 // Second: the return type of the delegate must be compatible with
1268 // the anonymous type. Instead of doing a pass to examine the block
1269 // we satisfy the rule by setting the return type on the EmitContext
1270 // to be the delegate type return type.
1273 //MethodBuilder builder = method_data.MethodBuilder;
1274 //ILGenerator ig = builder.GetILGenerator ();
1276 Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1277 Container, Block, invoke_mb.ReturnType, delegate_type,
1278 TypeManager.IsGenericType (delegate_type), loc);
1280 anonymous = new AnonymousMethod (
1281 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
1282 GenericMethod, parameters, Container, Block, invoke_mb.ReturnType,
1283 delegate_type, loc);
1285 if (!anonymous.Resolve (ec))
1288 return anonymous.AnonymousDelegate;
1291 public override Expression DoResolve (EmitContext ec)
1294 // Set class type, set type
1297 eclass = ExprClass.Value;
1300 // This hack means `The type is not accessible
1301 // anywhere', we depend on special conversion
1304 type = TypeManager.anonymous_method_type;
1306 if ((Parameters != null) && !Parameters.Resolve (ec))
1312 public override void Emit (EmitContext ec)
1314 // nothing, as we only exist to not do anything.
1317 public bool IsIterator {
1318 get { return false; }
1322 public abstract class AnonymousContainer : IAnonymousContainer
1324 public readonly Location Location;
1326 public Parameters Parameters;
1329 // The block that makes up the body for the anonymous mehtod
1331 public readonly ToplevelBlock Block;
1333 public readonly int ModFlags;
1334 public Type ReturnType;
1335 public readonly DeclSpace Host;
1338 // The implicit method we create
1340 protected Method method;
1341 protected EmitContext aec;
1343 // The emit context for the anonymous method
1344 protected bool unreachable;
1345 protected readonly Block container;
1346 protected readonly GenericMethod generic;
1349 // Points to our container anonymous method if its present
1351 public readonly AnonymousContainer ContainerAnonymousMethod;
1353 protected AnonymousContainer (AnonymousContainer parent, DeclSpace host,
1354 GenericMethod generic, Parameters parameters,
1355 Block container, ToplevelBlock block,
1356 Type return_type, int mod, Location loc)
1358 this.ContainerAnonymousMethod = parent;
1359 this.ReturnType = return_type;
1360 this.ModFlags = mod;
1363 this.container = container;
1364 this.generic = parent != null ? null : generic;
1365 this.Parameters = parameters;
1367 this.Location = loc;
1369 block.AnonymousContainer = this;
1372 public Method Method {
1373 get { return method; }
1376 public abstract RootScopeInfo RootScope {
1380 public abstract ScopeInfo Scope {
1384 public abstract string GetSignatureForError ();
1386 public virtual bool Resolve (EmitContext ec)
1388 Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1389 RootScope, Parameters, ec.IsStatic);
1391 if (ReturnType != null) {
1392 TypeExpr return_type_expr;
1393 if (RootScope != null)
1394 return_type_expr = RootScope.InflateType (ReturnType);
1396 return_type_expr = new TypeExpression (ReturnType, Location);
1397 return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
1398 if ((return_type_expr == null) || (return_type_expr.Type == null))
1400 ReturnType = return_type_expr.Type;
1403 if (RootScope != null)
1404 Parameters = RootScope.InflateParameters (Parameters);
1406 aec = new EmitContext (
1407 ec.ResolveContext, ec.TypeContainer,
1408 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1409 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1410 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1412 aec.CurrentAnonymousMethod = this;
1413 aec.IsFieldInitializer = ec.IsFieldInitializer;
1414 aec.IsStatic = ec.IsStatic;
1416 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1417 RootScope, Parameters, Block);
1420 if (!aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable))
1423 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #3", this, ec, aec, Block);
1425 method = DoCreateMethodHost (ec);
1430 if (!method.ResolveMembers ())
1432 return method.Define ();
1435 protected abstract Method DoCreateMethodHost (EmitContext ec);
1437 public Block Container {
1438 get { return container; }
1441 public GenericMethod GenericMethod {
1442 get { return generic; }
1445 public abstract bool IsIterator {
1449 protected class AnonymousMethodMethod : Method
1451 public readonly AnonymousContainer AnonymousMethod;
1452 public readonly ScopeInfo Scope;
1454 public AnonymousMethodMethod (AnonymousContainer am, ScopeInfo scope,
1455 GenericMethod generic, TypeExpr return_type,
1456 int mod, MemberName name, Parameters parameters)
1457 : base (scope != null ? scope : am.Host,
1458 generic, return_type, mod, false, name, parameters, null)
1460 this.AnonymousMethod = am;
1463 if (scope != null) {
1464 scope.CheckMembersDefined ();
1465 scope.AddMethod (this);
1467 ModFlags |= Modifiers.STATIC;
1468 am.Host.PartialContainer.AddMethod (this);
1473 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1475 EmitContext aec = AnonymousMethod.aec;
1477 aec.MethodIsStatic = Scope == null;
1483 public class AnonymousMethod : AnonymousContainer
1485 public readonly Type DelegateType;
1488 // The value return by the Compatible call, this ensure that
1489 // the code works even if invoked more than once (Resolve called
1490 // more than once, due to the way Convert.ImplicitConversion works
1492 Expression anonymous_delegate;
1493 RootScopeInfo root_scope;
1496 public AnonymousMethod (AnonymousMethod parent, RootScopeInfo root_scope,
1497 DeclSpace host, GenericMethod generic,
1498 Parameters parameters, Block container,
1499 ToplevelBlock block, Type return_type, Type delegate_type,
1501 : base (parent, host, generic, parameters, container, block,
1502 return_type, 0, loc)
1504 this.DelegateType = delegate_type;
1505 this.root_scope = root_scope;
1508 public override RootScopeInfo RootScope {
1509 get { return root_scope; }
1512 public override ScopeInfo Scope {
1513 get { return scope; }
1516 public override bool IsIterator {
1517 get { return false; }
1520 public Expression AnonymousDelegate {
1521 get { return anonymous_delegate; }
1524 public override string GetSignatureForError ()
1526 return TypeManager.CSharpName (DelegateType);
1530 // Creates the host for the anonymous method
1532 protected override Method DoCreateMethodHost (EmitContext ec)
1534 string name = CompilerGeneratedClass.MakeName ("AnonymousMethod");
1535 MemberName member_name;
1537 Report.Debug (128, "CREATE METHOD HOST #0", RootScope);
1542 Report.Debug (128, "CREATE METHOD HOST #1", this, Block, Block.ScopeInfo,
1543 RootScope, Location);
1545 for (b = Block.Parent; b != null; b = b.Parent) {
1546 Report.Debug (128, "CREATE METHOD HOST #2", this, Block,
1548 if (b.ScopeInfo != null) {
1549 scope = b.ScopeInfo;
1555 scope.CheckMembersDefined ();
1557 ArrayList scopes = new ArrayList ();
1559 for (b = b.Parent; b != null; b = b.Parent) {
1560 if (b.ScopeInfo != null)
1561 scopes.Add (b.ScopeInfo);
1565 Report.Debug (128, "CREATE METHOD HOST #1", this, scope, scopes);
1567 foreach (ScopeInfo si in scopes)
1568 scope.CaptureScope (si);
1570 Report.Debug (128, "CREATE METHOD HOST", this, Block, container,
1571 RootScope, scope, scopes, Location,
1572 ContainerAnonymousMethod);
1574 GenericMethod generic_method = null;
1576 if (TypeManager.IsGenericType (DelegateType)) {
1577 TypeArguments args = new TypeArguments (Location);
1579 Type dt = DelegateType.GetGenericTypeDefinition ();
1581 Type[] tparam = TypeManager.GetTypeArguments (dt);
1582 for (int i = 0; i < tparam.Length; i++)
1583 args.Add (new SimpleName (tparam [i].Name, Location));
1585 member_name = new MemberName (name, args, Location);
1587 Report.Debug (128, "CREATE METHOD HOST #5", this, DelegateType,
1588 TypeManager.GetTypeArguments (DelegateType),
1591 generic_method = new GenericMethod (
1592 Host.NamespaceEntry, scope, member_name,
1593 new TypeExpression (ReturnType, Location), Parameters);
1595 generic_method.SetParameterInfo (null);
1598 member_name = new MemberName (name, Location);
1600 return new AnonymousMethodMethod (
1601 this, scope, generic_method, new TypeExpression (ReturnType, Location),
1602 Modifiers.INTERNAL, member_name, Parameters);
1605 public override bool Resolve (EmitContext ec)
1607 if (!base.Resolve (ec))
1610 anonymous_delegate = new AnonymousDelegate (
1611 this, DelegateType, Location).Resolve (ec);
1612 if (anonymous_delegate == null)
1618 public MethodInfo GetMethodBuilder (EmitContext ec)
1620 MethodInfo builder = method.MethodBuilder;
1621 if ((Scope != null) && Scope.IsGeneric) {
1622 Type scope_type = Scope.GetScopeType (ec);
1623 if (scope_type == null)
1624 throw new InternalErrorException ();
1626 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1627 ec.ContainerType, scope_type, builder.Name, Location);
1630 throw new InternalErrorException ();
1631 builder = (MethodInfo) mg.Methods [0];
1635 if (!DelegateType.IsGenericType)
1638 Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1639 return builder.MakeGenericMethod (targs);
1645 public static void Error_AddressOfCapturedVar (string name, Location loc)
1647 Report.Error (1686, loc,
1648 "Local variable `{0}' or its members cannot have their " +
1649 "address taken and be used inside an anonymous method block",
1655 // This will emit the code for the delegate, as well delegate creation on the host
1657 public class AnonymousDelegate : DelegateCreation {
1660 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1667 public override Expression DoResolve (EmitContext ec)
1669 eclass = ExprClass.Value;
1674 public override void Emit (EmitContext ec)
1676 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE");
1677 //ec.ig.Emit (OpCodes.Pop);
1680 // Now emit the delegate creation.
1682 if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1683 Report.Debug (128, "EMIT ANONYMOUS DELEGATE", this, am, am.Scope, loc);
1684 delegate_instance_expression = am.Scope.GetScopeInitializer (ec);
1686 if (delegate_instance_expression == null)
1687 throw new InternalErrorException ();
1690 Expression ml = Expression.MemberLookup (
1691 ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
1692 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
1695 constructor_method = ((MethodGroupExpr) ml).Methods [0];
1696 delegate_method = am.GetMethodBuilder (ec);
1699 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE DONE");
1700 //ec.ig.Emit (OpCodes.Pop);
1702 Report.Debug (128, "EMIT ANONYMOUS DELEGATE DONE", this, am, am.Scope, loc);