2 // anonymous.cs: Support for anonymous methods
5 // Miguel de Icaza (miguel@ximain.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // (C) 2003, 2004 Novell, Inc.
10 // TODO: Ideally, we should have the helper classes emited as a hierarchy to map
11 // their nesting, and have the visibility set to private, instead of NestedAssembly
18 using System.Collections;
19 using System.Reflection;
20 using System.Reflection.Emit;
22 namespace Mono.CSharp {
24 public abstract class CompilerGeneratedClass : Class
26 GenericMethod generic_method;
27 static int next_index = 0;
29 private static MemberName MakeProxyName (GenericMethod generic, Location loc)
31 string name = MakeName (null, "CompilerGenerated");
32 if (generic != null) {
33 TypeArguments args = new TypeArguments (loc);
34 foreach (TypeParameter tparam in generic.CurrentTypeParameters)
35 args.Add (new SimpleName (tparam.Name, loc));
36 return new MemberName (name, args, loc);
38 return new MemberName (name, loc);
41 public static string MakeName (string host, string prefix)
43 return "<" + host + ">c__" + prefix + next_index++;
46 protected CompilerGeneratedClass (DeclSpace parent,
47 MemberName name, int mod, Location loc) :
48 base (parent.NamespaceEntry, parent, name, mod | Modifiers.COMPILER_GENERATED, null)
50 parent.PartialContainer.AddCompilerGeneratedClass (this);
53 protected CompilerGeneratedClass (DeclSpace parent, GenericMethod generic,
54 int mod, Location loc)
55 : this (parent, MakeProxyName (generic, loc), mod, loc)
57 this.generic_method = generic;
59 if (generic != null) {
60 ArrayList list = new ArrayList ();
61 foreach (TypeParameter tparam in generic.TypeParameters) {
62 if (tparam.Constraints != null)
63 list.Add (tparam.Constraints.Clone ());
65 SetParameterInfo (list);
70 protected override bool DefineNestedTypes ()
72 RootContext.RegisterCompilerGeneratedType (TypeBuilder);
73 return base.DefineNestedTypes ();
76 protected override bool DoDefineMembers ()
78 members_defined = true;
80 if (!base.DoDefineMembers ())
83 if (CompilerGenerated != null) {
84 foreach (CompilerGeneratedClass c in CompilerGenerated) {
85 if (!c.DefineMembers ())
86 throw new InternalErrorException ();
93 protected override bool DoResolveMembers ()
95 if (CompilerGenerated != null) {
96 foreach (CompilerGeneratedClass c in CompilerGenerated) {
97 if (!c.ResolveMembers ())
102 return base.DoResolveMembers ();
105 public GenericMethod GenericMethod {
106 get { return generic_method; }
109 public Parameters InflateParameters (Parameters ps)
111 if (generic_method == null)
118 Parameter[] inflated_params = new Parameter [n];
119 Type[] inflated_types = new Type [n];
121 for (int i = 0; i < n; ++i) {
122 Parameter p = ps [i];
123 Type it = InflateType (p.ExternalType ()).ResolveAsTypeTerminal (this, false).Type;
124 inflated_types [i] = it;
125 inflated_params [i] = new Parameter (it, p.Name, p.ModFlags, p.OptAttributes, p.Location);
127 return Parameters.CreateFullyResolved (inflated_params, inflated_types);
130 public TypeExpr InflateType (Type it)
133 if (generic_method == null)
134 return new TypeExpression (it, Location);
136 if (it.IsGenericParameter && (it.DeclaringMethod != null)) {
137 int pos = it.GenericParameterPosition;
138 it = CurrentTypeParameters [pos].Type;
139 } else if (it.IsGenericType) {
140 Type[] args = it.GetGenericArguments ();
142 TypeArguments inflated = new TypeArguments (Location);
143 foreach (Type t in args)
144 inflated.Add (InflateType (t));
146 return new ConstructedType (it, inflated, Location);
147 } else if (it.IsArray) {
148 TypeExpr et_expr = InflateType (it.GetElementType ());
149 int rank = it.GetArrayRank ();
151 Type et = et_expr.ResolveAsTypeTerminal (this, false).Type;
152 it = et.MakeArrayType (rank);
156 return new TypeExpression (it, Location);
159 public Field CaptureVariable (string name, TypeExpr type)
162 throw new InternalErrorException ("Helper class already defined!");
164 throw new ArgumentNullException ();
166 return new CapturedVariableField (this, name, type);
169 bool members_defined;
171 internal void CheckMembersDefined ()
174 throw new InternalErrorException ("Helper class already defined!");
177 protected class CapturedVariableField : Field
179 public CapturedVariableField (CompilerGeneratedClass helper, string name,
181 : base (helper, type, Modifiers.INTERNAL, name, null, helper.Location)
183 helper.AddField (this);
188 public class ScopeInfo : CompilerGeneratedClass
190 protected readonly RootScopeInfo RootScope;
191 new public readonly DeclSpace Parent;
192 public readonly int ID = ++next_id;
193 public readonly Block ScopeBlock;
194 protected ScopeInitializer scope_initializer;
196 readonly Hashtable locals = new Hashtable ();
197 readonly Hashtable captured_scopes = new Hashtable ();
198 Hashtable captured_params;
202 public static ScopeInfo CreateScope (Block block)
204 ToplevelBlock toplevel = block.Toplevel;
205 AnonymousContainer ac = toplevel.AnonymousContainer;
207 Report.Debug (128, "CREATE SCOPE", block, block.ScopeInfo, toplevel, ac);
210 return new ScopeInfo (block, toplevel.RootScope.Parent,
211 toplevel.RootScope.GenericMethod);
213 Report.Debug (128, "CREATE SCOPE #1", ac, ac.Host, ac.Scope, ac.Block,
218 ScopeInfo parent = null;
220 for (b = ac.Block; b != null; b = b.Parent) {
221 if (b.ScopeInfo != null) {
222 parent = b.ScopeInfo;
227 Report.Debug (128, "CREATE SCOPE #2", parent);
229 ScopeInfo new_scope = new ScopeInfo (block, parent, null);
231 Report.Debug (128, "CREATE SCOPE #3", new_scope);
236 private static int default_modflags (DeclSpace parent)
238 return parent is CompilerGeneratedClass ? Modifiers.PUBLIC : Modifiers.PRIVATE;
241 protected ScopeInfo (Block block, DeclSpace parent, GenericMethod generic)
242 : base (parent, generic, default_modflags (parent), block.StartLocation)
245 RootScope = block.Toplevel.RootScope;
248 Report.Debug (128, "NEW SCOPE", this, block,
249 block.Parent, block.Toplevel);
251 RootScope.AddScope (this);
254 protected ScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
255 GenericMethod generic, Location loc)
256 : base (parent, generic, default_modflags (parent), loc)
259 RootScope = (RootScopeInfo) this;
260 ScopeBlock = toplevel;
262 Report.Debug (128, "NEW ROOT SCOPE", this, toplevel, loc);
265 protected CapturedScope[] CapturedScopes {
267 CapturedScope[] list = new CapturedScope [captured_scopes.Count];
268 captured_scopes.Values.CopyTo (list, 0);
273 protected CapturedVariable GetCapturedScope (ScopeInfo scope)
275 return (CapturedVariable) captured_scopes [scope];
278 protected void EmitScopeInstance (EmitContext ec)
280 if (scope_initializer == null) {
282 // This is needed if someone overwrites the Emit method
283 // of Statement and manually calls Block.Emit without
284 // this snippet first:
286 // ec.EmitScopeInitFromBlock (The_Block);
287 // The_Block.Emit (ec);
289 throw new InternalErrorException ();
292 scope_initializer.Emit (ec);
295 public ExpressionStatement GetScopeInitializer (EmitContext ec)
297 Report.Debug (128, "GET SCOPE INITIALIZER",
298 this, GetType (), scope_initializer, ScopeBlock);
300 if (scope_initializer == null) {
301 scope_initializer = CreateScopeInitializer ();
302 if (scope_initializer.Resolve (ec) == null)
303 throw new InternalErrorException ();
306 return scope_initializer;
309 public Type GetScopeType (EmitContext ec)
314 TypeArguments targs = new TypeArguments (Location);
316 if (ec.DeclContainer.Parent.IsGeneric)
317 foreach (TypeParameter t in ec.DeclContainer.Parent.TypeParameters)
318 targs.Add (new TypeParameterExpr (t, Location));
319 if (ec.DeclContainer.IsGeneric)
320 foreach (TypeParameter t in ec.DeclContainer.CurrentTypeParameters)
321 targs.Add (new TypeParameterExpr (t, Location));
323 Report.Debug (128, "GET SCOPE TYPE", this, TypeBuilder, targs,
324 ec.DeclContainer, ec.DeclContainer.GetType (),
325 ec.DeclContainer.Parent.Name);
327 TypeExpr te = new ConstructedType (TypeBuilder, targs, Location);
328 te = te.ResolveAsTypeTerminal (ec, false);
329 if ((te == null) || (te.Type == null))
334 protected override bool DoDefineMembers ()
336 Report.Debug (64, "SCOPE INFO DEFINE MEMBERS", this, GetType (), IsGeneric,
337 Parent.IsGeneric, GenericMethod);
339 foreach (CapturedScope child in CapturedScopes) {
340 if (!child.DefineMembers ())
344 return base.DoDefineMembers ();
347 protected override bool DoResolveMembers ()
349 Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
350 Parent.IsGeneric, GenericMethod);
352 return base.DoResolveMembers ();
355 public Variable CaptureScope (ScopeInfo child)
357 CheckMembersDefined ();
358 Report.Debug (128, "CAPTURE SCOPE", this, GetType (), child, child.GetType ());
360 throw new InternalErrorException ();
361 CapturedScope captured = (CapturedScope) captured_scopes [child];
362 if (captured == null) {
363 captured = new CapturedScope (this, child);
364 captured_scopes.Add (child, captured);
369 public Variable AddLocal (LocalInfo local)
371 Report.Debug (128, "CAPTURE LOCAL", this, local);
372 Variable var = (Variable) locals [local];
374 var = new CapturedLocal (this, local);
375 locals.Add (local, var);
376 local.IsCaptured = true;
381 public Variable GetCapturedVariable (LocalInfo local)
383 return (Variable) locals [local];
386 public bool HostsParameters {
387 get { return captured_params != null; }
390 public Variable GetCapturedParameter (Parameter par)
392 if (captured_params != null)
393 return (Variable) captured_params [par];
398 public Variable AddParameter (Parameter par, int idx)
400 if (captured_params == null)
401 captured_params = new Hashtable ();
403 Variable var = (Variable) captured_params [par];
405 var = new CapturedParameter (this, par, idx);
406 captured_params.Add (par, var);
407 par.IsCaptured = true;
413 public override void EmitType ()
415 SymbolWriter.DefineAnonymousScope (ID);
416 foreach (CapturedLocal local in locals.Values)
417 local.EmitSymbolInfo ();
419 if (captured_params != null) {
420 foreach (CapturedParameter param in captured_params.Values)
421 param.EmitSymbolInfo ();
424 foreach (CapturedScope scope in CapturedScopes) {
425 scope.EmitSymbolInfo ();
431 protected string MakeFieldName (string local_name)
433 return "<" + ID + ":" + local_name + ">";
436 protected virtual ScopeInitializer CreateScopeInitializer ()
438 return new ScopeInitializer (this);
441 protected abstract class CapturedVariable : Variable
443 public readonly ScopeInfo Scope;
444 public readonly string Name;
446 public FieldExpr FieldInstance;
447 protected Field field;
449 protected CapturedVariable (ScopeInfo scope, string name)
455 protected CapturedVariable (ScopeInfo scope, string name, Type type)
458 this.field = scope.CaptureVariable (
459 scope.MakeFieldName (name), scope.RootScope.InflateType (type));
463 get { return field; }
466 public override Type Type {
467 get { return Field.MemberType; }
470 public override bool HasInstance {
474 public override bool NeedsTemporary {
478 protected FieldInfo GetField (EmitContext ec)
480 if ((ec.CurrentBlock != null) &&
481 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel))
482 return Field.FieldBuilder;
484 return FieldInstance.FieldInfo;
487 public abstract void EmitSymbolInfo ();
489 public override void EmitInstance (EmitContext ec)
491 if ((ec.CurrentAnonymousMethod != null) &&
492 (ec.CurrentAnonymousMethod.Scope == Scope)) {
493 ec.ig.Emit (OpCodes.Ldarg_0);
497 Scope.EmitScopeInstance (ec);
500 public override void Emit (EmitContext ec)
502 ec.ig.Emit (OpCodes.Ldfld, GetField (ec));
505 public override void EmitAssign (EmitContext ec)
507 ec.ig.Emit (OpCodes.Stfld, GetField (ec));
510 public override void EmitAddressOf (EmitContext ec)
512 ec.ig.Emit (OpCodes.Ldflda, GetField (ec));
516 protected class CapturedParameter : CapturedVariable {
517 public readonly Parameter Parameter;
518 public readonly int Idx;
520 public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
521 : base (scope, par.Name, par.ParameterType)
523 this.Parameter = par;
527 public override void EmitSymbolInfo ()
529 SymbolWriter.DefineCapturedParameter (
530 Scope.ID, Parameter.Name, Field.Name);
533 public override string ToString ()
535 return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
536 Parameter.Name, Idx);
540 protected class CapturedLocal : CapturedVariable {
541 public readonly LocalInfo Local;
543 public CapturedLocal (ScopeInfo scope, LocalInfo local)
544 : base (scope, local.Name, local.VariableType)
549 public override void EmitSymbolInfo ()
551 SymbolWriter.DefineCapturedLocal (
552 Scope.ID, Local.Name, Field.Name);
555 public override string ToString ()
557 return String.Format ("{0} ({1}:{2})", GetType (), Field,
562 protected class CapturedThis : CapturedVariable {
563 public CapturedThis (RootScopeInfo host)
564 : base (host, "<>THIS", host.ParentType)
567 public override void EmitSymbolInfo ()
569 SymbolWriter.DefineCapturedThis (Scope.ID, Field.Name);
573 protected class CapturedScope : CapturedVariable {
574 public readonly ScopeInfo ChildScope;
576 public CapturedScope (ScopeInfo root, ScopeInfo child)
577 : base (root, "scope" + child.ID)
579 this.ChildScope = child;
582 public override void EmitSymbolInfo ()
584 SymbolWriter.DefineCapturedScope (Scope.ID, ChildScope.ID, Field.Name);
587 public bool DefineMembers ()
589 Type type = ChildScope.IsGeneric ?
590 ChildScope.CurrentType : ChildScope.TypeBuilder;
591 Report.Debug (128, "CAPTURED SCOPE DEFINE MEMBERS", this, Scope,
592 ChildScope, Name, type);
594 throw new InternalErrorException ();
595 field = Scope.CaptureVariable (
596 Scope.MakeFieldName (Name), Scope.InflateType (type));
600 public override string ToString ()
602 return String.Format ("CapturedScope ({1} captured in {0})",
607 static void DoPath (StringBuilder sb, ScopeInfo start)
609 sb.Append ((start.ID).ToString ());
612 public override string ToString ()
614 StringBuilder sb = new StringBuilder ();
620 return sb.ToString ();
623 protected class ScopeInitializer : ExpressionStatement
626 CapturedVariable captured_scope;
627 LocalBuilder scope_instance;
628 ConstructorInfo scope_ctor;
632 public ScopeInitializer (ScopeInfo scope)
635 this.loc = scope.Location;
636 eclass = ExprClass.Value;
639 public ScopeInfo Scope {
640 get { return scope; }
643 public override Expression DoResolve (EmitContext ec)
645 if (scope_ctor != null)
648 Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
649 ec, ec.CurrentBlock);
651 type = Scope.GetScopeType (ec);
653 throw new InternalErrorException ();
655 if (!DoResolveInternal (ec))
656 throw new InternalErrorException ();
661 protected virtual bool DoResolveInternal (EmitContext ec)
663 MethodGroupExpr mg = (MethodGroupExpr) MemberLookupFinal (
664 ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
665 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
667 throw new InternalErrorException ();
669 scope_ctor = (ConstructorInfo) mg.Methods [0];
671 Report.Debug (128, "RESOLVE THE INIT", this, Scope, Scope.RootScope,
672 Scope.RootScope.GetType ());
674 ScopeInfo host = Scope.RootScope;
675 if ((Scope != host) && (Scope.RootScope is IteratorHost)) {
676 captured_scope = host.GetCapturedScope (Scope);
677 Type root = host.GetScopeType (ec);
678 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
679 type, root, captured_scope.Field.Name, loc);
681 throw new InternalErrorException ();
683 fe.InstanceExpression = this;
684 captured_scope.FieldInstance = fe;
686 Report.Debug (128, "RESOLVE THE INIT #1", this,
689 scope_instance = ec.ig.DeclareLocal (type);
690 if (!Scope.RootScope.IsIterator)
691 SymbolWriter.DefineScopeVariable (Scope.ID, scope_instance);
694 foreach (CapturedLocal local in Scope.locals.Values) {
695 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
696 ec.ContainerType, type, local.Field.Name, loc);
697 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
698 Scope, ec, ec.ContainerType, type,
699 local.Field, local.Field.Name, loc, fe);
701 throw new InternalErrorException ();
703 fe.InstanceExpression = this;
704 local.FieldInstance = fe;
707 if (Scope.HostsParameters) {
708 foreach (CapturedParameter cp in Scope.captured_params.Values) {
709 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
710 ec.ContainerType, type, cp.Field.Name, loc);
712 throw new InternalErrorException ();
714 fe.InstanceExpression = this;
715 cp.FieldInstance = fe;
719 foreach (CapturedScope scope in Scope.CapturedScopes) {
720 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
721 ec.ContainerType, type, scope.Field.Name, loc);
722 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #3", this, Scope,
723 scope, ec, ec.ContainerType, type,
724 scope.Field, scope.Field.Name, loc, fe);
726 throw new InternalErrorException ();
728 fe.InstanceExpression = this;
729 scope.FieldInstance = fe;
735 protected virtual void EmitParameterReference (EmitContext ec,
736 CapturedParameter cp)
738 int extra = ec.MethodIsStatic ? 0 : 1;
739 ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
745 protected virtual void DoEmit (EmitContext ec)
747 if ((ec.CurrentBlock != null) &&
748 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)) {
749 ec.ig.Emit (OpCodes.Ldarg_0);
751 if (ec.CurrentAnonymousMethod != null) {
752 ScopeInfo host = ec.CurrentAnonymousMethod.Scope;
753 Variable captured = host.GetCapturedScope (scope);
754 Report.Debug (128, "EMIT SCOPE INSTANCE #2",
755 ec.CurrentAnonymousMethod, host,
757 if (captured != null)
760 } else if (scope_instance != null)
761 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
763 Report.Debug (128, "DO EMIT", this, Scope, ec,
764 scope_instance, captured_scope);
765 captured_scope.EmitInstance (ec);
766 captured_scope.Emit (ec);
770 protected void DoEmitInstance (EmitContext ec)
772 Report.Debug (128, "DO EMIT INSTANCE", this, Scope, ec,
773 scope_instance, captured_scope);
775 if (scope_instance != null)
776 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
778 captured_scope.EmitInstance (ec);
781 protected virtual void EmitScopeConstructor (EmitContext ec)
783 ec.ig.Emit (OpCodes.Newobj, scope_ctor);
786 public override void Emit (EmitContext ec)
789 throw new InternalErrorException (
790 "Scope {0} not initialized yet", scope);
795 public override void EmitStatement (EmitContext ec)
800 DoEmitStatement (ec);
804 protected virtual void DoEmitStatement (EmitContext ec)
806 Report.Debug (128, "EMIT SCOPE INITIALIZER STATEMENT", this, id,
807 Scope, scope_instance, ec);
809 ec.ig.Emit (OpCodes.Nop);
810 ec.ig.Emit (OpCodes.Ldc_I4, id);
811 ec.ig.Emit (OpCodes.Pop);
812 ec.ig.Emit (OpCodes.Nop);
814 if (scope_instance == null)
815 ec.ig.Emit (OpCodes.Ldarg_0);
816 EmitScopeConstructor (ec);
817 if (scope_instance != null)
818 ec.ig.Emit (OpCodes.Stloc, scope_instance);
820 captured_scope.EmitAssign (ec);
822 if (Scope.HostsParameters) {
823 foreach (CapturedParameter cp in Scope.captured_params.Values) {
824 Report.Debug (128, "EMIT SCOPE INIT #6", this,
825 ec, ec.IsStatic, Scope, cp, cp.Field.Name);
827 EmitParameterReference (ec, cp);
828 ec.ig.Emit (OpCodes.Stfld, cp.FieldInstance.FieldInfo);
832 if (Scope is IteratorHost)
835 foreach (CapturedScope scope in Scope.CapturedScopes) {
836 ScopeInfo child = scope.ChildScope;
838 Report.Debug (128, "EMIT SCOPE INIT #5", this, Scope,
839 scope.Scope, scope.ChildScope);
841 ExpressionStatement init = child.GetScopeInitializer (ec);
842 init.EmitStatement (ec);
845 scope.ChildScope.EmitScopeInstance (ec);
846 scope.EmitAssign (ec);
852 public class RootScopeInfo : ScopeInfo
854 public RootScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
855 GenericMethod generic, Location loc)
856 : base (toplevel, parent, generic, loc)
858 scopes = new ArrayList ();
861 TypeExpr parent_type;
862 CapturedVariableField parent_link;
863 CapturedThis this_variable;
864 protected ArrayList scopes;
866 public virtual bool IsIterator {
867 get { return false; }
870 public RootScopeInfo ParentHost {
871 get { return Parent.PartialContainer as RootScopeInfo; }
874 public Type ParentType {
875 get { return parent_type.Type; }
878 public Field ParentLink {
879 get { return parent_link; }
882 protected CapturedThis THIS {
883 get { return this_variable; }
886 public Variable CaptureThis ()
888 if (ParentHost != null)
889 return ParentHost.CaptureThis ();
891 CheckMembersDefined ();
892 if (this_variable == null)
893 this_variable = new CapturedThis (this);
894 return this_variable;
897 public void AddScope (ScopeInfo scope)
903 public void LinkScopes ()
905 Report.Debug (128, "LINK SCOPES", this, linked, scopes);
911 if (ParentHost != null)
912 ParentHost.LinkScopes ();
914 foreach (ScopeInfo si in scopes) {
916 throw new InternalErrorException ();
917 if (si.DefineType () == null)
918 throw new InternalErrorException ();
919 if (!si.ResolveType ())
920 throw new InternalErrorException ();
923 foreach (ScopeInfo si in scopes) {
924 if (!si.ResolveMembers ())
925 throw new InternalErrorException ();
926 if (!si.DefineMembers ())
927 throw new InternalErrorException ();
931 protected override ScopeInitializer CreateScopeInitializer ()
933 return new RootScopeInitializer (this);
936 protected override bool DefineNestedTypes ()
938 if (Parent.IsGeneric) {
939 parent_type = new ConstructedType (
940 Parent.TypeBuilder, Parent.TypeParameters, Location);
941 parent_type = parent_type.ResolveAsTypeTerminal (this, false);
942 if ((parent_type == null) || (parent_type.Type == null))
945 parent_type = new TypeExpression (Parent.TypeBuilder, Location);
948 CompilerGeneratedClass parent = Parent.PartialContainer as CompilerGeneratedClass;
950 parent_link = new CapturedVariableField (this, "<>parent", parent_type);
952 return base.DefineNestedTypes ();
955 protected override bool DoDefineMembers ()
957 ArrayList args = new ArrayList ();
958 if (this is IteratorHost)
959 args.Add (new Parameter (
960 TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
964 if (Parent is CompilerGeneratedClass)
965 pfield = parent_link;
967 pfield = this_variable != null ? this_variable.Field : null;
969 args.Add (new Parameter (
970 pfield.MemberType, "parent", Parameter.Modifier.NONE,
973 Parameter[] ctor_params = new Parameter [args.Count];
974 args.CopyTo (ctor_params, 0);
975 Constructor ctor = new Constructor (
976 this, MemberName.Name, Modifiers.PUBLIC,
977 new Parameters (ctor_params),
978 new GeneratedBaseInitializer (Location),
980 AddConstructor (ctor);
982 ctor.Block = new ToplevelBlock (null, Location);
983 ctor.Block.AddStatement (new TheCtor (this));
985 return base.DoDefineMembers ();
988 protected virtual void EmitScopeConstructor (EmitContext ec)
990 int pos = (this is IteratorHost) ? 2 : 1;
993 if (Parent is CompilerGeneratedClass)
994 pfield = parent_link;
996 pfield = this_variable != null ? this_variable.Field : null;
998 if (pfield != null) {
999 ec.ig.Emit (OpCodes.Ldarg_0);
1000 ec.ig.Emit (OpCodes.Ldarg, pos);
1001 ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
1006 public override void EmitType ()
1010 THIS.EmitSymbolInfo ();
1013 protected class TheCtor : Statement
1017 public TheCtor (RootScopeInfo host)
1022 public override bool Resolve (EmitContext ec)
1027 protected override void DoEmit (EmitContext ec)
1029 host.EmitScopeConstructor (ec);
1033 protected class RootScopeInitializer : ScopeInitializer
1037 public RootScopeInitializer (RootScopeInfo host)
1043 public RootScopeInfo Host {
1044 get { return host; }
1047 protected override bool DoResolveInternal (EmitContext ec)
1049 Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
1050 this, Host, Host.ParentType, loc);
1052 if (Host.THIS != null) {
1053 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
1054 ec.ContainerType, type, Host.THIS.Field.Name, loc);
1056 throw new InternalErrorException ();
1058 fe.InstanceExpression = this;
1059 Host.THIS.FieldInstance = fe;
1062 return base.DoResolveInternal (ec);
1065 protected virtual bool IsGetEnumerator {
1066 get { return false; }
1069 protected override void EmitScopeConstructor (EmitContext ec)
1071 if (host.THIS != null) {
1072 ec.ig.Emit (OpCodes.Ldarg_0);
1073 if (IsGetEnumerator)
1074 ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
1075 else if (host.THIS.Type.IsValueType)
1076 Expression.LoadFromPtr (ec.ig, host.THIS.Type);
1077 } else if (host.ParentLink != null)
1078 ec.ig.Emit (OpCodes.Ldarg_0);
1080 base.EmitScopeConstructor (ec);
1086 public interface IAnonymousContainer
1092 GenericMethod GenericMethod {
1096 RootScopeInfo RootScope {
1105 public interface IAnonymousHost
1108 // Invoked if a yield statement is found in the body
1113 // Invoked if an anonymous method is found in the body
1115 void AddAnonymousMethod (AnonymousMethodExpression anonymous);
1118 public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
1120 public readonly AnonymousMethodExpression Parent;
1121 public readonly TypeContainer Host;
1122 public readonly Parameters Parameters;
1124 public ToplevelBlock Block;
1126 protected Block container;
1127 protected readonly GenericMethod generic;
1129 public Block Container {
1130 get { return container; }
1133 public GenericMethod GenericMethod {
1134 get { return generic; }
1137 public RootScopeInfo RootScope {
1138 get { return root_scope; }
1141 public AnonymousMethodExpression (AnonymousMethodExpression parent,
1142 GenericMethod generic, TypeContainer host,
1143 Parameters parameters, Block container,
1146 this.Parent = parent;
1147 this.generic = parent != null ? null : generic;
1149 this.Parameters = parameters;
1150 this.container = container;
1153 Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host,
1157 parent.AddAnonymousMethod (this);
1161 RootScopeInfo root_scope;
1163 static int next_index;
1165 void IAnonymousHost.SetYields ()
1167 throw new InvalidOperationException ();
1170 public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
1172 if (children == null)
1173 children = new ArrayList ();
1174 children.Add (anonymous);
1177 public bool CreateAnonymousHelpers ()
1179 // FIXME: this polutes expression trees implementation
1181 Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
1182 this, Host, container, loc);
1184 if (container != null)
1185 root_scope = container.Toplevel.CreateRootScope (Host);
1187 if (children != null) {
1188 foreach (AnonymousMethodExpression child in children) {
1189 if (!child.CreateAnonymousHelpers ())
1197 public override string ExprClassName {
1199 return "anonymous method";
1203 public virtual bool HasExplicitParameters {
1210 // Returns true if the body of lambda expression can be implicitly
1211 // converted to the delegate of type `delegate_type'
1213 public bool ImplicitStandardConversionExists (Type delegate_type)
1215 EmitContext ec = EmitContext.TempEc;
1216 using (ec.Set (EmitContext.Flags.ProbingMode)) {
1217 return Compatible (ec, delegate_type) != null;
1221 protected Type CompatibleChecks (EmitContext ec, Type delegate_type)
1223 if (!ec.IsAnonymousMethodAllowed) {
1224 Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
1228 if (TypeManager.IsDelegateType (delegate_type))
1229 return delegate_type;
1232 if (TypeManager.DropGenericTypeArguments (delegate_type) == TypeManager.expression_type) {
1233 delegate_type = TypeManager.GetTypeArguments (delegate_type) [0];
1234 if (TypeManager.IsDelegateType (delegate_type))
1235 return delegate_type;
1237 Report.Error (835, loc, "Cannot convert `{0}' to an expression tree of non-delegate type `{1}'",
1238 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
1243 Report.Error (1660, loc, "Cannot convert `{0}' to non-delegate type `{1}'",
1244 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
1248 protected bool VerifyExplicitParameters (Type delegate_type, ParameterData parameters, bool ignore_error)
1250 if (VerifyParameterCompatibility (delegate_type, parameters, ignore_error))
1254 Report.Error (1661, loc,
1255 "Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch",
1256 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
1261 protected bool VerifyParameterCompatibility (Type delegate_type, ParameterData invoke_pd, bool ignore_errors)
1263 if (Parameters.Count != invoke_pd.Count) {
1267 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1268 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1272 if (!HasExplicitParameters)
1276 for (int i = 0; i < Parameters.Count; ++i) {
1277 Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1278 if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1282 if (p_mod == Parameter.Modifier.NONE)
1283 Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1284 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1286 Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1287 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1292 Type type = invoke_pd.Types [i];
1294 // We assume that generic parameters are always inflated
1295 if (TypeManager.IsGenericParameter (type))
1298 if (TypeManager.HasElementType (type) && TypeManager.IsGenericParameter (TypeManager.GetElementType (type)))
1301 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1305 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1307 TypeManager.CSharpName (Parameters.ParameterType (i)),
1308 TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1317 // Infers type arguments based on explicit arguments
1319 public bool ExplicitTypeInference (TypeInferenceContext type_inference, Type delegate_type)
1321 if (!HasExplicitParameters)
1324 if (!TypeManager.IsDelegateType (delegate_type)) {
1326 if (TypeManager.DropGenericTypeArguments (delegate_type) != TypeManager.expression_type)
1329 delegate_type = delegate_type.GetGenericArguments () [0];
1330 if (!TypeManager.IsDelegateType (delegate_type))
1337 ParameterData d_params = TypeManager.GetDelegateParameters (delegate_type);
1338 if (d_params.Count != Parameters.Count)
1341 for (int i = 0; i < Parameters.Count; ++i) {
1342 Type itype = d_params.Types [i];
1343 if (!TypeManager.IsGenericParameter (itype)) {
1344 if (!TypeManager.HasElementType (itype))
1347 if (!TypeManager.IsGenericParameter (itype.GetElementType ()))
1350 type_inference.ExactInference (Parameters.FixedParameters[i].ParameterType, itype);
1355 public Type InferReturnType (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
1358 using (ec.Set (EmitContext.Flags.ProbingMode | EmitContext.Flags.InferReturnType)) {
1359 am = CompatibleMethod (ec, tic, GetType (), delegate_type);
1365 if (am.ReturnType == TypeManager.null_type)
1366 am.ReturnType = null;
1368 return am.ReturnType;
1372 // Returns AnonymousMethod container if this anonymous method
1373 // expression can be implicitly converted to the delegate type `delegate_type'
1375 public Expression Compatible (EmitContext ec, Type type)
1377 Type delegate_type = CompatibleChecks (ec, type);
1378 if (delegate_type == null)
1382 // At this point its the first time we know the return type that is
1383 // needed for the anonymous method. We create the method here.
1386 MethodInfo invoke_mb = Delegate.GetInvokeMethod (
1387 ec.ContainerType, delegate_type);
1388 Type return_type = TypeManager.TypeToCoreType (invoke_mb.ReturnType);
1391 Type[] g_args = delegate_type.GetGenericArguments ();
1392 if (return_type.IsGenericParameter)
1393 return_type = g_args [return_type.GenericParameterPosition];
1397 // Second: the return type of the delegate must be compatible with
1398 // the anonymous type. Instead of doing a pass to examine the block
1399 // we satisfy the rule by setting the return type on the EmitContext
1400 // to be the delegate type return type.
1403 Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1404 Container, Block, return_type, delegate_type,
1405 TypeManager.IsGenericType (delegate_type), loc);
1408 AnonymousMethod am = CompatibleMethod (ec, null, return_type, delegate_type);
1409 if (am != null && delegate_type != type)
1410 return CreateExpressionTree (ec, delegate_type);
1413 } catch (Exception e) {
1414 throw new InternalErrorException (e, loc);
1418 protected virtual Expression CreateExpressionTree (EmitContext ec, Type delegate_type)
1420 Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree");
1424 protected virtual Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
1426 ParameterData delegate_parameters = TypeManager.GetDelegateParameters (delegate_type);
1428 if (Parameters == null) {
1430 // We provide a set of inaccessible parameters
1432 Parameter[] fixedpars = new Parameter[delegate_parameters.Count];
1434 for (int i = 0; i < delegate_parameters.Count; i++) {
1435 Parameter.Modifier i_mod = delegate_parameters.ParameterModifier (i);
1436 if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1437 Report.Error (1688, loc, "Cannot convert anonymous " +
1438 "method block without a parameter list " +
1439 "to delegate type `{0}' because it has " +
1440 "one or more `out' parameters.",
1441 TypeManager.CSharpName (delegate_type));
1444 fixedpars[i] = new Parameter (
1445 delegate_parameters.ParameterType (i), "+" + (++next_index),
1446 delegate_parameters.ParameterModifier (i), null, loc);
1449 return Parameters.CreateFullyResolved (fixedpars, delegate_parameters.Types);
1452 if (!VerifyExplicitParameters (delegate_type, delegate_parameters, ec.IsInProbingMode)) {
1459 public override Expression DoResolve (EmitContext ec)
1462 // Set class type, set type
1465 eclass = ExprClass.Value;
1468 // This hack means `The type is not accessible
1469 // anywhere', we depend on special conversion
1472 type = TypeManager.anonymous_method_type;
1474 if ((Parameters != null) && !Parameters.Resolve (ec))
1480 public override void Emit (EmitContext ec)
1482 // nothing, as we only exist to not do anything.
1485 public override string GetSignatureForError ()
1487 return ExprClassName;
1490 public bool IsIterator {
1491 get { return false; }
1494 protected AnonymousMethod CompatibleMethod (EmitContext ec, TypeInferenceContext tic, Type return_type, Type delegate_type)
1496 Parameters p = ResolveParameters (ec, tic, delegate_type);
1500 ToplevelBlock b = ec.IsInProbingMode ? (ToplevelBlock) Block.PerformClone () : Block;
1502 AnonymousMethod anonymous = CompatibleMethodFactory (return_type, delegate_type, p, b);
1503 if (!anonymous.Compatible (ec))
1509 protected virtual AnonymousMethod CompatibleMethodFactory (Type return_type, Type delegate_type, Parameters p, ToplevelBlock b)
1511 return new AnonymousMethod (RootScope, Host,
1512 GenericMethod, p, Container, b, return_type,
1513 delegate_type, loc);
1516 protected override void CloneTo (CloneContext clonectx, Expression t)
1518 AnonymousMethodExpression target = (AnonymousMethodExpression) t;
1520 target.Block = (ToplevelBlock) clonectx.LookupBlock (Block);
1521 target.container = clonectx.LookupBlock (Block);
1525 public abstract class AnonymousContainer : Expression, IAnonymousContainer
1527 public Parameters Parameters;
1530 // The block that makes up the body for the anonymous mehtod
1532 public readonly ToplevelBlock Block;
1534 public readonly int ModFlags;
1535 public Type ReturnType;
1536 public readonly DeclSpace Host;
1539 // The implicit method we create
1541 protected Method method;
1542 protected EmitContext aec;
1544 // The emit context for the anonymous method
1545 protected bool unreachable;
1546 protected readonly Block container;
1547 protected readonly GenericMethod generic;
1549 protected AnonymousContainer (DeclSpace host,
1550 GenericMethod generic, Parameters parameters,
1551 Block container, ToplevelBlock block,
1552 Type return_type, int mod, Location loc)
1554 this.ReturnType = return_type;
1555 this.ModFlags = mod | Modifiers.COMPILER_GENERATED;
1558 this.container = container;
1559 this.generic = generic;
1560 this.Parameters = parameters;
1564 block.AnonymousContainer = this;
1567 public Method Method {
1568 get { return method; }
1571 public abstract string ContainerType {
1575 public abstract RootScopeInfo RootScope {
1579 public abstract ScopeInfo Scope {
1583 public bool Compatible (EmitContext ec)
1585 // REFACTOR: The method should be refactor, many of the
1586 // hacks can be handled in better way
1588 Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1589 RootScope, Parameters, ec.IsStatic);
1591 if (ReturnType != null) {
1592 TypeExpr return_type_expr;
1593 if (RootScope != null)
1594 return_type_expr = RootScope.InflateType (ReturnType);
1596 return_type_expr = new TypeExpression (ReturnType, Location);
1597 return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
1598 if ((return_type_expr == null) || (return_type_expr.Type == null))
1600 ReturnType = return_type_expr.Type;
1603 // Linq type inference is done differently
1604 if (RootScope != null && RootContext.Version != LanguageVersion.LINQ)
1605 Parameters = RootScope.InflateParameters (Parameters);
1607 aec = new EmitContext (
1608 ec.ResolveContext, ec.TypeContainer,
1609 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1610 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1611 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1613 aec.CurrentAnonymousMethod = this;
1614 aec.IsStatic = ec.IsStatic;
1617 // HACK: Overwrite parent declaration container to currently resolved.
1618 // It's required for an anonymous container inside partial class.
1620 if (RootScope != null)
1621 aec.DeclContainer.Parent = ec.TypeContainer;
1623 IDisposable aec_dispose = null;
1624 EmitContext.Flags flags = 0;
1625 if (ec.InferReturnType)
1626 flags |= EmitContext.Flags.InferReturnType;
1628 if (ec.IsInProbingMode)
1629 flags |= EmitContext.Flags.ProbingMode;
1631 if (ec.IsInFieldInitializer)
1632 flags |= EmitContext.Flags.InFieldInitializer;
1634 // HACK: Flag with 0 cannot be set
1636 aec_dispose = aec.Set (flags);
1638 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1639 RootScope, Parameters, Block);
1642 bool res = aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable);
1644 if (ec.InferReturnType)
1645 ReturnType = aec.ReturnType;
1647 if (aec_dispose != null) {
1648 aec_dispose.Dispose ();
1654 public virtual bool Define (EmitContext ec)
1656 Report.Debug (64, "DEFINE ANONYMOUS METHOD #3", this, ec, aec, Block);
1658 if (aec == null && !Compatible (ec))
1661 // Don't define anything when we are in probing scope (nested anonymous methods)
1662 if (ec.IsInProbingMode)
1665 method = DoCreateMethodHost (ec);
1670 if (!method.ResolveMembers ())
1672 return method.Define ();
1675 protected abstract Method DoCreateMethodHost (EmitContext ec);
1677 public override void Emit (EmitContext ec)
1679 throw new NotSupportedException ();
1682 public Block Container {
1683 get { return container; }
1686 public GenericMethod GenericMethod {
1687 get { return generic; }
1690 public abstract bool IsIterator {
1694 protected class AnonymousMethodMethod : Method
1696 public readonly AnonymousContainer AnonymousMethod;
1697 public readonly ScopeInfo Scope;
1698 public readonly string RealName;
1700 public AnonymousMethodMethod (AnonymousContainer am, ScopeInfo scope,
1701 GenericMethod generic, TypeExpr return_type,
1702 int mod, string real_name, MemberName name,
1703 Parameters parameters)
1704 : base (scope != null ? scope : am.Host,
1705 generic, return_type, mod | Modifiers.COMPILER_GENERATED, false, name, parameters, null)
1707 this.AnonymousMethod = am;
1709 this.RealName = real_name;
1711 if (scope != null) {
1712 scope.CheckMembersDefined ();
1713 scope.AddMethod (this);
1715 ModFlags |= Modifiers.STATIC;
1716 am.Host.PartialContainer.AddMethod (this);
1721 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1723 EmitContext aec = AnonymousMethod.aec;
1725 aec.MethodIsStatic = Scope == null;
1729 public override void EmitExtraSymbolInfo ()
1731 SymbolWriter.SetRealMethodName (RealName);
1736 public class AnonymousMethod : AnonymousContainer
1741 // The value return by the Compatible call, this ensure that
1742 // the code works even if invoked more than once (Resolve called
1743 // more than once, due to the way Convert.ImplicitConversion works
1745 RootScopeInfo root_scope;
1748 public AnonymousMethod (RootScopeInfo root_scope,
1749 DeclSpace host, GenericMethod generic,
1750 Parameters parameters, Block container,
1751 ToplevelBlock block, Type return_type, Type delegate_type,
1753 : base (host, generic, parameters, container, block,
1754 return_type, 0, loc)
1756 this.DelegateType = delegate_type;
1757 this.root_scope = root_scope;
1760 public override string ContainerType {
1761 get { return "anonymous method"; }
1764 public override RootScopeInfo RootScope {
1765 get { return root_scope; }
1768 public override ScopeInfo Scope {
1769 get { return scope; }
1772 public override bool IsIterator {
1773 get { return false; }
1776 public override string GetSignatureForError ()
1778 return TypeManager.CSharpName (DelegateType);
1782 // Creates the host for the anonymous method
1784 protected override Method DoCreateMethodHost (EmitContext ec)
1786 MemberCore mc = ec.ResolveContext as MemberCore;
1787 string name = CompilerGeneratedClass.MakeName (mc.Name, null);
1788 MemberName member_name;
1790 Report.Debug (128, "CREATE METHOD HOST #0", RootScope);
1795 Report.Debug (128, "CREATE METHOD HOST #1", this, Block, Block.ScopeInfo,
1796 RootScope, Location);
1798 for (b = Block.Parent; b != null; b = b.Parent) {
1799 Report.Debug (128, "CREATE METHOD HOST #2", this, Block,
1801 if (b.ScopeInfo != null) {
1802 scope = b.ScopeInfo;
1808 scope.CheckMembersDefined ();
1810 ArrayList scopes = new ArrayList ();
1812 for (b = b.Parent; b != null; b = b.Parent) {
1813 if (b.ScopeInfo != null)
1814 scopes.Add (b.ScopeInfo);
1818 Report.Debug (128, "CREATE METHOD HOST #1", this, scope, scopes);
1820 foreach (ScopeInfo si in scopes)
1821 scope.CaptureScope (si);
1823 Report.Debug (128, "CREATE METHOD HOST", this, Block, container,
1824 RootScope, scope, scopes, Location);
1826 GenericMethod generic_method = null;
1828 if (TypeManager.IsGenericType (DelegateType)) {
1829 TypeArguments args = new TypeArguments (Location);
1831 Type dt = DelegateType.GetGenericTypeDefinition ();
1833 Type[] tparam = TypeManager.GetTypeArguments (dt);
1834 for (int i = 0; i < tparam.Length; i++)
1835 args.Add (new SimpleName (tparam [i].Name, Location));
1837 member_name = new MemberName (name, args, Location);
1839 Report.Debug (128, "CREATE METHOD HOST #5", this, DelegateType,
1840 TypeManager.GetTypeArguments (DelegateType),
1843 generic_method = new GenericMethod (
1844 Host.NamespaceEntry, scope, member_name,
1845 new TypeExpression (ReturnType, Location), Parameters);
1847 generic_method.SetParameterInfo (null);
1850 member_name = new MemberName (name, Location);
1852 string real_name = String.Format (
1853 "{0}~{1}{2}", mc.GetSignatureForError (), GetSignatureForError (),
1854 Parameters.GetSignatureForError ());
1856 return new AnonymousMethodMethod (
1857 this, scope, generic_method, new TypeExpression (ReturnType, Location),
1858 scope == null ? Modifiers.PRIVATE : Modifiers.INTERNAL,
1859 real_name, member_name, Parameters);
1862 public override Expression DoResolve (EmitContext ec)
1867 return new AnonymousDelegate (this, DelegateType, Location).Resolve (ec);
1870 public MethodInfo GetMethodBuilder (EmitContext ec)
1872 MethodInfo builder = method.MethodBuilder;
1873 if ((Scope != null) && Scope.IsGeneric) {
1874 Type scope_type = Scope.GetScopeType (ec);
1875 if (scope_type == null)
1876 throw new InternalErrorException ();
1878 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1879 ec.ContainerType, scope_type, builder.Name,
1880 MemberTypes.Method, Expression.AllBindingFlags | BindingFlags.NonPublic, Location);
1883 throw new InternalErrorException ();
1884 builder = (MethodInfo) mg.Methods [0];
1888 if (!DelegateType.IsGenericType)
1891 Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1892 return builder.MakeGenericMethod (targs);
1898 public static void Error_AddressOfCapturedVar (string name, Location loc)
1900 Report.Error (1686, loc,
1901 "Local variable `{0}' or its members cannot have their " +
1902 "address taken and be used inside an anonymous method block",
1908 // This will emit the code for the delegate, as well delegate creation on the host
1910 public class AnonymousDelegate : DelegateCreation {
1911 readonly AnonymousMethod am;
1914 // if target_type is null, this means that we do not know the type
1915 // for this delegate, and we want to infer it from the various
1916 // returns (implicit and explicit) from the body of this anonymous
1919 // for example, the lambda: x => 1
1921 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1928 public override Expression DoResolve (EmitContext ec)
1930 eclass = ExprClass.Value;
1934 public override void Emit (EmitContext ec)
1936 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE");
1937 //ec.ig.Emit (OpCodes.Pop);
1940 // Now emit the delegate creation.
1942 if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1943 Report.Debug (128, "EMIT ANONYMOUS DELEGATE", this, am, am.Scope, loc);
1944 delegate_instance_expression = am.Scope.GetScopeInitializer (ec);
1946 if (delegate_instance_expression == null)
1947 throw new InternalErrorException ();
1950 constructor_method = Delegate.GetConstructor (ec.ContainerType, type);
1952 if (type.IsGenericType && type is TypeBuilder)
1953 constructor_method = TypeBuilder.GetConstructor (type, (ConstructorInfo)constructor_method);
1956 delegate_method = am.GetMethodBuilder (ec);
1959 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE DONE");
1960 //ec.ig.Emit (OpCodes.Pop);
1962 Report.Debug (128, "EMIT ANONYMOUS DELEGATE DONE", this, am, am.Scope, loc);
1967 // Anonymous type container
1969 public class AnonymousTypeClass : CompilerGeneratedClass
1971 static int types_counter;
1972 public const string ClassNamePrefix = "<>__AnonType";
1973 public const string SignatureForError = "anonymous type";
1975 static readonly IntConstant FNV_prime = new IntConstant (16777619, Location.Null);
1977 readonly ArrayList parameters;
1979 private AnonymousTypeClass (DeclSpace parent, MemberName name, ArrayList parameters, Location loc)
1980 : base (parent, name, Modifiers.SEALED, loc)
1982 this.parameters = parameters;
1985 public static AnonymousTypeClass Create (TypeContainer parent, ArrayList parameters, Location loc)
1987 if (RootContext.Version <= LanguageVersion.ISO_2)
1988 Report.FeatureIsNotAvailable (loc, "anonymous types");
1990 string name = ClassNamePrefix + types_counter++;
1992 SimpleName [] t_args = new SimpleName [parameters.Count];
1993 Parameter [] ctor_params = new Parameter [parameters.Count];
1994 for (int i = 0; i < parameters.Count; ++i) {
1995 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1997 t_args [i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
1998 ctor_params [i] = new Parameter (t_args [i], p.Name, 0, null, p.Location);
2002 // Create generic anonymous type host with generic arguments
2003 // named upon properties names
2005 AnonymousTypeClass a_type = new AnonymousTypeClass (parent.NamespaceEntry.SlaveDeclSpace,
2006 new MemberName (name, new TypeArguments (loc, t_args), loc), parameters, loc);
2008 if (parameters.Count > 0)
2009 a_type.SetParameterInfo (null);
2011 Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC,
2012 new Parameters (ctor_params), null, loc);
2013 c.OptAttributes = a_type.GetDebuggerHiddenAttribute ();
2014 c.Block = new ToplevelBlock (c.Parameters, loc);
2017 // Create fields and contructor body with field initialization
2020 for (int i = 0; i < parameters.Count; ++i) {
2021 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
2023 Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY,
2024 "<" + p.Name + ">", null, p.Location);
2026 if (!a_type.AddField (f)) {
2028 Report.Error (833, p.Location, "`{0}': An anonymous type cannot have multiple properties with the same name",
2033 c.Block.AddStatement (new StatementExpression (
2034 new Assign (new MemberAccess (new This (p.Location), f.Name),
2035 c.Block.GetParameterReference (p.Name, p.Location))));
2037 ToplevelBlock get_block = new ToplevelBlock (p.Location);
2038 get_block.AddStatement (new Return (
2039 new MemberAccess (new This (p.Location), f.Name), p.Location));
2040 Accessor get_accessor = new Accessor (get_block, 0, null, p.Location);
2041 Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC, false,
2042 new MemberName (p.Name, p.Location), null, get_accessor, null, false);
2043 a_type.AddProperty (prop);
2049 a_type.AddConstructor (c);
2053 protected override bool AddToContainer (MemberCore symbol, string name)
2055 MemberCore mc = (MemberCore) defined_names [name];
2058 defined_names.Add (name, symbol);
2062 Report.SymbolRelatedToPreviousError (mc);
2066 void DefineOverrides ()
2068 Location loc = Location;
2070 Method equals = new Method (this, null, TypeManager.system_boolean_expr,
2071 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("Equals", loc),
2072 new Parameters (new Parameter (TypeManager.system_object_expr, "obj", 0, null, loc)),
2073 GetDebuggerHiddenAttribute ());
2075 Method tostring = new Method (this, null, TypeManager.system_string_expr,
2076 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("ToString", loc),
2077 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
2079 ToplevelBlock equals_block = new ToplevelBlock (equals.Parameters, loc);
2080 TypeExpr current_type;
2082 current_type = new ConstructedType (TypeBuilder, TypeParameters, loc);
2084 current_type = new TypeExpression (TypeBuilder, loc);
2086 equals_block.AddVariable (current_type, "other", loc);
2087 LocalVariableReference other_variable = new LocalVariableReference (equals_block, "other", loc);
2089 MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
2090 new SimpleName ("System", loc), "Collections", loc), "Generic", loc);
2092 Expression rs_equals = null;
2093 Expression string_concat = new StringConstant ("<empty type>", loc);
2094 Expression rs_hashcode = new IntConstant (-2128831035, loc);
2095 for (int i = 0; i < parameters.Count; ++i) {
2096 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
2097 Field f = (Field) Fields [i];
2099 MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
2100 system_collections_generic, "EqualityComparer",
2101 new TypeArguments (loc, new SimpleName (TypeParameters [i].Name, loc)), loc),
2104 ArrayList arguments_equal = new ArrayList (2);
2105 arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2106 arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name)));
2108 Expression field_equal = new Invocation (new MemberAccess (equality_comparer,
2109 "Equals", loc), arguments_equal);
2111 ArrayList arguments_hashcode = new ArrayList (1);
2112 arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2113 Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer,
2114 "GetHashCode", loc), arguments_hashcode);
2116 rs_hashcode = new Binary (Binary.Operator.Multiply,
2117 new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode),
2120 Expression field_to_string = new Conditional (new Binary (Binary.Operator.Inequality,
2121 new MemberAccess (new This (f.Location), f.Name), new NullLiteral (loc)),
2122 new Invocation (new MemberAccess (
2123 new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
2124 new StringConstant ("<null>", loc));
2126 if (rs_equals == null) {
2127 rs_equals = field_equal;
2128 string_concat = new Binary (Binary.Operator.Addition,
2129 new StringConstant (p.Name + " = ", loc),
2135 // Implementation of ToString () body using string concatenation
2137 string_concat = new Binary (Binary.Operator.Addition,
2138 new Binary (Binary.Operator.Addition,
2140 new StringConstant (", " + p.Name + " = ", loc)),
2143 rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal);
2147 // Equals (object obj) override
2149 equals_block.AddStatement (new StatementExpression (
2150 new Assign (other_variable,
2151 new As (equals_block.GetParameterReference ("obj", loc),
2152 current_type, loc), loc)));
2154 Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc));
2155 if (rs_equals != null)
2156 equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals);
2157 equals_block.AddStatement (new Return (equals_test, loc));
2159 equals.Block = equals_block;
2160 equals.ResolveMembers ();
2164 // GetHashCode () override
2166 Method hashcode = new Method (this, null, TypeManager.system_int32_expr,
2167 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("GetHashCode", loc),
2168 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
2171 // Modified FNV with good avalanche behavior and uniform
2172 // distribution with larger hash sizes.
2174 // const int FNV_prime = 16777619;
2175 // int hash = (int) 2166136261;
2176 // foreach (int d in data)
2177 // hash = (hash ^ d) * FNV_prime;
2178 // hash += hash << 13;
2179 // hash ^= hash >> 7;
2180 // hash += hash << 3;
2181 // hash ^= hash >> 17;
2182 // hash += hash << 5;
2184 ToplevelBlock hashcode_block = new ToplevelBlock (loc);
2185 hashcode_block.AddVariable (TypeManager.system_int32_expr, "hash", loc);
2186 LocalVariableReference hash_variable = new LocalVariableReference (hashcode_block, "hash", loc);
2187 hashcode_block.AddStatement (new StatementExpression (
2188 new Assign (hash_variable, rs_hashcode)));
2190 hashcode_block.AddStatement (new StatementExpression (
2191 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2192 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (13, loc)))));
2193 hashcode_block.AddStatement (new StatementExpression (
2194 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2195 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (7, loc)))));
2196 hashcode_block.AddStatement (new StatementExpression (
2197 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2198 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (3, loc)))));
2199 hashcode_block.AddStatement (new StatementExpression (
2200 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2201 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (17, loc)))));
2202 hashcode_block.AddStatement (new StatementExpression (
2203 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2204 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (5, loc)))));
2206 hashcode_block.AddStatement (new Return (hash_variable, loc));
2207 hashcode.Block = hashcode_block;
2208 hashcode.ResolveMembers ();
2209 AddMethod (hashcode);
2212 // ToString () override
2215 ToplevelBlock tostring_block = new ToplevelBlock (loc);
2216 tostring_block.AddStatement (new Return (string_concat, loc));
2217 tostring.Block = tostring_block;
2218 tostring.ResolveMembers ();
2219 AddMethod (tostring);
2222 public override bool DefineMembers ()
2226 return base.DefineMembers ();
2229 Attributes GetDebuggerHiddenAttribute ()
2231 return new Attributes (new Attribute (null, null,
2232 "System.Diagnostics.DebuggerHiddenAttribute", null, Location, false));
2235 public override string GetSignatureForError ()
2237 return SignatureForError;
2240 public ArrayList Parameters {