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 = String.Format ("<>c__CompilerGenerated{0}", ++next_index);
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 protected 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 public readonly AnonymousMethodHost RootScope;
164 public readonly int ID = ++next_id;
165 public Block ScopeBlock;
169 public ScopeInfo (AnonymousMethodHost root, Block block)
170 : base (root, null, Modifiers.PUBLIC, block.StartLocation)
172 this.RootScope = root;
175 Report.Debug (64, "NEW SCOPE", this, root, block);
177 root.AddScope (this);
180 public ScopeInfo (ToplevelBlock toplevel, TypeContainer parent,
181 GenericMethod generic, Location loc)
182 : base (parent, generic, 0, loc)
184 RootScope = (AnonymousMethodHost) this;
185 ScopeBlock = toplevel;
187 Report.Debug (64, "NEW ROOT SCOPE", this);
190 protected CapturedScope scope_instance;
191 protected ScopeInitializer scope_initializer;
193 Hashtable locals = new Hashtable ();
195 public virtual AnonymousMethodHost Host {
196 get { return RootScope; }
199 public Variable ScopeInstance {
200 get { return scope_instance; }
203 public void EmitScopeInstance (EmitContext ec)
205 if (scope_initializer == null) {
207 // This is needed if someone overwrites the Emit method
208 // of Statement and manually calls Block.Emit without
209 // this snippet first:
211 // ec.EmitScopeInitFromBlock (The_Block);
212 // The_Block.Emit (ec);
214 throw new InternalErrorException ();
217 scope_initializer.Emit (ec);
220 public ExpressionStatement GetScopeInitializer (EmitContext ec)
222 Report.Debug (64, "GET SCOPE INITIALIZER",
223 this, GetType (), scope_initializer, ScopeBlock);
225 if (scope_initializer == null) {
226 scope_initializer = CreateScopeInitializer ();
227 if (scope_initializer.Resolve (ec) == null)
228 throw new InternalErrorException ();
231 return scope_initializer;
234 public Type GetScopeType (EmitContext ec)
239 TypeArguments targs = new TypeArguments (Location);
241 if (ec.DeclContainer.Parent.IsGeneric)
242 foreach (TypeParameter t in ec.DeclContainer.Parent.TypeParameters)
243 targs.Add (new TypeParameterExpr (t, Location));
244 if (ec.DeclContainer.IsGeneric)
245 foreach (TypeParameter t in ec.DeclContainer.CurrentTypeParameters)
246 targs.Add (new TypeParameterExpr (t, Location));
248 TypeExpr te = new ConstructedType (TypeBuilder, targs, Location);
249 te = te.ResolveAsTypeTerminal (ec, false);
250 if ((te == null) || (te.Type == null))
255 protected override bool DoResolveMembers ()
257 Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
258 Parent.IsGeneric, GenericMethod);
261 scope_instance = new CapturedScope (Host, this);
263 return base.DoResolveMembers ();
266 public Variable AddLocal (LocalInfo local)
268 Variable var = (Variable) locals [local];
270 var = new CapturedLocal (this, local);
271 locals.Add (local, var);
272 local.IsCaptured = true;
277 public Variable GetCapturedVariable (LocalInfo local)
279 return (Variable) locals [local];
282 protected string MakeFieldName (string local_name)
284 return "<" + ID + ":" + local_name + ">";
287 protected virtual ScopeInitializer CreateScopeInitializer ()
289 return new ScopeInitializer (this);
292 protected abstract class CapturedVariable : Variable
294 public readonly ScopeInfo Scope;
295 public readonly Field Field;
297 public FieldExpr FieldInstance;
299 protected CapturedVariable (ScopeInfo scope, string name, Type type)
302 this.Field = scope.CaptureVariable (
303 scope.MakeFieldName (name), scope.RootScope.InflateType (type));
306 public override Type Type {
307 get { return Field.MemberType; }
310 public override bool HasInstance {
314 public override bool NeedsTemporary {
318 protected FieldInfo GetField (EmitContext ec)
320 if (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)
321 return Field.FieldBuilder;
323 return FieldInstance.FieldInfo;
326 public override void EmitInstance (EmitContext ec)
328 ec.CurrentBlock.Toplevel.EmitScopeInstance (ec, Scope);
331 public override void Emit (EmitContext ec)
333 ec.ig.Emit (OpCodes.Ldfld, GetField (ec));
336 public override void EmitAssign (EmitContext ec)
338 ec.ig.Emit (OpCodes.Stfld, GetField (ec));
341 public override void EmitAddressOf (EmitContext ec)
343 ec.ig.Emit (OpCodes.Ldflda, GetField (ec));
347 protected class CapturedParameter : CapturedVariable {
348 public readonly Parameter Parameter;
349 public readonly int Idx;
351 public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
352 : base (scope, par.Name, par.ParameterType)
354 this.Parameter = par;
358 public override string ToString ()
360 return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
361 Parameter.Name, Idx);
365 protected class CapturedLocal : CapturedVariable {
366 public readonly LocalInfo Local;
368 public CapturedLocal (ScopeInfo scope, LocalInfo local)
369 : base (scope, local.Name, local.VariableType)
374 public override string ToString ()
376 return String.Format ("{0} ({1}:{2})", GetType (), Field,
381 protected class CapturedThis : CapturedVariable {
382 public CapturedThis (AnonymousMethodHost host)
383 : base (host, "<>THIS", host.ParentType)
387 protected class CapturedScope : CapturedVariable {
388 public readonly ScopeInfo ChildScope;
390 public CapturedScope (ScopeInfo root, ScopeInfo child)
391 : base (root, child.ID + "_scope",
392 child.IsGeneric ? child.CurrentType : child.TypeBuilder)
394 this.ChildScope = child;
398 static void DoPath (StringBuilder sb, ScopeInfo start)
400 sb.Append ((start.ID).ToString ());
403 public override string ToString ()
405 StringBuilder sb = new StringBuilder ();
411 return sb.ToString ();
414 protected class ScopeInitializer : ExpressionStatement
417 LocalBuilder scope_instance;
418 ConstructorInfo scope_ctor;
422 public ScopeInitializer (ScopeInfo scope)
425 this.loc = scope.Location;
426 eclass = ExprClass.Value;
429 public ScopeInfo Scope {
430 get { return scope; }
433 public override Expression DoResolve (EmitContext ec)
435 if (scope_ctor != null)
438 Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
439 ec, ec.CurrentBlock);
441 type = Scope.GetScopeType (ec);
443 throw new InternalErrorException ();
445 if (!DoResolveInternal (ec))
446 throw new InternalErrorException ();
451 protected virtual bool DoResolveInternal (EmitContext ec)
453 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookupFinal (
454 ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
455 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
457 throw new InternalErrorException ();
459 scope_ctor = (ConstructorInfo) mg.Methods [0];
461 if (Scope.ScopeInstance == null)
462 scope_instance = ec.ig.DeclareLocal (type);
464 Type root = Scope.Host.GetScopeType (ec);
465 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
466 type, root, Scope.scope_instance.Field.Name, loc);
468 throw new InternalErrorException ();
470 fe.InstanceExpression = this;
471 Scope.scope_instance.FieldInstance = fe;
474 foreach (CapturedLocal local in Scope.locals.Values) {
475 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
476 ec.ContainerType, type, local.Field.Name, loc);
477 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
478 Scope, ec, ec.ContainerType, type,
479 local.Field, local.Field.Name, loc, fe);
481 throw new InternalErrorException ();
483 fe.InstanceExpression = this;
484 local.FieldInstance = fe;
490 protected virtual void EmitParameterReference (EmitContext ec,
491 CapturedParameter cp)
493 int extra = ec.IsStatic ? 0 : 1;
494 ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
500 protected virtual void DoEmit (EmitContext ec)
502 if (ec.CurrentBlock.Toplevel == Scope.ScopeBlock.Toplevel)
505 ec.ig.Emit (OpCodes.Ldarg_0);
508 protected void DoEmitInstance (EmitContext ec)
510 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
513 protected virtual void EmitScopeConstructor (EmitContext ec)
515 ec.ig.Emit (OpCodes.Newobj, scope_ctor);
518 public override void Emit (EmitContext ec)
521 throw new InternalErrorException (
522 "Scope {0} not initialized yet", scope);
527 public override void EmitStatement (EmitContext ec)
532 DoEmitStatement (ec);
536 protected virtual void DoEmitStatement (EmitContext ec)
538 Report.Debug (64, "EMIT SCOPE INIT", this, id,
539 Scope, scope_instance, ec);
541 ec.ig.Emit (OpCodes.Nop);
542 ec.ig.Emit (OpCodes.Ldc_I4, id);
543 ec.ig.Emit (OpCodes.Pop);
544 ec.ig.Emit (OpCodes.Nop);
546 if (Scope != Scope.Host)
547 Scope.Host.EmitScopeInstance (ec);
548 else if (Scope.ScopeInstance != null)
549 ec.ig.Emit (OpCodes.Ldarg_0);
550 EmitScopeConstructor (ec);
551 if (Scope.ScopeInstance != null)
552 Scope.ScopeInstance.EmitAssign (ec);
554 ec.ig.Emit (OpCodes.Stloc, scope_instance);
559 public class AnonymousMethodHost : ScopeInfo
561 public AnonymousMethodHost (ToplevelBlock toplevel, TypeContainer parent,
562 GenericMethod generic, Location loc)
563 : base (toplevel, parent, generic, loc)
565 scopes = new ArrayList ();
569 TypeExpr parent_type;
570 CapturedVariableField parent_link;
571 CapturedThis this_variable;
572 Hashtable captured_params;
574 public override AnonymousMethodHost Host {
578 public virtual bool IsIterator {
579 get { return false; }
582 public AnonymousMethodHost ParentHost {
583 get { return Parent as AnonymousMethodHost; }
586 public Type ParentType {
587 get { return parent_type.Type; }
590 public Field ParentLink {
591 get { return parent_link; }
594 protected CapturedThis THIS {
595 get { return this_variable; }
598 public bool HostsParameters {
599 get { return captured_params != null; }
602 public Variable CaptureThis ()
604 if (ParentHost != null)
605 return ParentHost.CaptureThis ();
607 CheckMembersDefined ();
608 if (this_variable == null)
609 this_variable = new CapturedThis (this);
610 return this_variable;
613 public Variable GetCapturedParameter (Parameter par)
615 if (captured_params != null)
616 return (Variable) captured_params [par];
621 public bool IsParameterCaptured (string name)
623 if (captured_params != null)
624 return captured_params [name] != null;
628 public Variable AddParameter (Parameter par, int idx)
630 if (captured_params == null)
631 captured_params = new Hashtable ();
633 Variable var = (Variable) captured_params [par];
635 var = new CapturedParameter (this, par, idx);
636 captured_params.Add (par, var);
637 par.IsCaptured = true;
643 public void AddScope (ScopeInfo scope)
649 public void LinkScopes ()
655 if (ParentHost != null)
656 ParentHost.LinkScopes ();
658 foreach (ScopeInfo si in scopes) {
660 throw new InternalErrorException ();
661 if (si.DefineType () == null)
662 throw new InternalErrorException ();
666 protected override ScopeInitializer CreateScopeInitializer ()
668 return new AnonymousMethodHostInitializer (this);
671 protected override bool DefineNestedTypes ()
673 if (Parent.IsGeneric) {
674 parent_type = new ConstructedType (
675 Parent.TypeBuilder, Parent.TypeParameters, Location);
676 parent_type = parent_type.ResolveAsTypeTerminal (this, false);
677 if ((parent_type == null) || (parent_type.Type == null))
680 parent_type = new TypeExpression (Parent.TypeBuilder, Location);
683 CompilerGeneratedClass parent = Parent as CompilerGeneratedClass;
685 parent_link = new CapturedVariableField (this, "<>parent", parent_type);
687 return base.DefineNestedTypes ();
690 protected override bool DoDefineMembers ()
692 ArrayList args = new ArrayList ();
693 if (this is IteratorHost)
694 args.Add (new Parameter (
695 TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
699 if (Parent is CompilerGeneratedClass)
700 pfield = parent_link;
702 pfield = this_variable != null ? this_variable.Field : null;
704 args.Add (new Parameter (
705 pfield.MemberType, "parent", Parameter.Modifier.NONE,
708 if (HostsParameters) {
709 foreach (CapturedParameter cp in captured_params.Values) {
710 args.Add (new Parameter (
711 cp.Field.MemberType, cp.Field.Name,
712 Parameter.Modifier.NONE, null, Location));
716 Parameter[] ctor_params = new Parameter [args.Count];
717 args.CopyTo (ctor_params, 0);
718 Constructor ctor = new Constructor (
719 this, MemberName.Name, Modifiers.PUBLIC,
720 new Parameters (ctor_params),
721 new GeneratedBaseInitializer (Location),
723 AddConstructor (ctor);
725 ctor.Block = new ToplevelBlock (null, Location);
726 ctor.Block.AddStatement (new TheCtor (this));
728 return base.DoDefineMembers ();
731 protected virtual void EmitScopeConstructor (EmitContext ec)
733 int pos = (this is IteratorHost) ? 2 : 1;
736 if (Parent is CompilerGeneratedClass)
737 pfield = parent_link;
739 pfield = this_variable != null ? this_variable.Field : null;
741 if (pfield != null) {
742 ec.ig.Emit (OpCodes.Ldarg_0);
743 ec.ig.Emit (OpCodes.Ldarg, pos);
744 ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
748 if (HostsParameters) {
749 foreach (CapturedParameter cp in captured_params.Values) {
750 ec.ig.Emit (OpCodes.Ldarg_0);
751 ParameterReference.EmitLdArg (ec.ig, pos++);
752 ec.ig.Emit (OpCodes.Stfld, cp.Field.FieldBuilder);
757 protected class TheCtor : Statement
759 AnonymousMethodHost host;
761 public TheCtor (AnonymousMethodHost host)
766 public override bool Resolve (EmitContext ec)
771 protected override void DoEmit (EmitContext ec)
773 host.EmitScopeConstructor (ec);
777 protected class AnonymousMethodHostInitializer : ScopeInitializer
779 AnonymousMethodHost host;
781 public AnonymousMethodHostInitializer (AnonymousMethodHost host)
787 public AnonymousMethodHost Host {
791 protected override bool DoResolveInternal (EmitContext ec)
793 Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
794 this, Host, Host.ParentType, loc);
796 if (Host.THIS != null) {
797 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
798 ec.ContainerType, type, Host.THIS.Field.Name, loc);
800 throw new InternalErrorException ();
802 fe.InstanceExpression = this;
803 Host.THIS.FieldInstance = fe;
807 // Copy the parameter values, if any
809 if (Host.HostsParameters) {
810 foreach (CapturedParameter cp in Host.captured_params.Values) {
811 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
812 ec.ContainerType, type, cp.Field.Name, loc);
814 throw new InternalErrorException ();
816 fe.InstanceExpression = this;
817 cp.FieldInstance = fe;
821 return base.DoResolveInternal (ec);
824 protected virtual bool IsGetEnumerator {
825 get { return false; }
828 protected override void EmitScopeConstructor (EmitContext ec)
830 if (host.THIS != null) {
831 ec.ig.Emit (OpCodes.Ldarg_0);
833 ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
834 else if (host.THIS.Type.IsValueType)
835 Expression.LoadFromPtr (ec.ig, host.THIS.Type);
836 } else if (host.ParentLink != null)
837 ec.ig.Emit (OpCodes.Ldarg_0);
839 if (Host.HostsParameters) {
840 foreach (CapturedParameter cp in Host.captured_params.Values) {
841 EmitParameterReference (ec, cp);
845 base.EmitScopeConstructor (ec);
851 public interface IAnonymousContainer
857 GenericMethod GenericMethod {
861 AnonymousMethodHost RootScope {
870 public interface IAnonymousHost
873 // Invoked if a yield statement is found in the body
878 // Invoked if an anonymous method is found in the body
880 void AddAnonymousMethod (AnonymousMethodExpression anonymous);
883 public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
885 public readonly AnonymousMethodExpression Parent;
886 public readonly TypeContainer Host;
887 public readonly Parameters Parameters;
889 public ToplevelBlock Block;
890 protected AnonymousMethod anonymous;
892 protected readonly Block container;
893 protected readonly GenericMethod generic;
895 public Block Container {
896 get { return container; }
899 public GenericMethod GenericMethod {
900 get { return generic; }
903 public AnonymousMethod AnonymousMethod {
904 get { return anonymous; }
907 public AnonymousMethodHost RootScope {
908 get { return root_scope; }
911 public AnonymousMethodExpression (AnonymousMethodExpression parent,
912 GenericMethod generic, TypeContainer host,
913 Parameters parameters, Block container,
916 this.Parent = parent;
917 this.generic = parent != null ? null : generic;
919 this.Parameters = parameters;
920 this.container = container;
923 Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host,
927 parent.AddAnonymousMethod (this);
931 AnonymousMethodHost root_scope;
933 static int next_index;
935 void IAnonymousHost.SetYields ()
937 throw new InvalidOperationException ();
940 public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
942 if (children == null)
943 children = new ArrayList ();
944 children.Add (anonymous);
947 public bool CreateAnonymousHelpers ()
949 Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
950 this, Host, container, loc);
952 if (container != null)
953 root_scope = container.Toplevel.CreateAnonymousMethodHost (Host);
955 if (children != null) {
956 foreach (AnonymousMethodExpression child in children) {
957 if (!child.CreateAnonymousHelpers ())
965 public override string ExprClassName {
967 return "anonymous method";
971 void Error_ParameterMismatch (Type t)
973 Report.Error (1661, loc, "Anonymous method could not be converted to delegate `" +
974 "{0}' since there is a parameter mismatch",
975 TypeManager.CSharpName (t));
978 public bool ImplicitStandardConversionExists (Type delegate_type)
980 if (Parameters == null)
983 MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
984 Host.TypeBuilder, delegate_type, loc);
985 MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
986 ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
988 if (Parameters.Count != invoke_pd.Count)
991 for (int i = 0; i < Parameters.Count; ++i) {
992 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i))
999 // Returns true if this anonymous method can be implicitly
1000 // converted to the delegate type `delegate_type'
1002 public Expression Compatible (EmitContext ec, Type delegate_type)
1004 if (anonymous != null)
1005 return anonymous.AnonymousDelegate;
1007 if (!ec.IsAnonymousMethodAllowed) {
1008 Report.Error (1706, loc,
1009 "Anonymous methods are not allowed in the " +
1010 "attribute declaration");
1014 if (!TypeManager.IsDelegateType (delegate_type)){
1015 Report.Error (1660, loc,
1016 "Cannot convert anonymous method block to type " +
1017 "`{0}' because it is not a delegate type",
1018 TypeManager.CSharpName (delegate_type));
1023 // At this point its the first time we know the return type that is
1024 // needed for the anonymous method. We create the method here.
1027 MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1028 ec.ContainerType, delegate_type, loc);
1029 MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1030 ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
1032 Parameters parameters;
1033 if (Parameters == null) {
1035 // We provide a set of inaccessible parameters
1037 Parameter [] fixedpars = new Parameter [invoke_pd.Count];
1039 for (int i = 0; i < invoke_pd.Count; i++) {
1040 Parameter.Modifier i_mod = invoke_pd.ParameterModifier (i);
1041 if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1042 Report.Error (1688, loc, "Cannot convert anonymous " +
1043 "method block without a parameter list " +
1044 "to delegate type `{0}' because it has " +
1045 "one or more `out' parameters.",
1046 TypeManager.CSharpName (delegate_type));
1049 fixedpars [i] = new Parameter (
1050 invoke_pd.ParameterType (i), "+" + (++next_index),
1051 invoke_pd.ParameterModifier (i), null, loc);
1054 parameters = new Parameters (fixedpars);
1055 if (!parameters.Resolve (ec))
1058 if (Parameters.Count != invoke_pd.Count) {
1059 Report.SymbolRelatedToPreviousError (delegate_type);
1060 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1061 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1062 Error_ParameterMismatch (delegate_type);
1066 for (int i = 0; i < Parameters.Count; ++i) {
1067 Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1068 if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1069 if (p_mod == Parameter.Modifier.NONE)
1070 Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1071 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1073 Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1074 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1075 Error_ParameterMismatch (delegate_type);
1079 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1080 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1082 TypeManager.CSharpName (Parameters.ParameterType (i)),
1083 TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1084 Error_ParameterMismatch (delegate_type);
1089 parameters = Parameters;
1093 // Second: the return type of the delegate must be compatible with
1094 // the anonymous type. Instead of doing a pass to examine the block
1095 // we satisfy the rule by setting the return type on the EmitContext
1096 // to be the delegate type return type.
1099 //MethodBuilder builder = method_data.MethodBuilder;
1100 //ILGenerator ig = builder.GetILGenerator ();
1102 Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1103 Container, Block, invoke_mb.ReturnType, delegate_type,
1104 TypeManager.IsGenericType (delegate_type), loc);
1106 anonymous = new AnonymousMethod (
1107 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
1108 GenericMethod, parameters, Container, Block, invoke_mb.ReturnType,
1109 delegate_type, loc);
1111 if (!anonymous.Resolve (ec))
1114 return anonymous.AnonymousDelegate;
1117 public override Expression DoResolve (EmitContext ec)
1120 // Set class type, set type
1123 eclass = ExprClass.Value;
1126 // This hack means `The type is not accessible
1127 // anywhere', we depend on special conversion
1130 type = TypeManager.anonymous_method_type;
1132 if ((Parameters != null) && !Parameters.Resolve (ec))
1138 public override void Emit (EmitContext ec)
1140 // nothing, as we only exist to not do anything.
1143 public bool IsIterator {
1144 get { return false; }
1148 public abstract class AnonymousContainer : IAnonymousContainer
1150 // Used to generate unique method names.
1151 protected static int anonymous_method_count;
1153 public readonly Location Location;
1155 // An array list of AnonymousMethodParameter or null
1156 public readonly Parameters Parameters;
1159 // The block that makes up the body for the anonymous mehtod
1161 public readonly ToplevelBlock Block;
1163 public readonly int ModFlags;
1164 public Type ReturnType;
1165 public readonly TypeContainer Host;
1168 // The implicit method we create
1170 protected Method method;
1171 protected EmitContext aec;
1173 // The emit context for the anonymous method
1174 protected bool unreachable;
1175 protected readonly Block container;
1176 protected readonly GenericMethod generic;
1179 // Points to our container anonymous method if its present
1181 public readonly AnonymousContainer ContainerAnonymousMethod;
1183 protected AnonymousContainer (AnonymousContainer parent, TypeContainer host,
1184 GenericMethod generic, Parameters parameters,
1185 Block container, ToplevelBlock block,
1186 Type return_type, int mod, Location loc)
1188 this.ContainerAnonymousMethod = parent;
1189 this.ReturnType = return_type;
1190 this.ModFlags = mod;
1193 this.container = container;
1194 this.generic = parent != null ? null : generic;
1195 this.Parameters = parameters;
1197 this.Location = loc;
1200 public Method Method {
1201 get { return method; }
1204 public abstract AnonymousMethodHost RootScope {
1208 public abstract string GetSignatureForError ();
1210 public virtual bool Resolve (EmitContext ec)
1212 Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1213 RootScope, Parameters, ec.IsStatic);
1215 if (ReturnType != null) {
1216 TypeExpr return_type_expr;
1217 if (RootScope != null)
1218 return_type_expr = RootScope.InflateType (ReturnType);
1220 return_type_expr = new TypeExpression (ReturnType, Location);
1221 return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
1222 if ((return_type_expr == null) || (return_type_expr.Type == null))
1224 ReturnType = return_type_expr.Type;
1227 aec = new EmitContext (
1228 ec.ResolveContext, ec.TypeContainer,
1229 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1230 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1231 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1233 aec.CurrentAnonymousMethod = this;
1234 aec.IsFieldInitializer = ec.IsFieldInitializer;
1235 aec.IsStatic = ec.IsStatic;
1237 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1238 RootScope, Parameters, Block);
1241 if (!aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable))
1244 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #3", this, ec, aec, Block);
1246 method = DoCreateMethodHost (ec);
1248 if (RootScope != null)
1251 if (!method.ResolveMembers ())
1253 return method.Define ();
1256 protected abstract Method DoCreateMethodHost (EmitContext ec);
1258 public Block Container {
1259 get { return container; }
1262 public GenericMethod GenericMethod {
1263 get { return generic; }
1266 public abstract bool IsIterator {
1270 protected class AnonymousMethodMethod : Method
1272 public AnonymousContainer AnonymousMethod;
1274 public AnonymousMethodMethod (AnonymousContainer am, GenericMethod generic,
1275 TypeExpr return_type, int mod, MemberName name,
1276 Parameters parameters)
1277 : base (am.RootScope != null ? am.RootScope : am.Host,
1278 generic, return_type, mod, false, name, parameters, null)
1280 this.AnonymousMethod = am;
1282 if (am.RootScope != null) {
1283 am.RootScope.CheckMembersDefined ();
1284 am.RootScope.AddMethod (this);
1286 ModFlags |= Modifiers.STATIC;
1287 am.Host.AddMethod (this);
1292 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1294 EmitContext aec = AnonymousMethod.aec;
1301 public class AnonymousMethod : AnonymousContainer
1303 public readonly Type DelegateType;
1306 // The value return by the Compatible call, this ensure that
1307 // the code works even if invoked more than once (Resolve called
1308 // more than once, due to the way Convert.ImplicitConversion works
1310 Expression anonymous_delegate;
1311 AnonymousMethodHost root_scope;
1313 public AnonymousMethod (AnonymousMethod parent, AnonymousMethodHost root_scope,
1314 TypeContainer host, GenericMethod generic,
1315 Parameters parameters, Block container,
1316 ToplevelBlock block, Type return_type, Type delegate_type,
1318 : base (parent, host, generic, parameters, container, block,
1319 return_type, 0, loc)
1321 this.DelegateType = delegate_type;
1322 this.root_scope = root_scope;
1325 public override AnonymousMethodHost RootScope {
1326 get { return root_scope; }
1329 public override bool IsIterator {
1330 get { return false; }
1333 public Expression AnonymousDelegate {
1334 get { return anonymous_delegate; }
1337 public override string GetSignatureForError ()
1339 return TypeManager.CSharpName (DelegateType);
1343 // Creates the host for the anonymous method
1345 protected override Method DoCreateMethodHost (EmitContext ec)
1347 string name = "<>c__AnonymousMethod" + anonymous_method_count++;
1348 MemberName member_name;
1350 GenericMethod generic_method = null;
1352 if (TypeManager.IsGenericType (DelegateType)) {
1353 TypeArguments args = new TypeArguments (Location);
1355 Type dt = DelegateType.GetGenericTypeDefinition ();
1357 Type[] tparam = TypeManager.GetTypeArguments (dt);
1358 for (int i = 0; i < tparam.Length; i++)
1359 args.Add (new SimpleName (tparam [i].Name, Location));
1361 member_name = new MemberName (name, args, Location);
1363 generic_method = new GenericMethod (
1364 RootScope.NamespaceEntry, RootScope, member_name,
1365 new TypeExpression (ReturnType, Location), Parameters);
1367 generic_method.SetParameterInfo (null);
1370 member_name = new MemberName (name, Location);
1372 return new AnonymousMethodMethod (
1373 this, generic_method, new TypeExpression (ReturnType, Location),
1374 Modifiers.INTERNAL, member_name, Parameters);
1377 public override bool Resolve (EmitContext ec)
1379 if (!base.Resolve (ec))
1382 anonymous_delegate = new AnonymousDelegate (
1383 this, DelegateType, Location).Resolve (ec);
1384 if (anonymous_delegate == null)
1390 public MethodInfo GetMethodBuilder (EmitContext ec)
1392 MethodInfo builder = method.MethodBuilder;
1393 if ((RootScope != null) && RootScope.IsGeneric) {
1394 Type scope_type = RootScope.GetScopeType (ec);
1395 if (scope_type == null)
1396 throw new InternalErrorException ();
1398 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1399 ec.ContainerType, scope_type, builder.Name, Location);
1402 throw new InternalErrorException ();
1403 builder = (MethodInfo) mg.Methods [0];
1407 if (!DelegateType.IsGenericType)
1410 Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1411 return builder.MakeGenericMethod (targs);
1417 public static void Error_AddressOfCapturedVar (string name, Location loc)
1419 Report.Error (1686, loc,
1420 "Local variable `{0}' or its members cannot have their " +
1421 "address taken and be used inside an anonymous method block",
1427 // This will emit the code for the delegate, as well delegate creation on the host
1429 public class AnonymousDelegate : DelegateCreation {
1432 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1439 public override Expression DoResolve (EmitContext ec)
1441 eclass = ExprClass.Value;
1446 public override void Emit (EmitContext ec)
1449 // Now emit the delegate creation.
1451 if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1452 delegate_instance_expression = am.RootScope.GetScopeInitializer (ec);
1454 if (delegate_instance_expression == null)
1455 throw new InternalErrorException ();
1458 Expression ml = Expression.MemberLookup (
1459 ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
1460 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
1463 constructor_method = ((MethodGroupExpr) ml).Methods [0];
1464 delegate_method = am.GetMethodBuilder (ec);