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 protected string MakeFieldName (string local_name)
415 return "<" + ID + ":" + local_name + ">";
418 protected virtual ScopeInitializer CreateScopeInitializer ()
420 return new ScopeInitializer (this);
423 protected abstract class CapturedVariable : Variable
425 public readonly ScopeInfo Scope;
426 public readonly string Name;
428 public FieldExpr FieldInstance;
429 protected Field field;
431 protected CapturedVariable (ScopeInfo scope, string name)
437 protected CapturedVariable (ScopeInfo scope, string name, Type type)
440 this.field = scope.CaptureVariable (
441 scope.MakeFieldName (name), scope.RootScope.InflateType (type));
445 get { return field; }
448 public override Type Type {
449 get { return Field.MemberType; }
452 public override bool HasInstance {
456 public override bool NeedsTemporary {
460 protected FieldInfo GetField (EmitContext ec)
462 if ((ec.CurrentBlock != null) &&
463 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel))
464 return Field.FieldBuilder;
466 return FieldInstance.FieldInfo;
469 public override void EmitInstance (EmitContext ec)
471 if ((ec.CurrentAnonymousMethod != null) &&
472 (ec.CurrentAnonymousMethod.Scope == Scope)) {
473 ec.ig.Emit (OpCodes.Ldarg_0);
477 Scope.EmitScopeInstance (ec);
480 public override void Emit (EmitContext ec)
482 ec.ig.Emit (OpCodes.Ldfld, GetField (ec));
485 public override void EmitAssign (EmitContext ec)
487 ec.ig.Emit (OpCodes.Stfld, GetField (ec));
490 public override void EmitAddressOf (EmitContext ec)
492 ec.ig.Emit (OpCodes.Ldflda, GetField (ec));
496 protected class CapturedParameter : CapturedVariable {
497 public readonly Parameter Parameter;
498 public readonly int Idx;
500 public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
501 : base (scope, par.Name, par.ParameterType)
503 this.Parameter = par;
507 public override string ToString ()
509 return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
510 Parameter.Name, Idx);
514 protected class CapturedLocal : CapturedVariable {
515 public readonly LocalInfo Local;
517 public CapturedLocal (ScopeInfo scope, LocalInfo local)
518 : base (scope, local.Name, local.VariableType)
523 public override string ToString ()
525 return String.Format ("{0} ({1}:{2})", GetType (), Field,
530 protected class CapturedThis : CapturedVariable {
531 public CapturedThis (RootScopeInfo host)
532 : base (host, "<>THIS", host.ParentType)
536 protected class CapturedScope : CapturedVariable {
537 public readonly ScopeInfo ChildScope;
539 public CapturedScope (ScopeInfo root, ScopeInfo child)
540 : base (root, "scope" + child.ID)
542 this.ChildScope = child;
545 public bool DefineMembers ()
547 Type type = ChildScope.IsGeneric ?
548 ChildScope.CurrentType : ChildScope.TypeBuilder;
549 Report.Debug (128, "CAPTURED SCOPE DEFINE MEMBERS", this, Scope,
550 ChildScope, Name, type);
552 throw new InternalErrorException ();
553 field = Scope.CaptureVariable (
554 Scope.MakeFieldName (Name), Scope.InflateType (type));
558 public override string ToString ()
560 return String.Format ("CapturedScope ({1} captured in {0})",
565 static void DoPath (StringBuilder sb, ScopeInfo start)
567 sb.Append ((start.ID).ToString ());
570 public override string ToString ()
572 StringBuilder sb = new StringBuilder ();
578 return sb.ToString ();
581 protected class ScopeInitializer : ExpressionStatement
584 CapturedVariable captured_scope;
585 LocalBuilder scope_instance;
586 ConstructorInfo scope_ctor;
590 public ScopeInitializer (ScopeInfo scope)
593 this.loc = scope.Location;
594 eclass = ExprClass.Value;
597 public ScopeInfo Scope {
598 get { return scope; }
601 public override Expression DoResolve (EmitContext ec)
603 if (scope_ctor != null)
606 Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
607 ec, ec.CurrentBlock);
609 type = Scope.GetScopeType (ec);
611 throw new InternalErrorException ();
613 if (!DoResolveInternal (ec))
614 throw new InternalErrorException ();
619 protected virtual bool DoResolveInternal (EmitContext ec)
621 MethodGroupExpr mg = (MethodGroupExpr) MemberLookupFinal (
622 ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
623 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
625 throw new InternalErrorException ();
627 scope_ctor = (ConstructorInfo) mg.Methods [0];
629 Report.Debug (128, "RESOLVE THE INIT", this, Scope, Scope.RootScope,
630 Scope.RootScope.GetType ());
632 ScopeInfo host = Scope.RootScope;
633 if ((Scope != host) && (Scope.RootScope is IteratorHost)) {
634 captured_scope = host.GetCapturedScope (Scope);
635 Type root = host.GetScopeType (ec);
636 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
637 type, root, captured_scope.Field.Name, loc);
639 throw new InternalErrorException ();
641 fe.InstanceExpression = this;
642 captured_scope.FieldInstance = fe;
644 Report.Debug (128, "RESOLVE THE INIT #1", this,
647 scope_instance = ec.ig.DeclareLocal (type);
649 foreach (CapturedLocal local in Scope.locals.Values) {
650 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
651 ec.ContainerType, type, local.Field.Name, loc);
652 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
653 Scope, ec, ec.ContainerType, type,
654 local.Field, local.Field.Name, loc, fe);
656 throw new InternalErrorException ();
658 fe.InstanceExpression = this;
659 local.FieldInstance = fe;
662 if (Scope.HostsParameters) {
663 foreach (CapturedParameter cp in Scope.captured_params.Values) {
664 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
665 ec.ContainerType, type, cp.Field.Name, loc);
667 throw new InternalErrorException ();
669 fe.InstanceExpression = this;
670 cp.FieldInstance = fe;
674 foreach (CapturedScope scope in Scope.CapturedScopes) {
675 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
676 ec.ContainerType, type, scope.Field.Name, loc);
677 Report.Debug (64, "RESOLVE SCOPE INITIALIZER #3", this, Scope,
678 scope, ec, ec.ContainerType, type,
679 scope.Field, scope.Field.Name, loc, fe);
681 throw new InternalErrorException ();
683 fe.InstanceExpression = this;
684 scope.FieldInstance = fe;
690 protected virtual void EmitParameterReference (EmitContext ec,
691 CapturedParameter cp)
693 int extra = ec.MethodIsStatic ? 0 : 1;
694 ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
700 protected virtual void DoEmit (EmitContext ec)
702 if ((ec.CurrentBlock != null) &&
703 (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)) {
704 ec.ig.Emit (OpCodes.Ldarg_0);
706 if (ec.CurrentAnonymousMethod != null) {
707 ScopeInfo host = ec.CurrentAnonymousMethod.Scope;
708 Variable captured = host.GetCapturedScope (scope);
709 Report.Debug (128, "EMIT SCOPE INSTANCE #2",
710 ec.CurrentAnonymousMethod, host,
712 if (captured != null)
715 } else if (scope_instance != null)
716 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
718 Report.Debug (128, "DO EMIT", this, Scope, ec,
719 scope_instance, captured_scope);
720 captured_scope.EmitInstance (ec);
721 captured_scope.Emit (ec);
725 protected void DoEmitInstance (EmitContext ec)
727 Report.Debug (128, "DO EMIT INSTANCE", this, Scope, ec,
728 scope_instance, captured_scope);
730 if (scope_instance != null)
731 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
733 captured_scope.EmitInstance (ec);
736 protected virtual void EmitScopeConstructor (EmitContext ec)
738 ec.ig.Emit (OpCodes.Newobj, scope_ctor);
741 public override void Emit (EmitContext ec)
744 throw new InternalErrorException (
745 "Scope {0} not initialized yet", scope);
750 public override void EmitStatement (EmitContext ec)
755 DoEmitStatement (ec);
759 protected virtual void DoEmitStatement (EmitContext ec)
761 Report.Debug (128, "EMIT SCOPE INITIALIZER STATEMENT", this, id,
762 Scope, scope_instance, ec);
764 ec.ig.Emit (OpCodes.Nop);
765 ec.ig.Emit (OpCodes.Ldc_I4, id);
766 ec.ig.Emit (OpCodes.Pop);
767 ec.ig.Emit (OpCodes.Nop);
769 if (scope_instance == null)
770 ec.ig.Emit (OpCodes.Ldarg_0);
771 EmitScopeConstructor (ec);
772 if (scope_instance != null)
773 ec.ig.Emit (OpCodes.Stloc, scope_instance);
775 captured_scope.EmitAssign (ec);
777 if (Scope.HostsParameters) {
778 foreach (CapturedParameter cp in Scope.captured_params.Values) {
779 Report.Debug (128, "EMIT SCOPE INIT #6", this,
780 ec, ec.IsStatic, Scope, cp, cp.Field.Name);
782 EmitParameterReference (ec, cp);
783 ec.ig.Emit (OpCodes.Stfld, cp.FieldInstance.FieldInfo);
787 if (Scope is IteratorHost)
790 foreach (CapturedScope scope in Scope.CapturedScopes) {
791 ScopeInfo child = scope.ChildScope;
793 Report.Debug (128, "EMIT SCOPE INIT #5", this, Scope,
794 scope.Scope, scope.ChildScope);
796 ExpressionStatement init = child.GetScopeInitializer (ec);
797 init.EmitStatement (ec);
800 scope.ChildScope.EmitScopeInstance (ec);
801 scope.EmitAssign (ec);
807 public class RootScopeInfo : ScopeInfo
809 public RootScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
810 GenericMethod generic, Location loc)
811 : base (toplevel, parent, generic, loc)
813 scopes = new ArrayList ();
816 TypeExpr parent_type;
817 CapturedVariableField parent_link;
818 CapturedThis this_variable;
819 protected ArrayList scopes;
821 public virtual bool IsIterator {
822 get { return false; }
825 public RootScopeInfo ParentHost {
826 get { return Parent.PartialContainer as RootScopeInfo; }
829 public Type ParentType {
830 get { return parent_type.Type; }
833 public Field ParentLink {
834 get { return parent_link; }
837 protected CapturedThis THIS {
838 get { return this_variable; }
841 public Variable CaptureThis ()
843 if (ParentHost != null)
844 return ParentHost.CaptureThis ();
846 CheckMembersDefined ();
847 if (this_variable == null)
848 this_variable = new CapturedThis (this);
849 return this_variable;
852 public void AddScope (ScopeInfo scope)
858 public void LinkScopes ()
860 Report.Debug (128, "LINK SCOPES", this, linked, scopes);
866 if (ParentHost != null)
867 ParentHost.LinkScopes ();
869 foreach (ScopeInfo si in scopes) {
871 throw new InternalErrorException ();
872 if (si.DefineType () == null)
873 throw new InternalErrorException ();
874 if (!si.ResolveType ())
875 throw new InternalErrorException ();
878 foreach (ScopeInfo si in scopes) {
879 if (!si.ResolveMembers ())
880 throw new InternalErrorException ();
881 if (!si.DefineMembers ())
882 throw new InternalErrorException ();
886 protected override ScopeInitializer CreateScopeInitializer ()
888 return new RootScopeInitializer (this);
891 protected override bool DefineNestedTypes ()
893 if (Parent.IsGeneric) {
894 parent_type = new ConstructedType (
895 Parent.TypeBuilder, Parent.TypeParameters, Location);
896 parent_type = parent_type.ResolveAsTypeTerminal (this, false);
897 if ((parent_type == null) || (parent_type.Type == null))
900 parent_type = new TypeExpression (Parent.TypeBuilder, Location);
903 CompilerGeneratedClass parent = Parent.PartialContainer as CompilerGeneratedClass;
905 parent_link = new CapturedVariableField (this, "<>parent", parent_type);
907 return base.DefineNestedTypes ();
910 protected override bool DoDefineMembers ()
912 ArrayList args = new ArrayList ();
913 if (this is IteratorHost)
914 args.Add (new Parameter (
915 TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
919 if (Parent is CompilerGeneratedClass)
920 pfield = parent_link;
922 pfield = this_variable != null ? this_variable.Field : null;
924 args.Add (new Parameter (
925 pfield.MemberType, "parent", Parameter.Modifier.NONE,
928 Parameter[] ctor_params = new Parameter [args.Count];
929 args.CopyTo (ctor_params, 0);
930 Constructor ctor = new Constructor (
931 this, MemberName.Name, Modifiers.PUBLIC,
932 new Parameters (ctor_params),
933 new GeneratedBaseInitializer (Location),
935 AddConstructor (ctor);
937 ctor.Block = new ToplevelBlock (null, Location);
938 ctor.Block.AddStatement (new TheCtor (this));
940 return base.DoDefineMembers ();
943 protected virtual void EmitScopeConstructor (EmitContext ec)
945 int pos = (this is IteratorHost) ? 2 : 1;
948 if (Parent is CompilerGeneratedClass)
949 pfield = parent_link;
951 pfield = this_variable != null ? this_variable.Field : null;
953 if (pfield != null) {
954 ec.ig.Emit (OpCodes.Ldarg_0);
955 ec.ig.Emit (OpCodes.Ldarg, pos);
956 ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
961 protected class TheCtor : Statement
965 public TheCtor (RootScopeInfo host)
970 public override bool Resolve (EmitContext ec)
975 protected override void DoEmit (EmitContext ec)
977 host.EmitScopeConstructor (ec);
981 protected class RootScopeInitializer : ScopeInitializer
985 public RootScopeInitializer (RootScopeInfo host)
991 public RootScopeInfo Host {
995 protected override bool DoResolveInternal (EmitContext ec)
997 Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
998 this, Host, Host.ParentType, loc);
1000 if (Host.THIS != null) {
1001 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
1002 ec.ContainerType, type, Host.THIS.Field.Name, loc);
1004 throw new InternalErrorException ();
1006 fe.InstanceExpression = this;
1007 Host.THIS.FieldInstance = fe;
1010 return base.DoResolveInternal (ec);
1013 protected virtual bool IsGetEnumerator {
1014 get { return false; }
1017 protected override void EmitScopeConstructor (EmitContext ec)
1019 if (host.THIS != null) {
1020 ec.ig.Emit (OpCodes.Ldarg_0);
1021 if (IsGetEnumerator)
1022 ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
1023 else if (host.THIS.Type.IsValueType)
1024 Expression.LoadFromPtr (ec.ig, host.THIS.Type);
1025 } else if (host.ParentLink != null)
1026 ec.ig.Emit (OpCodes.Ldarg_0);
1028 base.EmitScopeConstructor (ec);
1034 public interface IAnonymousContainer
1040 GenericMethod GenericMethod {
1044 RootScopeInfo RootScope {
1053 public interface IAnonymousHost
1056 // Invoked if a yield statement is found in the body
1061 // Invoked if an anonymous method is found in the body
1063 void AddAnonymousMethod (AnonymousMethodExpression anonymous);
1066 public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
1068 public readonly AnonymousMethodExpression Parent;
1069 public readonly TypeContainer Host;
1070 public readonly Parameters Parameters;
1072 public ToplevelBlock Block;
1074 protected Block container;
1075 protected readonly GenericMethod generic;
1077 public Block Container {
1078 get { return container; }
1081 public GenericMethod GenericMethod {
1082 get { return generic; }
1085 public RootScopeInfo RootScope {
1086 get { return root_scope; }
1089 public AnonymousMethodExpression (AnonymousMethodExpression parent,
1090 GenericMethod generic, TypeContainer host,
1091 Parameters parameters, Block container,
1094 this.Parent = parent;
1095 this.generic = parent != null ? null : generic;
1097 this.Parameters = parameters;
1098 this.container = container;
1101 Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host,
1105 parent.AddAnonymousMethod (this);
1109 RootScopeInfo root_scope;
1111 static int next_index;
1113 void IAnonymousHost.SetYields ()
1115 throw new InvalidOperationException ();
1118 public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
1120 if (children == null)
1121 children = new ArrayList ();
1122 children.Add (anonymous);
1125 public bool CreateAnonymousHelpers ()
1127 Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
1128 this, Host, container, loc);
1130 if (container != null)
1131 root_scope = container.Toplevel.CreateRootScope (Host);
1133 if (children != null) {
1134 foreach (AnonymousMethodExpression child in children) {
1135 if (!child.CreateAnonymousHelpers ())
1143 public override string ExprClassName {
1145 return "anonymous method";
1149 public virtual bool HasExplicitParameters {
1156 // Returns true if the body of lambda expression can be implicitly
1157 // converted to the delegate of type `delegate_type'
1159 public bool ImplicitStandardConversionExists (Type delegate_type)
1161 EmitContext ec = EmitContext.TempEc;
1162 using (ec.Set (EmitContext.Flags.ProbingMode)) {
1163 return Compatible (ec, delegate_type) != null;
1167 protected Expression CompatibleChecks (EmitContext ec, Type delegate_type)
1169 if (!ec.IsAnonymousMethodAllowed) {
1170 Report.Error (1706, loc,
1171 "Anonymous methods are not allowed in the " +
1172 "attribute declaration");
1176 if (!TypeManager.IsDelegateType (delegate_type)){
1177 Report.Error (1660, loc,
1178 "Cannot convert `{0}' to type " +
1179 "`{1}' because it is not a delegate type",
1180 GetSignatureForError (), TypeManager.CSharpName (delegate_type));
1186 protected bool VerifyExplicitParameters (Type delegateType, ParameterData parameters, bool ignoreError)
1188 if (VerifyParameterCompatibility (delegateType, parameters, ignoreError))
1192 Report.Error (1661, loc,
1193 "Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch",
1194 GetSignatureForError (), TypeManager.CSharpName (delegateType));
1199 bool VerifyParameterCompatibility (Type delegate_type, ParameterData invoke_pd, bool ignoreErrors)
1201 if (Parameters.Count != invoke_pd.Count) {
1205 Report.SymbolRelatedToPreviousError (delegate_type);
1206 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1207 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1212 for (int i = 0; i < Parameters.Count; ++i) {
1213 Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1214 if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1218 if (p_mod == Parameter.Modifier.NONE)
1219 Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1220 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1222 Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1223 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1228 Type type = invoke_pd.Types [i];
1230 // We assume that generic parameters are always inflated
1231 if (TypeManager.IsGenericParameter (type))
1234 if (TypeManager.HasElementType (type) && TypeManager.IsGenericParameter (TypeManager.GetElementType (type)))
1237 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1241 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1243 TypeManager.CSharpName (Parameters.ParameterType (i)),
1244 TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1253 // Infers type arguments based on explicit arguments
1255 public void ExplicitTypeInference (TypeInferenceContext typeInference, Type delegateType)
1257 if (!HasExplicitParameters)
1260 if (!TypeManager.IsDelegateType (delegateType))
1263 ParameterData d_params = TypeManager.GetDelegateParameters (delegateType);
1264 if (d_params.Count != Parameters.Count)
1267 for (int i = 0; i < Parameters.Count; ++i) {
1268 Type itype = d_params.Types [i];
1269 if (!TypeManager.IsGenericParameter (itype)) {
1270 if (!itype.HasElementType)
1273 if (!TypeManager.IsGenericParameter (itype.GetElementType ()))
1276 typeInference.ExactInference (Parameters.FixedParameters[i].ParameterType, itype);
1280 public Type InferReturnType (EmitContext ec, TypeInferenceContext tic, Type delegateType)
1283 using (ec.Set (EmitContext.Flags.ProbingMode | EmitContext.Flags.InferReturnType)) {
1284 am = CompatibleMethod (ec, tic, GetType (), delegateType);
1290 if (am.ReturnType == TypeManager.null_type)
1291 am.ReturnType = null;
1293 return am.ReturnType;
1297 // Returns AnonymousMethod container if this anonymous method
1298 // expression can be implicitly converted to the delegate type `delegate_type'
1300 public AnonymousMethod Compatible (EmitContext ec, Type delegateType)
1302 if (CompatibleChecks (ec, delegateType) == null)
1306 // At this point its the first time we know the return type that is
1307 // needed for the anonymous method. We create the method here.
1310 MethodInfo invoke_mb = Delegate.GetInvokeMethod (
1311 ec.ContainerType, delegateType);
1312 Type return_type = invoke_mb.ReturnType;
1315 Type[] g_args = delegateType.GetGenericArguments ();
1316 if (return_type.IsGenericParameter)
1317 return_type = g_args [return_type.GenericParameterPosition];
1321 // Second: the return type of the delegate must be compatible with
1322 // the anonymous type. Instead of doing a pass to examine the block
1323 // we satisfy the rule by setting the return type on the EmitContext
1324 // to be the delegate type return type.
1327 Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1328 Container, Block, return_type, delegateType,
1329 TypeManager.IsGenericType (delegateType), loc);
1332 return CompatibleMethod (ec, null, return_type, delegateType);
1333 } catch (Exception e) {
1334 throw new InternalErrorException (e, loc);
1338 protected virtual Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegateType)
1340 ParameterData delegateParameters = TypeManager.GetDelegateParameters (delegateType);
1342 if (Parameters == null) {
1344 // We provide a set of inaccessible parameters
1346 Parameter[] fixedpars = new Parameter[delegateParameters.Count];
1348 for (int i = 0; i < delegateParameters.Count; i++) {
1349 Parameter.Modifier i_mod = delegateParameters.ParameterModifier (i);
1350 if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1351 Report.Error (1688, loc, "Cannot convert anonymous " +
1352 "method block without a parameter list " +
1353 "to delegate type `{0}' because it has " +
1354 "one or more `out' parameters.",
1355 TypeManager.CSharpName (delegateType));
1358 fixedpars[i] = new Parameter (
1359 delegateParameters.ParameterType (i), "+" + (++next_index),
1360 delegateParameters.ParameterModifier (i), null, loc);
1363 return Parameters.CreateFullyResolved (fixedpars, delegateParameters.Types);
1366 if (!VerifyExplicitParameters (delegateType, delegateParameters, ec.IsInProbingMode)) {
1373 public override Expression DoResolve (EmitContext ec)
1376 // Set class type, set type
1379 eclass = ExprClass.Value;
1382 // This hack means `The type is not accessible
1383 // anywhere', we depend on special conversion
1386 type = TypeManager.anonymous_method_type;
1388 if ((Parameters != null) && !Parameters.Resolve (ec))
1394 public override void Emit (EmitContext ec)
1396 // nothing, as we only exist to not do anything.
1399 public override string GetSignatureForError ()
1401 return ExprClassName;
1404 public bool IsIterator {
1405 get { return false; }
1408 protected AnonymousMethod CompatibleMethod (EmitContext ec, TypeInferenceContext tic, Type returnType, Type delegateType)
1410 Parameters p = ResolveParameters (ec, tic, delegateType);
1414 ToplevelBlock b = ec.IsInProbingMode ? (ToplevelBlock) Block.PerformClone () : Block;
1416 AnonymousMethod anonymous = CompatibleMethodFactory (returnType, delegateType, p, b);
1417 if (!anonymous.Compatible (ec))
1423 protected virtual AnonymousMethod CompatibleMethodFactory (Type returnType, Type delegateType, Parameters p, ToplevelBlock b)
1425 return new AnonymousMethod (RootScope, Host,
1426 GenericMethod, p, Container, b, returnType,
1430 protected override void CloneTo (CloneContext clonectx, Expression t)
1432 AnonymousMethodExpression target = (AnonymousMethodExpression) t;
1434 target.Block = (ToplevelBlock) clonectx.LookupBlock (Block);
1435 target.container = clonectx.LookupBlock (Block);
1439 public abstract class AnonymousContainer : IAnonymousContainer
1441 public readonly Location Location;
1443 public Parameters Parameters;
1446 // The block that makes up the body for the anonymous mehtod
1448 public readonly ToplevelBlock Block;
1450 public readonly int ModFlags;
1451 public Type ReturnType;
1452 public readonly DeclSpace Host;
1455 // The implicit method we create
1457 protected Method method;
1458 protected EmitContext aec;
1460 // The emit context for the anonymous method
1461 protected bool unreachable;
1462 protected readonly Block container;
1463 protected readonly GenericMethod generic;
1465 protected AnonymousContainer (DeclSpace host,
1466 GenericMethod generic, Parameters parameters,
1467 Block container, ToplevelBlock block,
1468 Type return_type, int mod, Location loc)
1470 this.ReturnType = return_type;
1471 this.ModFlags = mod | Modifiers.COMPILER_GENERATED;
1474 this.container = container;
1475 this.generic = generic;
1476 this.Parameters = parameters;
1478 this.Location = loc;
1480 block.AnonymousContainer = this;
1483 public Method Method {
1484 get { return method; }
1487 public abstract string ContainerType {
1491 public abstract RootScopeInfo RootScope {
1495 public abstract ScopeInfo Scope {
1499 public abstract string GetSignatureForError ();
1501 public bool Compatible (EmitContext ec)
1503 // REFACTOR: The method should be refactor, many of the
1504 // hacks can be handled in better way
1506 Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1507 RootScope, Parameters, ec.IsStatic);
1509 if (ReturnType != null) {
1510 TypeExpr return_type_expr;
1511 if (RootScope != null)
1512 return_type_expr = RootScope.InflateType (ReturnType);
1514 return_type_expr = new TypeExpression (ReturnType, Location);
1515 return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
1516 if ((return_type_expr == null) || (return_type_expr.Type == null))
1518 ReturnType = return_type_expr.Type;
1521 // Linq type inference is done differently
1522 if (RootScope != null && RootContext.Version != LanguageVersion.LINQ)
1523 Parameters = RootScope.InflateParameters (Parameters);
1525 aec = new EmitContext (
1526 ec.ResolveContext, ec.TypeContainer,
1527 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1528 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1529 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1531 aec.CurrentAnonymousMethod = this;
1532 aec.IsStatic = ec.IsStatic;
1534 IDisposable aec_dispose = null;
1535 if (ec.InferReturnType)
1536 aec_dispose = aec.Set (EmitContext.Flags.InferReturnType);
1537 if (ec.IsInProbingMode)
1538 aec_dispose = aec.Set (EmitContext.Flags.ProbingMode);
1539 if (ec.IsInFieldInitializer)
1540 aec_dispose = aec.Set (EmitContext.Flags.InFieldInitializer);
1542 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1543 RootScope, Parameters, Block);
1546 bool res = aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable);
1548 if (ec.InferReturnType)
1549 ReturnType = aec.ReturnType;
1551 if (aec_dispose != null) {
1552 aec_dispose.Dispose ();
1558 public abstract Expression Resolve (EmitContext ec);
1560 public virtual bool Define (EmitContext ec)
1562 Report.Debug (64, "DEFINE ANONYMOUS METHOD #3", this, ec, aec, Block);
1564 if (aec == null && !Compatible (ec))
1567 // Don't define anything when we are in probing scope (nested anonymous methods)
1568 if (ec.IsInProbingMode)
1571 method = DoCreateMethodHost (ec);
1576 if (!method.ResolveMembers ())
1578 return method.Define ();
1581 protected abstract Method DoCreateMethodHost (EmitContext ec);
1583 public Block Container {
1584 get { return container; }
1587 public GenericMethod GenericMethod {
1588 get { return generic; }
1591 public abstract bool IsIterator {
1595 protected class AnonymousMethodMethod : Method
1597 public readonly AnonymousContainer AnonymousMethod;
1598 public readonly ScopeInfo Scope;
1600 public AnonymousMethodMethod (AnonymousContainer am, ScopeInfo scope,
1601 GenericMethod generic, TypeExpr return_type,
1602 int mod, MemberName name, Parameters parameters)
1603 : base (scope != null ? scope : am.Host,
1604 generic, return_type, mod | Modifiers.COMPILER_GENERATED, false, name, parameters, null)
1606 this.AnonymousMethod = am;
1609 if (scope != null) {
1610 scope.CheckMembersDefined ();
1611 scope.AddMethod (this);
1613 ModFlags |= Modifiers.STATIC;
1614 am.Host.PartialContainer.AddMethod (this);
1619 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1621 EmitContext aec = AnonymousMethod.aec;
1623 aec.MethodIsStatic = Scope == null;
1629 public class AnonymousMethod : AnonymousContainer
1634 // The value return by the Compatible call, this ensure that
1635 // the code works even if invoked more than once (Resolve called
1636 // more than once, due to the way Convert.ImplicitConversion works
1638 RootScopeInfo root_scope;
1641 public AnonymousMethod (RootScopeInfo root_scope,
1642 DeclSpace host, GenericMethod generic,
1643 Parameters parameters, Block container,
1644 ToplevelBlock block, Type return_type, Type delegate_type,
1646 : base (host, generic, parameters, container, block,
1647 return_type, 0, loc)
1649 this.DelegateType = delegate_type;
1650 this.root_scope = root_scope;
1653 public override string ContainerType {
1654 get { return "anonymous method"; }
1657 public override RootScopeInfo RootScope {
1658 get { return root_scope; }
1661 public override ScopeInfo Scope {
1662 get { return scope; }
1665 public override bool IsIterator {
1666 get { return false; }
1669 public override string GetSignatureForError ()
1671 return TypeManager.CSharpName (DelegateType);
1675 // Creates the host for the anonymous method
1677 protected override Method DoCreateMethodHost (EmitContext ec)
1679 MemberCore mc = ec.ResolveContext as MemberCore;
1680 string name = CompilerGeneratedClass.MakeName (mc.Name, null);
1681 MemberName member_name;
1683 Report.Debug (128, "CREATE METHOD HOST #0", RootScope);
1688 Report.Debug (128, "CREATE METHOD HOST #1", this, Block, Block.ScopeInfo,
1689 RootScope, Location);
1691 for (b = Block.Parent; b != null; b = b.Parent) {
1692 Report.Debug (128, "CREATE METHOD HOST #2", this, Block,
1694 if (b.ScopeInfo != null) {
1695 scope = b.ScopeInfo;
1701 scope.CheckMembersDefined ();
1703 ArrayList scopes = new ArrayList ();
1705 for (b = b.Parent; b != null; b = b.Parent) {
1706 if (b.ScopeInfo != null)
1707 scopes.Add (b.ScopeInfo);
1711 Report.Debug (128, "CREATE METHOD HOST #1", this, scope, scopes);
1713 foreach (ScopeInfo si in scopes)
1714 scope.CaptureScope (si);
1716 Report.Debug (128, "CREATE METHOD HOST", this, Block, container,
1717 RootScope, scope, scopes, Location);
1719 GenericMethod generic_method = null;
1721 if (TypeManager.IsGenericType (DelegateType)) {
1722 TypeArguments args = new TypeArguments (Location);
1724 Type dt = DelegateType.GetGenericTypeDefinition ();
1726 Type[] tparam = TypeManager.GetTypeArguments (dt);
1727 for (int i = 0; i < tparam.Length; i++)
1728 args.Add (new SimpleName (tparam [i].Name, Location));
1730 member_name = new MemberName (name, args, Location);
1732 Report.Debug (128, "CREATE METHOD HOST #5", this, DelegateType,
1733 TypeManager.GetTypeArguments (DelegateType),
1736 generic_method = new GenericMethod (
1737 Host.NamespaceEntry, scope, member_name,
1738 new TypeExpression (ReturnType, Location), Parameters);
1740 generic_method.SetParameterInfo (null);
1743 member_name = new MemberName (name, Location);
1745 return new AnonymousMethodMethod (
1746 this, scope, generic_method, new TypeExpression (ReturnType, Location),
1747 scope == null ? Modifiers.PRIVATE : Modifiers.INTERNAL, member_name, Parameters);
1750 public override Expression Resolve (EmitContext ec)
1755 return new AnonymousDelegate (this, DelegateType, Location).Resolve (ec);
1758 public MethodInfo GetMethodBuilder (EmitContext ec)
1760 MethodInfo builder = method.MethodBuilder;
1761 if ((Scope != null) && Scope.IsGeneric) {
1762 Type scope_type = Scope.GetScopeType (ec);
1763 if (scope_type == null)
1764 throw new InternalErrorException ();
1766 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1767 ec.ContainerType, scope_type, builder.Name,
1768 MemberTypes.Method, Expression.AllBindingFlags | BindingFlags.NonPublic, Location);
1771 throw new InternalErrorException ();
1772 builder = (MethodInfo) mg.Methods [0];
1776 if (!DelegateType.IsGenericType)
1779 Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1780 return builder.MakeGenericMethod (targs);
1786 public static void Error_AddressOfCapturedVar (string name, Location loc)
1788 Report.Error (1686, loc,
1789 "Local variable `{0}' or its members cannot have their " +
1790 "address taken and be used inside an anonymous method block",
1796 // This will emit the code for the delegate, as well delegate creation on the host
1798 public class AnonymousDelegate : DelegateCreation {
1799 readonly AnonymousMethod am;
1802 // if target_type is null, this means that we do not know the type
1803 // for this delegate, and we want to infer it from the various
1804 // returns (implicit and explicit) from the body of this anonymous
1807 // for example, the lambda: x => 1
1809 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1816 public override Expression DoResolve (EmitContext ec)
1818 eclass = ExprClass.Value;
1822 public override void Emit (EmitContext ec)
1824 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE");
1825 //ec.ig.Emit (OpCodes.Pop);
1828 // Now emit the delegate creation.
1830 if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1831 Report.Debug (128, "EMIT ANONYMOUS DELEGATE", this, am, am.Scope, loc);
1832 delegate_instance_expression = am.Scope.GetScopeInitializer (ec);
1834 if (delegate_instance_expression == null)
1835 throw new InternalErrorException ();
1838 constructor_method = Delegate.GetConstructor (ec.ContainerType, type);
1840 if (type.IsGenericType && type is TypeBuilder)
1841 constructor_method = TypeBuilder.GetConstructor (type, (ConstructorInfo)constructor_method);
1844 delegate_method = am.GetMethodBuilder (ec);
1847 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE DONE");
1848 //ec.ig.Emit (OpCodes.Pop);
1850 Report.Debug (128, "EMIT ANONYMOUS DELEGATE DONE", this, am, am.Scope, loc);
1855 // Anonymous type container
1857 public class AnonymousTypeClass : CompilerGeneratedClass
1859 static int types_counter;
1860 public const string ClassNamePrefix = "<>__AnonType";
1861 public const string SignatureForError = "anonymous type";
1863 static readonly IntConstant FNV_prime = new IntConstant (16777619, Location.Null);
1865 readonly ArrayList parameters;
1867 private AnonymousTypeClass (DeclSpace parent, MemberName name, ArrayList parameters, Location loc)
1868 : base (parent, name, Modifiers.SEALED, loc)
1870 this.parameters = parameters;
1873 public static AnonymousTypeClass Create (TypeContainer parent, ArrayList parameters, Location loc)
1875 string name = ClassNamePrefix + types_counter++;
1877 SimpleName [] t_args = new SimpleName [parameters.Count];
1878 Parameter [] ctor_params = new Parameter [parameters.Count];
1879 for (int i = 0; i < parameters.Count; ++i) {
1880 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1882 t_args [i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
1883 ctor_params [i] = new Parameter (t_args [i], p.Name, 0, null, p.Location);
1887 // Create generic anonymous type host with generic arguments
1888 // named upon properties names
1890 AnonymousTypeClass a_type = new AnonymousTypeClass (parent.NamespaceEntry.SlaveDeclSpace,
1891 new MemberName (name, new TypeArguments (loc, t_args), loc), parameters, loc);
1893 if (parameters.Count > 0)
1894 a_type.SetParameterInfo (null);
1896 Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC,
1897 new Parameters (ctor_params), null, loc);
1898 c.OptAttributes = a_type.GetDebuggerHiddenAttribute ();
1899 c.Block = new ToplevelBlock (c.Parameters, loc);
1902 // Create fields and contructor body with field initialization
1905 for (int i = 0; i < parameters.Count; ++i) {
1906 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1908 Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY,
1909 "<" + p.Name + ">", null, p.Location);
1911 if (!a_type.AddField (f)) {
1913 Report.Error (833, p.Location, "`{0}': An anonymous type cannot have multiple properties with the same name",
1918 c.Block.AddStatement (new StatementExpression (
1919 new Assign (new MemberAccess (new This (p.Location), f.Name),
1920 c.Block.GetParameterReference (p.Name, p.Location))));
1922 ToplevelBlock get_block = new ToplevelBlock (p.Location);
1923 get_block.AddStatement (new Return (
1924 new MemberAccess (new This (p.Location), f.Name), p.Location));
1925 Accessor get_accessor = new Accessor (get_block, 0, null, p.Location);
1926 Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC, false,
1927 new MemberName (p.Name, p.Location), null, get_accessor, null, false);
1928 a_type.AddProperty (prop);
1934 a_type.AddConstructor (c);
1938 protected override bool AddToContainer (MemberCore symbol, string name)
1940 MemberCore mc = (MemberCore) defined_names [name];
1943 defined_names.Add (name, symbol);
1947 Report.SymbolRelatedToPreviousError (mc);
1951 void DefineOverrides ()
1953 Location loc = Location;
1955 Method equals = new Method (this, null, TypeManager.system_boolean_expr,
1956 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("Equals", loc),
1957 new Parameters (new Parameter (TypeManager.system_object_expr, "obj", 0, null, loc)),
1958 GetDebuggerHiddenAttribute ());
1960 Method tostring = new Method (this, null, TypeManager.system_string_expr,
1961 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("ToString", loc),
1962 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
1964 ToplevelBlock equals_block = new ToplevelBlock (equals.Parameters, loc);
1965 TypeExpr current_type;
1967 current_type = new ConstructedType (TypeBuilder, TypeParameters, loc);
1969 current_type = new TypeExpression (TypeBuilder, loc);
1971 equals_block.AddVariable (current_type, "other", loc);
1972 LocalVariableReference other_variable = new LocalVariableReference (equals_block, "other", loc);
1974 MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
1975 new SimpleName ("System", loc), "Collections", loc), "Generic", loc);
1977 Expression rs_equals = null;
1978 Expression string_concat = new StringConstant ("<empty type>", loc);
1979 Expression rs_hashcode = new IntConstant (-2128831035, loc);
1980 for (int i = 0; i < parameters.Count; ++i) {
1981 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1982 Field f = (Field) Fields [i];
1984 MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
1985 system_collections_generic, "EqualityComparer",
1986 new TypeArguments (loc, new SimpleName (TypeParameters [i].Name, loc)), loc),
1989 ArrayList arguments_equal = new ArrayList (2);
1990 arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
1991 arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name)));
1993 Expression field_equal = new Invocation (new MemberAccess (equality_comparer,
1994 "Equals", loc), arguments_equal);
1996 ArrayList arguments_hashcode = new ArrayList (1);
1997 arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
1998 Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer,
1999 "GetHashCode", loc), arguments_hashcode);
2001 rs_hashcode = new Binary (Binary.Operator.Multiply,
2002 new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode),
2005 Expression field_to_string = new Conditional (new Binary (Binary.Operator.Inequality,
2006 new MemberAccess (new This (f.Location), f.Name), new NullConstant (loc)),
2007 new Invocation (new MemberAccess (
2008 new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
2009 new StringConstant ("<null>", loc));
2011 if (rs_equals == null) {
2012 rs_equals = field_equal;
2013 string_concat = new Binary (Binary.Operator.Addition,
2014 new StringConstant (p.Name + " = ", loc),
2020 // Implementation of ToString () body using string concatenation
2022 string_concat = new Binary (Binary.Operator.Addition,
2023 new Binary (Binary.Operator.Addition,
2025 new StringConstant (", " + p.Name + " = ", loc)),
2028 rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal);
2032 // Equals (object obj) override
2034 equals_block.AddStatement (new StatementExpression (
2035 new Assign (other_variable,
2036 new As (equals_block.GetParameterReference ("obj", loc),
2037 current_type, loc), loc)));
2039 Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc));
2040 if (rs_equals != null)
2041 equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals);
2042 equals_block.AddStatement (new Return (equals_test, loc));
2044 equals.Block = equals_block;
2045 equals.ResolveMembers ();
2049 // GetHashCode () override
2051 Method hashcode = new Method (this, null, TypeManager.system_int32_expr,
2052 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("GetHashCode", loc),
2053 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
2056 // Modified FNV with good avalanche behavior and uniform
2057 // distribution with larger hash sizes.
2059 // const int FNV_prime = 16777619;
2060 // int hash = (int) 2166136261;
2061 // foreach (int d in data)
2062 // hash = (hash ^ d) * FNV_prime;
2063 // hash += hash << 13;
2064 // hash ^= hash >> 7;
2065 // hash += hash << 3;
2066 // hash ^= hash >> 17;
2067 // hash += hash << 5;
2069 ToplevelBlock hashcode_block = new ToplevelBlock (loc);
2070 hashcode_block.AddVariable (TypeManager.system_int32_expr, "hash", loc);
2071 LocalVariableReference hash_variable = new LocalVariableReference (hashcode_block, "hash", loc);
2072 hashcode_block.AddStatement (new StatementExpression (
2073 new Assign (hash_variable, rs_hashcode)));
2075 hashcode_block.AddStatement (new StatementExpression (
2076 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2077 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (13, loc)))));
2078 hashcode_block.AddStatement (new StatementExpression (
2079 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2080 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (7, loc)))));
2081 hashcode_block.AddStatement (new StatementExpression (
2082 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2083 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (3, loc)))));
2084 hashcode_block.AddStatement (new StatementExpression (
2085 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2086 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (17, loc)))));
2087 hashcode_block.AddStatement (new StatementExpression (
2088 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2089 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (5, loc)))));
2091 hashcode_block.AddStatement (new Return (hash_variable, loc));
2092 hashcode.Block = hashcode_block;
2093 hashcode.ResolveMembers ();
2094 AddMethod (hashcode);
2097 // ToString () override
2100 ToplevelBlock tostring_block = new ToplevelBlock (loc);
2101 tostring_block.AddStatement (new Return (string_concat, loc));
2102 tostring.Block = tostring_block;
2103 tostring.ResolveMembers ();
2104 AddMethod (tostring);
2107 public override bool DefineMembers ()
2111 return base.DefineMembers ();
2114 Attributes GetDebuggerHiddenAttribute ()
2116 return new Attributes (new Attribute (null, null,
2117 "System.Diagnostics.DebuggerHiddenAttribute", null, Location, false));
2120 public override string GetSignatureForError ()
2122 return SignatureForError;
2125 public ArrayList Parameters {