2 // anonymous.cs: Support for anonymous methods
5 // Miguel de Icaza (miguel@ximain.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2003-2008 Novell, Inc.
11 // TODO: Ideally, we should have the helper classes emited as a hierarchy to map
12 // their nesting, and have the visibility set to private, instead of NestedAssembly
19 using System.Collections;
20 using System.Reflection;
21 using System.Reflection.Emit;
23 namespace Mono.CSharp {
25 public abstract class CompilerGeneratedClass : Class
27 GenericMethod generic_method;
28 static int next_index = 0;
30 private static MemberName MakeProxyName (GenericMethod generic, Location loc)
32 string name = MakeName (null, "CompilerGenerated");
33 if (generic != null) {
34 TypeArguments args = new TypeArguments (loc);
35 foreach (TypeParameter tparam in generic.CurrentTypeParameters)
36 args.Add (new SimpleName (tparam.Name, loc));
37 return new MemberName (name, args, loc);
39 return new MemberName (name, loc);
42 public static string MakeName (string host, string prefix)
44 return "<" + host + ">c__" + prefix + next_index++;
47 public static void Reset ()
52 protected CompilerGeneratedClass (DeclSpace parent,
53 MemberName name, int mod, Location loc) :
54 base (parent.NamespaceEntry, parent, name, mod | Modifiers.COMPILER_GENERATED, null)
56 parent.PartialContainer.AddCompilerGeneratedClass (this);
59 protected CompilerGeneratedClass (DeclSpace parent, GenericMethod generic,
60 int mod, Location loc)
61 : this (parent, MakeProxyName (generic, loc), mod, loc)
63 this.generic_method = generic;
65 if (generic != null) {
66 ArrayList list = new ArrayList ();
67 foreach (TypeParameter tparam in generic.TypeParameters) {
68 if (tparam.Constraints != null)
69 list.Add (tparam.Constraints.Clone ());
71 SetParameterInfo (list);
76 protected override bool DefineNestedTypes ()
78 RootContext.RegisterCompilerGeneratedType (TypeBuilder);
79 return base.DefineNestedTypes ();
82 protected override bool DoDefineMembers ()
84 members_defined = true;
86 if (!base.DoDefineMembers ())
89 if (CompilerGenerated != null) {
90 foreach (CompilerGeneratedClass c in CompilerGenerated) {
91 if (!c.DefineMembers ())
92 throw new InternalErrorException ();
99 protected override bool DoResolveMembers ()
101 if (CompilerGenerated != null) {
102 foreach (CompilerGeneratedClass c in CompilerGenerated) {
103 if (!c.ResolveMembers ())
108 return base.DoResolveMembers ();
111 public GenericMethod GenericMethod {
112 get { return generic_method; }
115 public Parameters InflateParameters (Parameters ps)
117 if (generic_method == null)
124 Parameter[] inflated_params = new Parameter [n];
125 Type[] inflated_types = new Type [n];
127 for (int i = 0; i < n; ++i) {
128 Parameter p = ps [i];
129 Type it = InflateType (p.ExternalType ()).ResolveAsTypeTerminal (this, false).Type;
130 inflated_types [i] = it;
131 inflated_params [i] = new Parameter (it, p.Name, p.ModFlags, p.OptAttributes, p.Location);
133 return Parameters.CreateFullyResolved (inflated_params, inflated_types);
136 public TypeExpr InflateType (Type it)
139 if (generic_method == null)
140 return new TypeExpression (it, Location);
142 if (it.IsGenericParameter && (it.DeclaringMethod != null)) {
143 int pos = it.GenericParameterPosition;
144 it = CurrentTypeParameters [pos].Type;
145 } else if (it.IsGenericType) {
146 Type[] args = it.GetGenericArguments ();
148 TypeArguments inflated = new TypeArguments (Location);
149 foreach (Type t in args)
150 inflated.Add (InflateType (t));
152 return new ConstructedType (it, inflated, Location);
153 } else if (it.IsArray) {
154 TypeExpr et_expr = InflateType (it.GetElementType ());
155 int rank = it.GetArrayRank ();
157 Type et = et_expr.ResolveAsTypeTerminal (this, false).Type;
158 it = et.MakeArrayType (rank);
162 return new TypeExpression (it, Location);
165 public Field CaptureVariable (string name, TypeExpr type)
168 throw new InternalErrorException ("Helper class already defined!");
170 throw new ArgumentNullException ();
172 return new CapturedVariableField (this, name, type);
175 bool members_defined;
177 internal void CheckMembersDefined ()
180 throw new InternalErrorException ("Helper class already defined!");
183 protected class CapturedVariableField : Field
185 public CapturedVariableField (CompilerGeneratedClass helper, string name,
187 : base (helper, type, Modifiers.INTERNAL, name, null, helper.Location)
189 helper.AddField (this);
194 public class ScopeInfo : CompilerGeneratedClass
196 protected readonly RootScopeInfo RootScope;
197 new public readonly DeclSpace Parent;
198 public readonly int ID = ++next_id;
199 public readonly Block ScopeBlock;
200 protected ScopeInitializer scope_initializer;
202 readonly Hashtable locals = new Hashtable ();
203 readonly Hashtable captured_scopes = new Hashtable ();
204 Hashtable captured_params;
208 public static ScopeInfo CreateScope (Block block)
210 ToplevelBlock toplevel = block.Toplevel;
211 AnonymousContainer ac = toplevel.AnonymousContainer;
213 Report.Debug (128, "CREATE SCOPE", block, block.ScopeInfo, toplevel, ac);
216 return new ScopeInfo (block, toplevel.RootScope.Parent,
217 toplevel.RootScope.GenericMethod);
219 Report.Debug (128, "CREATE SCOPE #1", ac, ac.Host, ac.Scope, ac.Block,
224 ScopeInfo parent = null;
226 for (b = ac.Block; b != null; b = b.Parent) {
227 if (b.ScopeInfo != null) {
228 parent = b.ScopeInfo;
233 Report.Debug (128, "CREATE SCOPE #2", parent);
235 ScopeInfo new_scope = new ScopeInfo (block, parent, null);
237 Report.Debug (128, "CREATE SCOPE #3", new_scope);
242 private static int default_modflags (DeclSpace parent)
244 return parent is CompilerGeneratedClass ? Modifiers.PUBLIC : Modifiers.PRIVATE;
247 protected ScopeInfo (Block block, DeclSpace parent, GenericMethod generic)
248 : base (parent, generic, default_modflags (parent), block.StartLocation)
251 RootScope = block.Toplevel.RootScope;
254 Report.Debug (128, "NEW SCOPE", this, block,
255 block.Parent, block.Toplevel);
257 RootScope.AddScope (this);
260 protected ScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
261 GenericMethod generic, Location loc)
262 : base (parent, generic, default_modflags (parent), loc)
265 RootScope = (RootScopeInfo) this;
266 ScopeBlock = toplevel;
268 Report.Debug (128, "NEW ROOT SCOPE", this, toplevel, loc);
271 protected CapturedScope[] CapturedScopes {
273 CapturedScope[] list = new CapturedScope [captured_scopes.Count];
274 captured_scopes.Values.CopyTo (list, 0);
279 protected CapturedVariable GetCapturedScope (ScopeInfo scope)
281 return (CapturedVariable) captured_scopes [scope];
284 protected void EmitScopeInstance (EmitContext ec)
286 if (scope_initializer == null) {
288 // This is needed if someone overwrites the Emit method
289 // of Statement and manually calls Block.Emit without
290 // this snippet first:
292 // ec.EmitScopeInitFromBlock (The_Block);
293 // The_Block.Emit (ec);
295 throw new InternalErrorException ();
298 scope_initializer.Emit (ec);
301 public ExpressionStatement GetScopeInitializer (EmitContext ec)
303 Report.Debug (128, "GET SCOPE INITIALIZER",
304 this, GetType (), scope_initializer, ScopeBlock);
306 if (scope_initializer == null) {
307 scope_initializer = CreateScopeInitializer ();
308 if (scope_initializer.Resolve (ec) == null)
309 throw new InternalErrorException ();
312 return scope_initializer;
315 public Type GetScopeType (EmitContext ec)
320 TypeArguments targs = new TypeArguments (Location);
322 if (ec.DeclContainer.Parent.IsGeneric)
323 foreach (TypeParameter t in ec.DeclContainer.Parent.TypeParameters)
324 targs.Add (new TypeParameterExpr (t, Location));
325 if (ec.DeclContainer.IsGeneric)
326 foreach (TypeParameter t in ec.DeclContainer.CurrentTypeParameters)
327 targs.Add (new TypeParameterExpr (t, Location));
329 Report.Debug (128, "GET SCOPE TYPE", this, TypeBuilder, targs,
330 ec.DeclContainer, ec.DeclContainer.GetType (),
331 ec.DeclContainer.Parent.Name);
333 TypeExpr te = new ConstructedType (TypeBuilder, targs, Location);
334 te = te.ResolveAsTypeTerminal (ec, false);
335 if ((te == null) || (te.Type == null))
340 protected override bool DoDefineMembers ()
342 Report.Debug (64, "SCOPE INFO DEFINE MEMBERS", this, GetType (), IsGeneric,
343 Parent.IsGeneric, GenericMethod);
345 foreach (CapturedScope child in CapturedScopes) {
346 if (!child.DefineMembers ())
350 return base.DoDefineMembers ();
353 protected override bool DoResolveMembers ()
355 Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
356 Parent.IsGeneric, GenericMethod);
358 return base.DoResolveMembers ();
361 public Variable CaptureScope (ScopeInfo child)
363 CheckMembersDefined ();
364 Report.Debug (128, "CAPTURE SCOPE", this, GetType (), child, child.GetType ());
366 throw new InternalErrorException ();
367 CapturedScope captured = (CapturedScope) captured_scopes [child];
368 if (captured == null) {
369 captured = new CapturedScope (this, child);
370 captured_scopes.Add (child, captured);
375 public Variable AddLocal (LocalInfo local)
377 Report.Debug (128, "CAPTURE LOCAL", this, local);
378 Variable var = (Variable) locals [local];
380 var = new CapturedLocal (this, local);
381 locals.Add (local, var);
382 local.IsCaptured = true;
387 public Variable GetCapturedVariable (LocalInfo local)
389 return (Variable) locals [local];
392 public bool HostsParameters {
393 get { return captured_params != null; }
396 public Variable GetCapturedParameter (Parameter par)
398 if (captured_params != null)
399 return (Variable) captured_params [par];
404 public Variable AddParameter (Parameter par, int idx)
406 if (captured_params == null)
407 captured_params = new Hashtable ();
409 Variable var = (Variable) captured_params [par];
411 var = new CapturedParameter (this, par, idx);
412 captured_params.Add (par, var);
413 par.IsCaptured = true;
419 public override void EmitType ()
421 SymbolWriter.DefineAnonymousScope (ID);
422 foreach (CapturedLocal local in locals.Values)
423 local.EmitSymbolInfo ();
425 if (captured_params != null) {
426 foreach (CapturedParameter param in captured_params.Values)
427 param.EmitSymbolInfo ();
430 foreach (CapturedScope scope in CapturedScopes) {
431 scope.EmitSymbolInfo ();
437 protected string MakeFieldName (string local_name)
439 return "<" + ID + ":" + local_name + ">";
442 protected virtual ScopeInitializer CreateScopeInitializer ()
444 return new ScopeInitializer (this);
447 protected abstract class CapturedVariable : Variable
449 public readonly ScopeInfo Scope;
450 public readonly string Name;
452 public FieldExpr FieldInstance;
453 protected Field field;
455 protected CapturedVariable (ScopeInfo scope, string name)
461 protected CapturedVariable (ScopeInfo scope, string name, Type type)
464 this.field = scope.CaptureVariable (
465 scope.MakeFieldName (name), scope.RootScope.InflateType (type));
469 get { return field; }
472 public override Type Type {
473 get { return Field.MemberType; }
476 public override bool HasInstance {
480 public override bool NeedsTemporary {
484 protected FieldInfo GetField (EmitContext ec)
486 if ((ec.CurrentBlock != null) &&
487 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel))
488 return Field.FieldBuilder;
490 return FieldInstance.FieldInfo;
493 public abstract void EmitSymbolInfo ();
495 public override void EmitInstance (EmitContext ec)
497 if ((ec.CurrentAnonymousMethod != null) &&
498 (ec.CurrentAnonymousMethod.Scope == Scope)) {
499 ec.ig.Emit (OpCodes.Ldarg_0);
503 Scope.EmitScopeInstance (ec);
506 public override void Emit (EmitContext ec)
508 ec.ig.Emit (OpCodes.Ldfld, GetField (ec));
511 public override void EmitAssign (EmitContext ec)
513 ec.ig.Emit (OpCodes.Stfld, GetField (ec));
516 public override void EmitAddressOf (EmitContext ec)
518 ec.ig.Emit (OpCodes.Ldflda, GetField (ec));
522 protected class CapturedParameter : CapturedVariable {
523 public readonly Parameter Parameter;
524 public readonly int Idx;
526 public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
527 : base (scope, par.Name, par.ParameterType)
529 this.Parameter = par;
533 public override void EmitSymbolInfo ()
535 SymbolWriter.DefineCapturedParameter (
536 Scope.ID, Parameter.Name, Field.Name);
539 public override string ToString ()
541 return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
542 Parameter.Name, Idx);
546 protected class CapturedLocal : CapturedVariable {
547 public readonly LocalInfo Local;
549 public CapturedLocal (ScopeInfo scope, LocalInfo local)
550 : base (scope, local.Name, local.VariableType)
555 public override void EmitSymbolInfo ()
557 SymbolWriter.DefineCapturedLocal (
558 Scope.ID, Local.Name, Field.Name);
561 public override string ToString ()
563 return String.Format ("{0} ({1}:{2})", GetType (), Field,
568 protected class CapturedThis : CapturedVariable {
569 public CapturedThis (RootScopeInfo host)
570 : base (host, "<>THIS", host.ParentType)
573 public override void EmitSymbolInfo ()
575 SymbolWriter.DefineCapturedThis (Scope.ID, Field.Name);
579 protected class CapturedScope : CapturedVariable {
580 public readonly ScopeInfo ChildScope;
582 public CapturedScope (ScopeInfo root, ScopeInfo child)
583 : base (root, "scope" + child.ID)
585 this.ChildScope = child;
588 public override void EmitSymbolInfo ()
590 SymbolWriter.DefineCapturedScope (Scope.ID, ChildScope.ID, Field.Name);
593 public bool DefineMembers ()
595 Type type = ChildScope.IsGeneric ?
596 ChildScope.CurrentType : ChildScope.TypeBuilder;
597 Report.Debug (128, "CAPTURED SCOPE DEFINE MEMBERS", this, Scope,
598 ChildScope, Name, type);
600 throw new InternalErrorException ();
601 field = Scope.CaptureVariable (
602 Scope.MakeFieldName (Name), Scope.InflateType (type));
606 public override string ToString ()
608 return String.Format ("CapturedScope ({1} captured in {0})",
613 static void DoPath (StringBuilder sb, ScopeInfo start)
615 sb.Append ((start.ID).ToString ());
618 public override string ToString ()
620 StringBuilder sb = new StringBuilder ();
626 return sb.ToString ();
629 protected class ScopeInitializer : ExpressionStatement
632 CapturedVariable captured_scope;
633 LocalBuilder scope_instance;
634 ConstructorInfo scope_ctor;
638 public ScopeInitializer (ScopeInfo scope)
641 this.loc = scope.Location;
642 eclass = ExprClass.Value;
645 public ScopeInfo Scope {
646 get { return scope; }
649 public override Expression CreateExpressionTree (EmitContext ec)
651 throw new NotSupportedException ("ET");
654 public override Expression DoResolve (EmitContext ec)
656 if (scope_ctor != null)
659 Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
660 ec, ec.CurrentBlock);
662 type = Scope.GetScopeType (ec);
664 throw new InternalErrorException ();
666 if (!DoResolveInternal (ec))
667 throw new InternalErrorException ();
672 protected virtual bool DoResolveInternal (EmitContext ec)
674 MethodGroupExpr mg = (MethodGroupExpr) MemberLookupFinal (
675 ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
676 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
678 throw new InternalErrorException ();
680 scope_ctor = (ConstructorInfo) mg.Methods [0];
682 Report.Debug (128, "RESOLVE THE INIT", this, Scope, Scope.RootScope,
683 Scope.RootScope.GetType ());
685 ScopeInfo host = Scope.RootScope;
686 if ((Scope != host) && (Scope.RootScope is IteratorHost)) {
687 captured_scope = host.GetCapturedScope (Scope);
688 Type root = host.GetScopeType (ec);
689 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
690 type, root, captured_scope.Field.Name, loc);
692 throw new InternalErrorException ();
694 fe.InstanceExpression = this;
695 captured_scope.FieldInstance = fe;
697 Report.Debug (128, "RESOLVE THE INIT #1", this,
700 scope_instance = ec.ig.DeclareLocal (type);
701 if (!Scope.RootScope.IsIterator)
702 SymbolWriter.DefineScopeVariable (Scope.ID, scope_instance);
705 foreach (CapturedLocal local in Scope.locals.Values) {
706 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
707 ec.ContainerType, type, local.Field.Name, loc);
708 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
709 Scope, ec, ec.ContainerType, type,
710 local.Field, local.Field.Name, loc, fe);
712 throw new InternalErrorException ();
714 fe.InstanceExpression = this;
715 local.FieldInstance = fe;
718 if (Scope.HostsParameters) {
719 foreach (CapturedParameter cp in Scope.captured_params.Values) {
720 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
721 ec.ContainerType, type, cp.Field.Name, loc);
723 throw new InternalErrorException ();
725 fe.InstanceExpression = this;
726 cp.FieldInstance = fe;
730 foreach (CapturedScope scope in Scope.CapturedScopes) {
731 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
732 ec.ContainerType, type, scope.Field.Name, loc);
733 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #3", this, Scope,
734 scope, ec, ec.ContainerType, type,
735 scope.Field, scope.Field.Name, loc, fe);
737 throw new InternalErrorException ();
739 fe.InstanceExpression = this;
740 scope.FieldInstance = fe;
746 protected virtual void EmitParameterReference (EmitContext ec,
747 CapturedParameter cp)
749 int extra = ec.MethodIsStatic ? 0 : 1;
750 ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
756 protected virtual void DoEmit (EmitContext ec)
758 if ((ec.CurrentBlock != null) &&
759 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)) {
760 ec.ig.Emit (OpCodes.Ldarg_0);
762 if (ec.CurrentAnonymousMethod != null) {
763 ScopeInfo host = ec.CurrentAnonymousMethod.Scope;
764 Variable captured = host.GetCapturedScope (scope);
765 Report.Debug (128, "EMIT SCOPE INSTANCE #2",
766 ec.CurrentAnonymousMethod, host,
768 if (captured != null)
771 } else if (scope_instance != null)
772 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
774 Report.Debug (128, "DO EMIT", this, Scope, ec,
775 scope_instance, captured_scope);
776 captured_scope.EmitInstance (ec);
777 captured_scope.Emit (ec);
781 protected void DoEmitInstance (EmitContext ec)
783 Report.Debug (128, "DO EMIT INSTANCE", this, Scope, ec,
784 scope_instance, captured_scope);
786 if (scope_instance != null)
787 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
789 captured_scope.EmitInstance (ec);
792 protected virtual void EmitScopeConstructor (EmitContext ec)
794 ec.ig.Emit (OpCodes.Newobj, scope_ctor);
797 public override void Emit (EmitContext ec)
800 throw new InternalErrorException (
801 "Scope {0} not initialized yet", scope);
806 public override void EmitStatement (EmitContext ec)
811 DoEmitStatement (ec);
815 protected virtual void DoEmitStatement (EmitContext ec)
817 Report.Debug (128, "EMIT SCOPE INITIALIZER STATEMENT", this, id,
818 Scope, scope_instance, ec);
820 ec.ig.Emit (OpCodes.Nop);
821 ec.ig.Emit (OpCodes.Ldc_I4, id);
822 ec.ig.Emit (OpCodes.Pop);
823 ec.ig.Emit (OpCodes.Nop);
825 if (scope_instance == null)
826 ec.ig.Emit (OpCodes.Ldarg_0);
827 EmitScopeConstructor (ec);
828 if (scope_instance != null)
829 ec.ig.Emit (OpCodes.Stloc, scope_instance);
831 captured_scope.EmitAssign (ec);
833 if (Scope.HostsParameters) {
834 foreach (CapturedParameter cp in Scope.captured_params.Values) {
835 Report.Debug (128, "EMIT SCOPE INIT #6", this,
836 ec, ec.IsStatic, Scope, cp, cp.Field.Name);
838 EmitParameterReference (ec, cp);
839 ec.ig.Emit (OpCodes.Stfld, cp.FieldInstance.FieldInfo);
843 if (Scope is IteratorHost)
846 foreach (CapturedScope scope in Scope.CapturedScopes) {
847 ScopeInfo child = scope.ChildScope;
849 Report.Debug (128, "EMIT SCOPE INIT #5", this, Scope,
850 scope.Scope, scope.ChildScope);
852 ExpressionStatement init = child.GetScopeInitializer (ec);
853 init.EmitStatement (ec);
856 scope.ChildScope.EmitScopeInstance (ec);
857 scope.EmitAssign (ec);
863 public class RootScopeInfo : ScopeInfo
865 public RootScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
866 GenericMethod generic, Location loc)
867 : base (toplevel, parent, generic, loc)
869 scopes = new ArrayList ();
872 TypeExpr parent_type;
873 CapturedVariableField parent_link;
874 CapturedThis this_variable;
875 protected ArrayList scopes;
877 public virtual bool IsIterator {
878 get { return false; }
881 public RootScopeInfo ParentHost {
882 get { return Parent.PartialContainer as RootScopeInfo; }
885 public Type ParentType {
886 get { return parent_type.Type; }
889 public Field ParentLink {
890 get { return parent_link; }
893 protected CapturedThis THIS {
894 get { return this_variable; }
897 public Variable CaptureThis ()
899 if (ParentHost != null)
900 return ParentHost.CaptureThis ();
902 CheckMembersDefined ();
903 if (this_variable == null)
904 this_variable = new CapturedThis (this);
905 return this_variable;
908 public void AddScope (ScopeInfo scope)
914 public void LinkScopes ()
916 Report.Debug (128, "LINK SCOPES", this, linked, scopes);
922 if (ParentHost != null)
923 ParentHost.LinkScopes ();
925 foreach (ScopeInfo si in scopes) {
927 throw new InternalErrorException ();
928 if (si.DefineType () == null)
929 throw new InternalErrorException ();
930 if (!si.ResolveType ())
931 throw new InternalErrorException ();
934 foreach (ScopeInfo si in scopes) {
935 if (!si.ResolveMembers ())
936 throw new InternalErrorException ();
937 if (!si.DefineMembers ())
938 throw new InternalErrorException ();
942 protected override ScopeInitializer CreateScopeInitializer ()
944 return new RootScopeInitializer (this);
947 protected override bool DefineNestedTypes ()
949 if (Parent.IsGeneric) {
950 parent_type = new ConstructedType (
951 Parent.TypeBuilder, Parent.TypeParameters, Location);
952 parent_type = parent_type.ResolveAsTypeTerminal (this, false);
953 if ((parent_type == null) || (parent_type.Type == null))
956 parent_type = new TypeExpression (Parent.TypeBuilder, Location);
959 CompilerGeneratedClass parent = Parent.PartialContainer as CompilerGeneratedClass;
961 parent_link = new CapturedVariableField (this, "<>parent", parent_type);
963 return base.DefineNestedTypes ();
966 protected override bool DoDefineMembers ()
968 ArrayList args = new ArrayList ();
969 if (this is IteratorHost)
970 args.Add (new Parameter (
971 TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
975 if (Parent is CompilerGeneratedClass)
976 pfield = parent_link;
978 pfield = this_variable != null ? this_variable.Field : null;
980 args.Add (new Parameter (
981 pfield.MemberType, "parent", Parameter.Modifier.NONE,
984 Parameter[] ctor_params = new Parameter [args.Count];
985 args.CopyTo (ctor_params, 0);
986 Constructor ctor = new Constructor (
987 this, MemberName.Name, Modifiers.PUBLIC,
988 new Parameters (ctor_params),
989 new GeneratedBaseInitializer (Location),
991 AddConstructor (ctor);
993 ctor.Block = new ToplevelBlock (null, Location);
994 ctor.Block.AddStatement (new TheCtor (this));
996 return base.DoDefineMembers ();
999 protected virtual void EmitScopeConstructor (EmitContext ec)
1001 int pos = (this is IteratorHost) ? 2 : 1;
1004 if (Parent is CompilerGeneratedClass)
1005 pfield = parent_link;
1007 pfield = this_variable != null ? this_variable.Field : null;
1009 if (pfield != null) {
1010 ec.ig.Emit (OpCodes.Ldarg_0);
1011 ec.ig.Emit (OpCodes.Ldarg, pos);
1012 ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
1017 public override void EmitType ()
1021 THIS.EmitSymbolInfo ();
1024 protected class TheCtor : Statement
1028 public TheCtor (RootScopeInfo host)
1033 public override bool Resolve (EmitContext ec)
1038 protected override void DoEmit (EmitContext ec)
1040 host.EmitScopeConstructor (ec);
1044 protected class RootScopeInitializer : ScopeInitializer
1048 public RootScopeInitializer (RootScopeInfo host)
1054 public RootScopeInfo Host {
1055 get { return host; }
1058 protected override bool DoResolveInternal (EmitContext ec)
1060 Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
1061 this, Host, Host.ParentType, loc);
1063 if (Host.THIS != null) {
1064 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
1065 ec.ContainerType, type, Host.THIS.Field.Name, loc);
1067 throw new InternalErrorException ();
1069 fe.InstanceExpression = this;
1070 Host.THIS.FieldInstance = fe;
1073 return base.DoResolveInternal (ec);
1076 protected virtual bool IsGetEnumerator {
1077 get { return false; }
1080 protected override void EmitScopeConstructor (EmitContext ec)
1082 if (host.THIS != null) {
1083 ec.ig.Emit (OpCodes.Ldarg_0);
1084 if (IsGetEnumerator)
1085 ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
1086 else if (host.THIS.Type.IsValueType)
1087 Expression.LoadFromPtr (ec.ig, host.THIS.Type);
1088 } else if (host.ParentLink != null)
1089 ec.ig.Emit (OpCodes.Ldarg_0);
1091 base.EmitScopeConstructor (ec);
1097 public interface IAnonymousContainer
1103 GenericMethod GenericMethod {
1107 RootScopeInfo RootScope {
1116 public interface IAnonymousHost
1119 // Invoked if a yield statement is found in the body
1124 // Invoked if an anonymous method is found in the body
1126 void AddAnonymousMethod (AnonymousMethodExpression anonymous);
1129 public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
1131 public readonly AnonymousMethodExpression Parent;
1132 public readonly TypeContainer Host;
1133 public readonly Parameters Parameters;
1135 public ToplevelBlock Block;
1137 protected Block container;
1138 protected readonly GenericMethod generic;
1140 public Block Container {
1141 get { return container; }
1144 public GenericMethod GenericMethod {
1145 get { return generic; }
1148 public RootScopeInfo RootScope {
1149 get { return root_scope; }
1152 public AnonymousMethodExpression (AnonymousMethodExpression parent,
1153 GenericMethod generic, TypeContainer host,
1154 Parameters parameters, Block container,
1157 this.Parent = parent;
1158 this.generic = parent != null ? null : generic;
1160 this.Parameters = parameters;
1161 this.container = container;
1164 Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host,
1168 parent.AddAnonymousMethod (this);
1172 RootScopeInfo root_scope;
1174 static int next_index;
1176 void IAnonymousHost.SetYields ()
1178 throw new InvalidOperationException ();
1181 public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
1183 if (children == null)
1184 children = new ArrayList ();
1185 children.Add (anonymous);
1188 public bool CreateAnonymousHelpers ()
1190 // FIXME: this polutes expression trees implementation
1192 Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
1193 this, Host, container, loc);
1195 if (container != null)
1196 root_scope = container.Toplevel.CreateRootScope (Host);
1198 if (children != null) {
1199 foreach (AnonymousMethodExpression child in children) {
1200 if (!child.CreateAnonymousHelpers ())
1208 public override string ExprClassName {
1210 return "anonymous method";
1214 public virtual bool HasExplicitParameters {
1216 return Parameters != null;
1221 // Returns true if the body of lambda expression can be implicitly
1222 // converted to the delegate of type `delegate_type'
1224 public bool ImplicitStandardConversionExists (Type delegate_type)
1226 EmitContext ec = EmitContext.TempEc;
1227 using (ec.Set (EmitContext.Flags.ProbingMode)) {
1228 return Compatible (ec, delegate_type) != null;
1232 protected Type CompatibleChecks (EmitContext ec, Type delegate_type)
1234 if (!ec.IsAnonymousMethodAllowed) {
1235 Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
1239 if (TypeManager.IsDelegateType (delegate_type))
1240 return delegate_type;
1243 if (TypeManager.DropGenericTypeArguments (delegate_type) == TypeManager.expression_type) {
1244 delegate_type = TypeManager.GetTypeArguments (delegate_type) [0];
1245 if (TypeManager.IsDelegateType (delegate_type))
1246 return delegate_type;
1248 Report.Error (835, loc, "Cannot convert `{0}' to an expression tree of non-delegate type `{1}'",
1249 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
1254 Report.Error (1660, loc, "Cannot convert `{0}' to non-delegate type `{1}'",
1255 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
1259 protected bool VerifyExplicitParameters (Type delegate_type, ParameterData parameters, bool ignore_error)
1261 if (VerifyParameterCompatibility (delegate_type, parameters, ignore_error))
1265 Report.Error (1661, loc,
1266 "Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch",
1267 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
1272 protected bool VerifyParameterCompatibility (Type delegate_type, ParameterData invoke_pd, bool ignore_errors)
1274 if (Parameters.Count != invoke_pd.Count) {
1278 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1279 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1283 if (!HasExplicitParameters)
1287 for (int i = 0; i < Parameters.Count; ++i) {
1288 Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1289 if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1293 if (p_mod == Parameter.Modifier.NONE)
1294 Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1295 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1297 Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1298 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1303 Type type = invoke_pd.Types [i];
1305 // We assume that generic parameters are always inflated
1306 if (TypeManager.IsGenericParameter (type))
1309 if (TypeManager.HasElementType (type) && TypeManager.IsGenericParameter (TypeManager.GetElementType (type)))
1312 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1316 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1318 TypeManager.CSharpName (Parameters.ParameterType (i)),
1319 TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1328 // Infers type arguments based on explicit arguments
1330 public bool ExplicitTypeInference (TypeInferenceContext type_inference, Type delegate_type)
1332 if (!HasExplicitParameters)
1335 if (!TypeManager.IsDelegateType (delegate_type)) {
1337 if (TypeManager.DropGenericTypeArguments (delegate_type) != TypeManager.expression_type)
1340 delegate_type = delegate_type.GetGenericArguments () [0];
1341 if (!TypeManager.IsDelegateType (delegate_type))
1348 ParameterData d_params = TypeManager.GetDelegateParameters (delegate_type);
1349 if (d_params.Count != Parameters.Count)
1352 for (int i = 0; i < Parameters.Count; ++i) {
1353 Type itype = d_params.Types [i];
1354 if (!TypeManager.IsGenericParameter (itype)) {
1355 if (!TypeManager.HasElementType (itype))
1358 if (!TypeManager.IsGenericParameter (itype.GetElementType ()))
1361 type_inference.ExactInference (Parameters.FixedParameters[i].ParameterType, itype);
1366 public Type InferReturnType (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
1369 using (ec.Set (EmitContext.Flags.ProbingMode | EmitContext.Flags.InferReturnType)) {
1370 am = CompatibleMethod (ec, tic, GetType (), delegate_type);
1376 if (am.ReturnType == TypeManager.null_type)
1377 am.ReturnType = null;
1379 return am.ReturnType;
1383 // Returns AnonymousMethod container if this anonymous method
1384 // expression can be implicitly converted to the delegate type `delegate_type'
1386 public Expression Compatible (EmitContext ec, Type type)
1388 Type delegate_type = CompatibleChecks (ec, type);
1389 if (delegate_type == null)
1393 // At this point its the first time we know the return type that is
1394 // needed for the anonymous method. We create the method here.
1397 MethodInfo invoke_mb = Delegate.GetInvokeMethod (
1398 ec.ContainerType, delegate_type);
1399 Type return_type = TypeManager.TypeToCoreType (invoke_mb.ReturnType);
1402 Type[] g_args = delegate_type.GetGenericArguments ();
1403 if (return_type.IsGenericParameter)
1404 return_type = g_args [return_type.GenericParameterPosition];
1408 // Second: the return type of the delegate must be compatible with
1409 // the anonymous type. Instead of doing a pass to examine the block
1410 // we satisfy the rule by setting the return type on the EmitContext
1411 // to be the delegate type return type.
1414 Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1415 Container, Block, return_type, delegate_type,
1416 TypeManager.IsGenericType (delegate_type), loc);
1419 int errors = Report.Errors;
1420 AnonymousMethod am = CompatibleMethod (ec, null, return_type, delegate_type);
1421 if (am != null && delegate_type != type && errors == Report.Errors)
1422 return CreateExpressionTree (ec, delegate_type);
1425 } catch (Exception e) {
1426 throw new InternalErrorException (e, loc);
1430 protected virtual Expression CreateExpressionTree (EmitContext ec, Type delegate_type)
1432 return CreateExpressionTree (ec);
1435 public override Expression CreateExpressionTree (EmitContext ec)
1437 Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree");
1441 protected virtual Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
1443 ParameterData delegate_parameters = TypeManager.GetDelegateParameters (delegate_type);
1445 if (Parameters == null) {
1447 // We provide a set of inaccessible parameters
1449 Parameter[] fixedpars = new Parameter[delegate_parameters.Count];
1451 for (int i = 0; i < delegate_parameters.Count; i++) {
1452 Parameter.Modifier i_mod = delegate_parameters.ParameterModifier (i);
1453 if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1454 Report.Error (1688, loc, "Cannot convert anonymous " +
1455 "method block without a parameter list " +
1456 "to delegate type `{0}' because it has " +
1457 "one or more `out' parameters.",
1458 TypeManager.CSharpName (delegate_type));
1461 fixedpars[i] = new Parameter (
1462 delegate_parameters.ParameterType (i), "+" + (++next_index),
1463 delegate_parameters.ParameterModifier (i), null, loc);
1466 return Parameters.CreateFullyResolved (fixedpars, delegate_parameters.Types);
1469 if (!VerifyExplicitParameters (delegate_type, delegate_parameters, ec.IsInProbingMode)) {
1476 public override Expression DoResolve (EmitContext ec)
1479 // Set class type, set type
1482 eclass = ExprClass.Value;
1485 // This hack means `The type is not accessible
1486 // anywhere', we depend on special conversion
1489 type = TypeManager.anonymous_method_type;
1491 if ((Parameters != null) && !Parameters.Resolve (ec))
1494 // FIXME: The emitted code isn't very careful about reachability
1495 // so, ensure we have a 'ret' at the end
1496 if (ec.CurrentBranching != null &&
1497 ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
1498 ec.NeedReturnLabel ();
1503 public override void Emit (EmitContext ec)
1505 // nothing, as we only exist to not do anything.
1508 public override string GetSignatureForError ()
1510 return ExprClassName;
1513 public bool IsIterator {
1514 get { return false; }
1517 protected AnonymousMethod CompatibleMethod (EmitContext ec, TypeInferenceContext tic, Type return_type, Type delegate_type)
1519 Parameters p = ResolveParameters (ec, tic, delegate_type);
1523 ToplevelBlock b = ec.IsInProbingMode ? (ToplevelBlock) Block.PerformClone () : Block;
1525 AnonymousMethod anonymous = CompatibleMethodFactory (return_type, delegate_type, p, b);
1526 if (!anonymous.Compatible (ec))
1532 protected virtual AnonymousMethod CompatibleMethodFactory (Type return_type, Type delegate_type, Parameters p, ToplevelBlock b)
1534 return new AnonymousMethod (RootScope, Host,
1535 GenericMethod, p, Container, b, return_type,
1536 delegate_type, loc);
1539 protected override void CloneTo (CloneContext clonectx, Expression t)
1541 AnonymousMethodExpression target = (AnonymousMethodExpression) t;
1543 target.Block = (ToplevelBlock) clonectx.LookupBlock (Block);
1544 target.container = clonectx.LookupBlock (Block);
1548 public abstract class AnonymousContainer : Expression, IAnonymousContainer
1550 public Parameters Parameters;
1553 // The block that makes up the body for the anonymous mehtod
1555 public readonly ToplevelBlock Block;
1557 public readonly int ModFlags;
1558 public Type ReturnType;
1559 public readonly DeclSpace Host;
1562 // The implicit method we create
1564 protected Method method;
1565 protected EmitContext aec;
1567 // The emit context for the anonymous method
1568 protected bool unreachable;
1569 protected readonly Block container;
1570 protected readonly GenericMethod generic;
1572 protected AnonymousContainer (DeclSpace host,
1573 GenericMethod generic, Parameters parameters,
1574 Block container, ToplevelBlock block,
1575 Type return_type, int mod, Location loc)
1577 this.ReturnType = return_type;
1578 this.ModFlags = mod | Modifiers.COMPILER_GENERATED;
1581 this.container = container;
1582 this.generic = generic;
1583 this.Parameters = parameters;
1587 block.AnonymousContainer = this;
1590 public Method Method {
1591 get { return method; }
1594 public abstract string ContainerType {
1598 public abstract RootScopeInfo RootScope {
1602 public abstract ScopeInfo Scope {
1606 public bool Compatible (EmitContext ec)
1608 // REFACTOR: The method should be refactor, many of the
1609 // hacks can be handled in better way
1611 Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1612 RootScope, Parameters, ec.IsStatic);
1614 if (ReturnType != null) {
1615 TypeExpr return_type_expr;
1616 if (RootScope != null)
1617 return_type_expr = RootScope.InflateType (ReturnType);
1619 return_type_expr = new TypeExpression (ReturnType, Location);
1620 return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
1621 if ((return_type_expr == null) || (return_type_expr.Type == null))
1623 ReturnType = return_type_expr.Type;
1626 // Linq type inference is done differently
1627 if (RootScope != null && RootContext.Version != LanguageVersion.LINQ)
1628 Parameters = RootScope.InflateParameters (Parameters);
1630 aec = new EmitContext (
1631 ec.ResolveContext, ec.TypeContainer,
1632 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1633 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1634 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1636 aec.CurrentAnonymousMethod = this;
1637 aec.IsStatic = ec.IsStatic;
1640 // HACK: Overwrite parent declaration container to currently resolved.
1641 // It's required for an anonymous container inside partial class.
1643 if (RootScope != null)
1644 aec.DeclContainer.Parent = ec.TypeContainer;
1646 IDisposable aec_dispose = null;
1647 EmitContext.Flags flags = 0;
1648 if (ec.InferReturnType)
1649 flags |= EmitContext.Flags.InferReturnType;
1651 if (ec.IsInProbingMode)
1652 flags |= EmitContext.Flags.ProbingMode;
1654 if (ec.IsInFieldInitializer)
1655 flags |= EmitContext.Flags.InFieldInitializer;
1657 if (ec.IsInUnsafeScope)
1658 flags |= EmitContext.Flags.InUnsafe;
1660 // HACK: Flag with 0 cannot be set
1662 aec_dispose = aec.Set (flags);
1664 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1665 RootScope, Parameters, Block);
1668 bool res = aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable);
1670 if (ec.InferReturnType)
1671 ReturnType = aec.ReturnType;
1673 if (aec_dispose != null) {
1674 aec_dispose.Dispose ();
1680 public virtual bool Define (EmitContext ec)
1682 Report.Debug (64, "DEFINE ANONYMOUS METHOD #3", this, ec, aec, Block);
1684 if (aec == null && !Compatible (ec))
1687 // Don't define anything when we are in probing scope (nested anonymous methods)
1688 if (ec.IsInProbingMode)
1691 method = DoCreateMethodHost (ec);
1696 if (!method.ResolveMembers ())
1698 return method.Define ();
1701 protected abstract Method DoCreateMethodHost (EmitContext ec);
1703 public override void Emit (EmitContext ec)
1705 throw new NotSupportedException ();
1708 public Block Container {
1709 get { return container; }
1712 public GenericMethod GenericMethod {
1713 get { return generic; }
1716 public abstract bool IsIterator {
1720 protected class AnonymousMethodMethod : Method
1722 public readonly AnonymousContainer AnonymousMethod;
1723 public readonly ScopeInfo Scope;
1724 public readonly string RealName;
1726 public AnonymousMethodMethod (AnonymousContainer am, ScopeInfo scope,
1727 GenericMethod generic, TypeExpr return_type,
1728 int mod, string real_name, MemberName name,
1729 Parameters parameters)
1730 : base (scope != null ? scope : am.Host,
1731 generic, return_type, mod | Modifiers.COMPILER_GENERATED, false, name, parameters, null)
1733 this.AnonymousMethod = am;
1735 this.RealName = real_name;
1737 if (scope != null) {
1738 scope.CheckMembersDefined ();
1739 scope.AddMethod (this);
1741 ModFlags |= Modifiers.STATIC;
1742 am.Host.PartialContainer.AddMethod (this);
1747 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1749 EmitContext aec = AnonymousMethod.aec;
1751 aec.MethodIsStatic = Scope == null;
1755 public override void EmitExtraSymbolInfo ()
1757 SymbolWriter.SetRealMethodName (RealName);
1762 public class AnonymousMethod : AnonymousContainer
1767 // The value return by the Compatible call, this ensure that
1768 // the code works even if invoked more than once (Resolve called
1769 // more than once, due to the way Convert.ImplicitConversion works
1771 RootScopeInfo root_scope;
1774 public AnonymousMethod (RootScopeInfo root_scope,
1775 DeclSpace host, GenericMethod generic,
1776 Parameters parameters, Block container,
1777 ToplevelBlock block, Type return_type, Type delegate_type,
1779 : base (host, generic, parameters, container, block,
1780 return_type, 0, loc)
1782 this.DelegateType = delegate_type;
1783 this.root_scope = root_scope;
1786 public override string ContainerType {
1787 get { return "anonymous method"; }
1790 public override RootScopeInfo RootScope {
1791 get { return root_scope; }
1794 public override ScopeInfo Scope {
1795 get { return scope; }
1798 public override bool IsIterator {
1799 get { return false; }
1802 public override string GetSignatureForError ()
1804 return TypeManager.CSharpName (DelegateType);
1807 public override Expression CreateExpressionTree (EmitContext ec)
1809 Report.Error (1945, loc, "An expression tree cannot contain an anonymous method expression");
1814 // Creates the host for the anonymous method
1816 protected override Method DoCreateMethodHost (EmitContext ec)
1818 MemberCore mc = ec.ResolveContext as MemberCore;
1819 string name = CompilerGeneratedClass.MakeName (mc.Name, null);
1820 MemberName member_name;
1822 Report.Debug (128, "CREATE METHOD HOST #0", RootScope);
1827 Report.Debug (128, "CREATE METHOD HOST #1", this, Block, Block.ScopeInfo,
1828 RootScope, Location);
1830 for (b = Block.Parent; b != null; b = b.Parent) {
1831 Report.Debug (128, "CREATE METHOD HOST #2", this, Block,
1833 if (b.ScopeInfo != null) {
1834 scope = b.ScopeInfo;
1840 scope.CheckMembersDefined ();
1842 ArrayList scopes = new ArrayList ();
1844 for (b = b.Parent; b != null; b = b.Parent) {
1845 if (b.ScopeInfo != null)
1846 scopes.Add (b.ScopeInfo);
1850 Report.Debug (128, "CREATE METHOD HOST #1", this, scope, scopes);
1852 foreach (ScopeInfo si in scopes)
1853 scope.CaptureScope (si);
1855 Report.Debug (128, "CREATE METHOD HOST", this, Block, container,
1856 RootScope, scope, scopes, Location);
1858 GenericMethod generic_method = null;
1860 if (TypeManager.IsGenericType (DelegateType)) {
1861 TypeArguments args = new TypeArguments (Location);
1863 Type dt = DelegateType.GetGenericTypeDefinition ();
1865 Type[] tparam = TypeManager.GetTypeArguments (dt);
1866 for (int i = 0; i < tparam.Length; i++)
1867 args.Add (new SimpleName (tparam [i].Name, Location));
1869 member_name = new MemberName (name, args, Location);
1871 Report.Debug (128, "CREATE METHOD HOST #5", this, DelegateType,
1872 TypeManager.GetTypeArguments (DelegateType),
1875 generic_method = new GenericMethod (
1876 Host.NamespaceEntry, scope, member_name,
1877 new TypeExpression (ReturnType, Location), Parameters);
1879 generic_method.SetParameterInfo (null);
1882 member_name = new MemberName (name, Location);
1884 string real_name = String.Format (
1885 "{0}~{1}{2}", mc.GetSignatureForError (), GetSignatureForError (),
1886 Parameters.GetSignatureForError ());
1888 return new AnonymousMethodMethod (
1889 this, scope, generic_method, new TypeExpression (ReturnType, Location),
1890 scope == null ? Modifiers.PRIVATE : Modifiers.INTERNAL,
1891 real_name, member_name, Parameters);
1894 public override Expression DoResolve (EmitContext ec)
1899 return new AnonymousDelegate (this, DelegateType, Location).Resolve (ec);
1902 public MethodInfo GetMethodBuilder (EmitContext ec)
1904 MethodInfo builder = method.MethodBuilder;
1905 if ((Scope != null) && Scope.IsGeneric) {
1906 Type scope_type = Scope.GetScopeType (ec);
1907 if (scope_type == null)
1908 throw new InternalErrorException ();
1910 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1911 ec.ContainerType, scope_type, builder.Name,
1912 MemberTypes.Method, Expression.AllBindingFlags | BindingFlags.NonPublic, Location);
1915 throw new InternalErrorException ();
1916 builder = (MethodInfo) mg.Methods [0];
1920 if (!DelegateType.IsGenericType)
1923 Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1924 return builder.MakeGenericMethod (targs);
1930 public static void Error_AddressOfCapturedVar (string name, Location loc)
1932 Report.Error (1686, loc,
1933 "Local variable `{0}' or its members cannot have their " +
1934 "address taken and be used inside an anonymous method block",
1940 // This will emit the code for the delegate, as well delegate creation on the host
1942 public class AnonymousDelegate : DelegateCreation {
1943 readonly AnonymousMethod am;
1946 // if target_type is null, this means that we do not know the type
1947 // for this delegate, and we want to infer it from the various
1948 // returns (implicit and explicit) from the body of this anonymous
1951 // for example, the lambda: x => 1
1953 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1960 public override Expression CreateExpressionTree (EmitContext ec)
1962 return am.CreateExpressionTree (ec);
1965 public override Expression DoResolve (EmitContext ec)
1967 eclass = ExprClass.Value;
1971 public override void Emit (EmitContext ec)
1973 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE");
1974 //ec.ig.Emit (OpCodes.Pop);
1977 // Now emit the delegate creation.
1979 if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1980 Report.Debug (128, "EMIT ANONYMOUS DELEGATE", this, am, am.Scope, loc);
1981 delegate_instance_expression = am.Scope.GetScopeInitializer (ec);
1983 if (delegate_instance_expression == null)
1984 throw new InternalErrorException ();
1987 constructor_method = Delegate.GetConstructor (ec.ContainerType, type);
1989 if (type.IsGenericType && type is TypeBuilder)
1990 constructor_method = TypeBuilder.GetConstructor (type, (ConstructorInfo)constructor_method);
1993 delegate_method = am.GetMethodBuilder (ec);
1996 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE DONE");
1997 //ec.ig.Emit (OpCodes.Pop);
1999 Report.Debug (128, "EMIT ANONYMOUS DELEGATE DONE", this, am, am.Scope, loc);
2004 // Anonymous type container
2006 public class AnonymousTypeClass : CompilerGeneratedClass
2008 static int types_counter;
2009 public const string ClassNamePrefix = "<>__AnonType";
2010 public const string SignatureForError = "anonymous type";
2012 readonly ArrayList parameters;
2014 private AnonymousTypeClass (DeclSpace parent, MemberName name, ArrayList parameters, Location loc)
2015 : base (parent, name, Modifiers.SEALED, loc)
2017 this.parameters = parameters;
2020 public static AnonymousTypeClass Create (TypeContainer parent, ArrayList parameters, Location loc)
2022 if (RootContext.Version <= LanguageVersion.ISO_2)
2023 Report.FeatureIsNotAvailable (loc, "anonymous types");
2025 string name = ClassNamePrefix + types_counter++;
2027 SimpleName [] t_args = new SimpleName [parameters.Count];
2028 Parameter [] ctor_params = new Parameter [parameters.Count];
2029 for (int i = 0; i < parameters.Count; ++i) {
2030 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
2032 t_args [i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
2033 ctor_params [i] = new Parameter (t_args [i], p.Name, 0, null, p.Location);
2037 // Create generic anonymous type host with generic arguments
2038 // named upon properties names
2040 AnonymousTypeClass a_type = new AnonymousTypeClass (parent.NamespaceEntry.SlaveDeclSpace,
2041 new MemberName (name, new TypeArguments (loc, t_args), loc), parameters, loc);
2043 if (parameters.Count > 0)
2044 a_type.SetParameterInfo (null);
2046 Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC,
2047 new Parameters (ctor_params), null, loc);
2048 c.OptAttributes = a_type.GetDebuggerHiddenAttribute ();
2049 c.Block = new ToplevelBlock (c.Parameters, loc);
2052 // Create fields and contructor body with field initialization
2055 for (int i = 0; i < parameters.Count; ++i) {
2056 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
2058 Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY,
2059 "<" + p.Name + ">", null, p.Location);
2061 if (!a_type.AddField (f)) {
2063 Report.Error (833, p.Location, "`{0}': An anonymous type cannot have multiple properties with the same name",
2068 c.Block.AddStatement (new StatementExpression (
2069 new SimpleAssign (new MemberAccess (new This (p.Location), f.Name),
2070 c.Block.GetParameterReference (p.Name, p.Location))));
2072 ToplevelBlock get_block = new ToplevelBlock (p.Location);
2073 get_block.AddStatement (new Return (
2074 new MemberAccess (new This (p.Location), f.Name), p.Location));
2075 Accessor get_accessor = new Accessor (get_block, 0, null, p.Location);
2076 Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC, false,
2077 new MemberName (p.Name, p.Location), null, get_accessor, null, false);
2078 a_type.AddProperty (prop);
2084 a_type.AddConstructor (c);
2088 public new static void Reset ()
2093 protected override bool AddToContainer (MemberCore symbol, string name)
2095 MemberCore mc = (MemberCore) defined_names [name];
2098 defined_names.Add (name, symbol);
2102 Report.SymbolRelatedToPreviousError (mc);
2106 void DefineOverrides ()
2108 Location loc = Location;
2110 Method equals = new Method (this, null, TypeManager.system_boolean_expr,
2111 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("Equals", loc),
2112 new Parameters (new Parameter (TypeManager.system_object_expr, "obj", 0, null, loc)),
2113 GetDebuggerHiddenAttribute ());
2115 Method tostring = new Method (this, null, TypeManager.system_string_expr,
2116 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("ToString", loc),
2117 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
2119 ToplevelBlock equals_block = new ToplevelBlock (equals.Parameters, loc);
2120 TypeExpr current_type;
2122 current_type = new ConstructedType (TypeBuilder, TypeParameters, loc);
2124 current_type = new TypeExpression (TypeBuilder, loc);
2126 equals_block.AddVariable (current_type, "other", loc);
2127 LocalVariableReference other_variable = new LocalVariableReference (equals_block, "other", loc);
2129 MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
2130 new SimpleName ("System", loc), "Collections", loc), "Generic", loc);
2132 Expression rs_equals = null;
2133 Expression string_concat = new StringConstant ("<empty type>", loc);
2134 Expression rs_hashcode = new IntConstant (-2128831035, loc);
2135 for (int i = 0; i < parameters.Count; ++i) {
2136 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
2137 Field f = (Field) Fields [i];
2139 MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
2140 system_collections_generic, "EqualityComparer",
2141 new TypeArguments (loc, new SimpleName (TypeParameters [i].Name, loc)), loc),
2144 ArrayList arguments_equal = new ArrayList (2);
2145 arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2146 arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name)));
2148 Expression field_equal = new Invocation (new MemberAccess (equality_comparer,
2149 "Equals", loc), arguments_equal);
2151 ArrayList arguments_hashcode = new ArrayList (1);
2152 arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2153 Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer,
2154 "GetHashCode", loc), arguments_hashcode);
2156 IntConstant FNV_prime = new IntConstant (16777619, loc);
2157 rs_hashcode = new Binary (Binary.Operator.Multiply,
2158 new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode),
2161 Expression field_to_string = new Conditional (new Binary (Binary.Operator.Inequality,
2162 new MemberAccess (new This (f.Location), f.Name), new NullLiteral (loc)),
2163 new Invocation (new MemberAccess (
2164 new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
2165 new StringConstant ("<null>", loc));
2167 if (rs_equals == null) {
2168 rs_equals = field_equal;
2169 string_concat = new Binary (Binary.Operator.Addition,
2170 new StringConstant (p.Name + " = ", loc),
2176 // Implementation of ToString () body using string concatenation
2178 string_concat = new Binary (Binary.Operator.Addition,
2179 new Binary (Binary.Operator.Addition,
2181 new StringConstant (", " + p.Name + " = ", loc)),
2184 rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal);
2188 // Equals (object obj) override
2190 equals_block.AddStatement (new StatementExpression (
2191 new SimpleAssign (other_variable,
2192 new As (equals_block.GetParameterReference ("obj", loc),
2193 current_type, loc), loc)));
2195 Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc));
2196 if (rs_equals != null)
2197 equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals);
2198 equals_block.AddStatement (new Return (equals_test, loc));
2200 equals.Block = equals_block;
2201 equals.ResolveMembers ();
2205 // GetHashCode () override
2207 Method hashcode = new Method (this, null, TypeManager.system_int32_expr,
2208 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("GetHashCode", loc),
2209 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
2212 // Modified FNV with good avalanche behavior and uniform
2213 // distribution with larger hash sizes.
2215 // const int FNV_prime = 16777619;
2216 // int hash = (int) 2166136261;
2217 // foreach (int d in data)
2218 // hash = (hash ^ d) * FNV_prime;
2219 // hash += hash << 13;
2220 // hash ^= hash >> 7;
2221 // hash += hash << 3;
2222 // hash ^= hash >> 17;
2223 // hash += hash << 5;
2225 ToplevelBlock hashcode_block = new ToplevelBlock (loc);
2226 hashcode_block.AddVariable (TypeManager.system_int32_expr, "hash", loc);
2227 LocalVariableReference hash_variable = new LocalVariableReference (hashcode_block, "hash", loc);
2228 hashcode_block.AddStatement (new StatementExpression (
2229 new SimpleAssign (hash_variable, rs_hashcode)));
2231 hashcode_block.AddStatement (new StatementExpression (
2232 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2233 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (13, loc)))));
2234 hashcode_block.AddStatement (new StatementExpression (
2235 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2236 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (7, loc)))));
2237 hashcode_block.AddStatement (new StatementExpression (
2238 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2239 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (3, loc)))));
2240 hashcode_block.AddStatement (new StatementExpression (
2241 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2242 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (17, loc)))));
2243 hashcode_block.AddStatement (new StatementExpression (
2244 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2245 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (5, loc)))));
2247 hashcode_block.AddStatement (new Return (hash_variable, loc));
2248 hashcode.Block = hashcode_block;
2249 hashcode.ResolveMembers ();
2250 AddMethod (hashcode);
2253 // ToString () override
2256 ToplevelBlock tostring_block = new ToplevelBlock (loc);
2257 tostring_block.AddStatement (new Return (string_concat, loc));
2258 tostring.Block = tostring_block;
2259 tostring.ResolveMembers ();
2260 AddMethod (tostring);
2263 public override bool DefineMembers ()
2267 return base.DefineMembers ();
2270 Attributes GetDebuggerHiddenAttribute ()
2272 return new Attributes (new Attribute (null, null,
2273 "System.Diagnostics.DebuggerHiddenAttribute", null, Location, false));
2276 public override string GetSignatureForError ()
2278 return SignatureForError;
2281 public ArrayList Parameters {