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 protected bool VerifyParameterCompatibility (Type delegate_type, ParameterData invoke_pd, bool ignoreErrors)
1201 if (Parameters.Count != invoke_pd.Count) {
1205 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1206 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1210 if (!HasExplicitParameters)
1214 for (int i = 0; i < Parameters.Count; ++i) {
1215 Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1216 if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1220 if (p_mod == Parameter.Modifier.NONE)
1221 Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1222 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1224 Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1225 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1230 Type type = invoke_pd.Types [i];
1232 // We assume that generic parameters are always inflated
1233 if (TypeManager.IsGenericParameter (type))
1236 if (TypeManager.HasElementType (type) && TypeManager.IsGenericParameter (TypeManager.GetElementType (type)))
1239 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1243 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1245 TypeManager.CSharpName (Parameters.ParameterType (i)),
1246 TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1255 // Infers type arguments based on explicit arguments
1257 public bool ExplicitTypeInference (TypeInferenceContext typeInference, Type delegateType)
1259 if (!HasExplicitParameters)
1262 if (!TypeManager.IsDelegateType (delegateType))
1265 ParameterData d_params = TypeManager.GetDelegateParameters (delegateType);
1266 if (d_params.Count != Parameters.Count)
1269 for (int i = 0; i < Parameters.Count; ++i) {
1270 Type itype = d_params.Types [i];
1271 if (!TypeManager.IsGenericParameter (itype)) {
1272 if (!itype.HasElementType)
1275 if (!TypeManager.IsGenericParameter (itype.GetElementType ()))
1278 typeInference.ExactInference (Parameters.FixedParameters[i].ParameterType, itype);
1283 public Type InferReturnType (EmitContext ec, TypeInferenceContext tic, Type delegateType)
1286 using (ec.Set (EmitContext.Flags.ProbingMode | EmitContext.Flags.InferReturnType)) {
1287 am = CompatibleMethod (ec, tic, GetType (), delegateType);
1293 if (am.ReturnType == TypeManager.null_type)
1294 am.ReturnType = null;
1296 return am.ReturnType;
1300 // Returns AnonymousMethod container if this anonymous method
1301 // expression can be implicitly converted to the delegate type `delegate_type'
1303 public AnonymousMethod Compatible (EmitContext ec, Type delegateType)
1305 if (CompatibleChecks (ec, delegateType) == null)
1309 // At this point its the first time we know the return type that is
1310 // needed for the anonymous method. We create the method here.
1313 MethodInfo invoke_mb = Delegate.GetInvokeMethod (
1314 ec.ContainerType, delegateType);
1315 Type return_type = invoke_mb.ReturnType;
1318 Type[] g_args = delegateType.GetGenericArguments ();
1319 if (return_type.IsGenericParameter)
1320 return_type = g_args [return_type.GenericParameterPosition];
1324 // Second: the return type of the delegate must be compatible with
1325 // the anonymous type. Instead of doing a pass to examine the block
1326 // we satisfy the rule by setting the return type on the EmitContext
1327 // to be the delegate type return type.
1330 Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1331 Container, Block, return_type, delegateType,
1332 TypeManager.IsGenericType (delegateType), loc);
1335 return CompatibleMethod (ec, null, return_type, delegateType);
1336 } catch (Exception e) {
1337 throw new InternalErrorException (e, loc);
1341 protected virtual Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegateType)
1343 ParameterData delegateParameters = TypeManager.GetDelegateParameters (delegateType);
1345 if (Parameters == null) {
1347 // We provide a set of inaccessible parameters
1349 Parameter[] fixedpars = new Parameter[delegateParameters.Count];
1351 for (int i = 0; i < delegateParameters.Count; i++) {
1352 Parameter.Modifier i_mod = delegateParameters.ParameterModifier (i);
1353 if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1354 Report.Error (1688, loc, "Cannot convert anonymous " +
1355 "method block without a parameter list " +
1356 "to delegate type `{0}' because it has " +
1357 "one or more `out' parameters.",
1358 TypeManager.CSharpName (delegateType));
1361 fixedpars[i] = new Parameter (
1362 delegateParameters.ParameterType (i), "+" + (++next_index),
1363 delegateParameters.ParameterModifier (i), null, loc);
1366 return Parameters.CreateFullyResolved (fixedpars, delegateParameters.Types);
1369 if (!VerifyExplicitParameters (delegateType, delegateParameters, ec.IsInProbingMode)) {
1376 public override Expression DoResolve (EmitContext ec)
1379 // Set class type, set type
1382 eclass = ExprClass.Value;
1385 // This hack means `The type is not accessible
1386 // anywhere', we depend on special conversion
1389 type = TypeManager.anonymous_method_type;
1391 if ((Parameters != null) && !Parameters.Resolve (ec))
1397 public override void Emit (EmitContext ec)
1399 // nothing, as we only exist to not do anything.
1402 public override string GetSignatureForError ()
1404 return ExprClassName;
1407 public bool IsIterator {
1408 get { return false; }
1411 protected AnonymousMethod CompatibleMethod (EmitContext ec, TypeInferenceContext tic, Type returnType, Type delegateType)
1413 Parameters p = ResolveParameters (ec, tic, delegateType);
1417 ToplevelBlock b = ec.IsInProbingMode ? (ToplevelBlock) Block.PerformClone () : Block;
1419 AnonymousMethod anonymous = CompatibleMethodFactory (returnType, delegateType, p, b);
1420 if (!anonymous.Compatible (ec))
1426 protected virtual AnonymousMethod CompatibleMethodFactory (Type returnType, Type delegateType, Parameters p, ToplevelBlock b)
1428 return new AnonymousMethod (RootScope, Host,
1429 GenericMethod, p, Container, b, returnType,
1433 protected override void CloneTo (CloneContext clonectx, Expression t)
1435 AnonymousMethodExpression target = (AnonymousMethodExpression) t;
1437 target.Block = (ToplevelBlock) clonectx.LookupBlock (Block);
1438 target.container = clonectx.LookupBlock (Block);
1442 public abstract class AnonymousContainer : IAnonymousContainer
1444 public readonly Location Location;
1446 public Parameters Parameters;
1449 // The block that makes up the body for the anonymous mehtod
1451 public readonly ToplevelBlock Block;
1453 public readonly int ModFlags;
1454 public Type ReturnType;
1455 public readonly DeclSpace Host;
1458 // The implicit method we create
1460 protected Method method;
1461 protected EmitContext aec;
1463 // The emit context for the anonymous method
1464 protected bool unreachable;
1465 protected readonly Block container;
1466 protected readonly GenericMethod generic;
1468 protected AnonymousContainer (DeclSpace host,
1469 GenericMethod generic, Parameters parameters,
1470 Block container, ToplevelBlock block,
1471 Type return_type, int mod, Location loc)
1473 this.ReturnType = return_type;
1474 this.ModFlags = mod | Modifiers.COMPILER_GENERATED;
1477 this.container = container;
1478 this.generic = generic;
1479 this.Parameters = parameters;
1481 this.Location = loc;
1483 block.AnonymousContainer = this;
1486 public Method Method {
1487 get { return method; }
1490 public abstract string ContainerType {
1494 public abstract RootScopeInfo RootScope {
1498 public abstract ScopeInfo Scope {
1502 public abstract string GetSignatureForError ();
1504 public bool Compatible (EmitContext ec)
1506 // REFACTOR: The method should be refactor, many of the
1507 // hacks can be handled in better way
1509 Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1510 RootScope, Parameters, ec.IsStatic);
1512 if (ReturnType != null) {
1513 TypeExpr return_type_expr;
1514 if (RootScope != null)
1515 return_type_expr = RootScope.InflateType (ReturnType);
1517 return_type_expr = new TypeExpression (ReturnType, Location);
1518 return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
1519 if ((return_type_expr == null) || (return_type_expr.Type == null))
1521 ReturnType = return_type_expr.Type;
1524 // Linq type inference is done differently
1525 if (RootScope != null && RootContext.Version != LanguageVersion.LINQ)
1526 Parameters = RootScope.InflateParameters (Parameters);
1528 aec = new EmitContext (
1529 ec.ResolveContext, ec.TypeContainer,
1530 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1531 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1532 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1534 aec.CurrentAnonymousMethod = this;
1535 aec.IsStatic = ec.IsStatic;
1538 // HACK: Overwrite parent declaration container to currently resolved.
1539 // It's required for an anonymous container inside partial class.
1541 if (RootScope != null)
1542 aec.DeclContainer.Parent = ec.TypeContainer;
1544 IDisposable aec_dispose = null;
1545 EmitContext.Flags flags = 0;
1546 if (ec.InferReturnType)
1547 flags |= EmitContext.Flags.InferReturnType;
1549 if (ec.IsInProbingMode)
1550 flags |= EmitContext.Flags.ProbingMode;
1552 if (ec.IsInFieldInitializer)
1553 flags |= EmitContext.Flags.InFieldInitializer;
1555 // HACK: Flag with 0 cannot be set
1557 aec_dispose = aec.Set (flags);
1559 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1560 RootScope, Parameters, Block);
1563 bool res = aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable);
1565 if (ec.InferReturnType)
1566 ReturnType = aec.ReturnType;
1568 if (aec_dispose != null) {
1569 aec_dispose.Dispose ();
1575 public abstract Expression Resolve (EmitContext ec);
1577 public virtual bool Define (EmitContext ec)
1579 Report.Debug (64, "DEFINE ANONYMOUS METHOD #3", this, ec, aec, Block);
1581 if (aec == null && !Compatible (ec))
1584 // Don't define anything when we are in probing scope (nested anonymous methods)
1585 if (ec.IsInProbingMode)
1588 method = DoCreateMethodHost (ec);
1593 if (!method.ResolveMembers ())
1595 return method.Define ();
1598 protected abstract Method DoCreateMethodHost (EmitContext ec);
1600 public Block Container {
1601 get { return container; }
1604 public GenericMethod GenericMethod {
1605 get { return generic; }
1608 public abstract bool IsIterator {
1612 protected class AnonymousMethodMethod : Method
1614 public readonly AnonymousContainer AnonymousMethod;
1615 public readonly ScopeInfo Scope;
1617 public AnonymousMethodMethod (AnonymousContainer am, ScopeInfo scope,
1618 GenericMethod generic, TypeExpr return_type,
1619 int mod, MemberName name, Parameters parameters)
1620 : base (scope != null ? scope : am.Host,
1621 generic, return_type, mod | Modifiers.COMPILER_GENERATED, false, name, parameters, null)
1623 this.AnonymousMethod = am;
1626 if (scope != null) {
1627 scope.CheckMembersDefined ();
1628 scope.AddMethod (this);
1630 ModFlags |= Modifiers.STATIC;
1631 am.Host.PartialContainer.AddMethod (this);
1636 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1638 EmitContext aec = AnonymousMethod.aec;
1640 aec.MethodIsStatic = Scope == null;
1646 public class AnonymousMethod : AnonymousContainer
1651 // The value return by the Compatible call, this ensure that
1652 // the code works even if invoked more than once (Resolve called
1653 // more than once, due to the way Convert.ImplicitConversion works
1655 RootScopeInfo root_scope;
1658 public AnonymousMethod (RootScopeInfo root_scope,
1659 DeclSpace host, GenericMethod generic,
1660 Parameters parameters, Block container,
1661 ToplevelBlock block, Type return_type, Type delegate_type,
1663 : base (host, generic, parameters, container, block,
1664 return_type, 0, loc)
1666 this.DelegateType = delegate_type;
1667 this.root_scope = root_scope;
1670 public override string ContainerType {
1671 get { return "anonymous method"; }
1674 public override RootScopeInfo RootScope {
1675 get { return root_scope; }
1678 public override ScopeInfo Scope {
1679 get { return scope; }
1682 public override bool IsIterator {
1683 get { return false; }
1686 public override string GetSignatureForError ()
1688 return TypeManager.CSharpName (DelegateType);
1692 // Creates the host for the anonymous method
1694 protected override Method DoCreateMethodHost (EmitContext ec)
1696 MemberCore mc = ec.ResolveContext as MemberCore;
1697 string name = CompilerGeneratedClass.MakeName (mc.Name, null);
1698 MemberName member_name;
1700 Report.Debug (128, "CREATE METHOD HOST #0", RootScope);
1705 Report.Debug (128, "CREATE METHOD HOST #1", this, Block, Block.ScopeInfo,
1706 RootScope, Location);
1708 for (b = Block.Parent; b != null; b = b.Parent) {
1709 Report.Debug (128, "CREATE METHOD HOST #2", this, Block,
1711 if (b.ScopeInfo != null) {
1712 scope = b.ScopeInfo;
1718 scope.CheckMembersDefined ();
1720 ArrayList scopes = new ArrayList ();
1722 for (b = b.Parent; b != null; b = b.Parent) {
1723 if (b.ScopeInfo != null)
1724 scopes.Add (b.ScopeInfo);
1728 Report.Debug (128, "CREATE METHOD HOST #1", this, scope, scopes);
1730 foreach (ScopeInfo si in scopes)
1731 scope.CaptureScope (si);
1733 Report.Debug (128, "CREATE METHOD HOST", this, Block, container,
1734 RootScope, scope, scopes, Location);
1736 GenericMethod generic_method = null;
1738 if (TypeManager.IsGenericType (DelegateType)) {
1739 TypeArguments args = new TypeArguments (Location);
1741 Type dt = DelegateType.GetGenericTypeDefinition ();
1743 Type[] tparam = TypeManager.GetTypeArguments (dt);
1744 for (int i = 0; i < tparam.Length; i++)
1745 args.Add (new SimpleName (tparam [i].Name, Location));
1747 member_name = new MemberName (name, args, Location);
1749 Report.Debug (128, "CREATE METHOD HOST #5", this, DelegateType,
1750 TypeManager.GetTypeArguments (DelegateType),
1753 generic_method = new GenericMethod (
1754 Host.NamespaceEntry, scope, member_name,
1755 new TypeExpression (ReturnType, Location), Parameters);
1757 generic_method.SetParameterInfo (null);
1760 member_name = new MemberName (name, Location);
1762 return new AnonymousMethodMethod (
1763 this, scope, generic_method, new TypeExpression (ReturnType, Location),
1764 scope == null ? Modifiers.PRIVATE : Modifiers.INTERNAL, member_name, Parameters);
1767 public override Expression Resolve (EmitContext ec)
1772 return new AnonymousDelegate (this, DelegateType, Location).Resolve (ec);
1775 public MethodInfo GetMethodBuilder (EmitContext ec)
1777 MethodInfo builder = method.MethodBuilder;
1778 if ((Scope != null) && Scope.IsGeneric) {
1779 Type scope_type = Scope.GetScopeType (ec);
1780 if (scope_type == null)
1781 throw new InternalErrorException ();
1783 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1784 ec.ContainerType, scope_type, builder.Name,
1785 MemberTypes.Method, Expression.AllBindingFlags | BindingFlags.NonPublic, Location);
1788 throw new InternalErrorException ();
1789 builder = (MethodInfo) mg.Methods [0];
1793 if (!DelegateType.IsGenericType)
1796 Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1797 return builder.MakeGenericMethod (targs);
1803 public static void Error_AddressOfCapturedVar (string name, Location loc)
1805 Report.Error (1686, loc,
1806 "Local variable `{0}' or its members cannot have their " +
1807 "address taken and be used inside an anonymous method block",
1813 // This will emit the code for the delegate, as well delegate creation on the host
1815 public class AnonymousDelegate : DelegateCreation {
1816 readonly AnonymousMethod am;
1819 // if target_type is null, this means that we do not know the type
1820 // for this delegate, and we want to infer it from the various
1821 // returns (implicit and explicit) from the body of this anonymous
1824 // for example, the lambda: x => 1
1826 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1833 public override Expression DoResolve (EmitContext ec)
1835 eclass = ExprClass.Value;
1839 public override void Emit (EmitContext ec)
1841 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE");
1842 //ec.ig.Emit (OpCodes.Pop);
1845 // Now emit the delegate creation.
1847 if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1848 Report.Debug (128, "EMIT ANONYMOUS DELEGATE", this, am, am.Scope, loc);
1849 delegate_instance_expression = am.Scope.GetScopeInitializer (ec);
1851 if (delegate_instance_expression == null)
1852 throw new InternalErrorException ();
1855 constructor_method = Delegate.GetConstructor (ec.ContainerType, type);
1857 if (type.IsGenericType && type is TypeBuilder)
1858 constructor_method = TypeBuilder.GetConstructor (type, (ConstructorInfo)constructor_method);
1861 delegate_method = am.GetMethodBuilder (ec);
1864 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE DONE");
1865 //ec.ig.Emit (OpCodes.Pop);
1867 Report.Debug (128, "EMIT ANONYMOUS DELEGATE DONE", this, am, am.Scope, loc);
1872 // Anonymous type container
1874 public class AnonymousTypeClass : CompilerGeneratedClass
1876 static int types_counter;
1877 public const string ClassNamePrefix = "<>__AnonType";
1878 public const string SignatureForError = "anonymous type";
1880 static readonly IntConstant FNV_prime = new IntConstant (16777619, Location.Null);
1882 readonly ArrayList parameters;
1884 private AnonymousTypeClass (DeclSpace parent, MemberName name, ArrayList parameters, Location loc)
1885 : base (parent, name, Modifiers.SEALED, loc)
1887 this.parameters = parameters;
1890 public static AnonymousTypeClass Create (TypeContainer parent, ArrayList parameters, Location loc)
1892 if (RootContext.Version <= LanguageVersion.ISO_2)
1893 Report.FeatureIsNotISO1 (loc, "anonymous types");
1895 string name = ClassNamePrefix + types_counter++;
1897 SimpleName [] t_args = new SimpleName [parameters.Count];
1898 Parameter [] ctor_params = new Parameter [parameters.Count];
1899 for (int i = 0; i < parameters.Count; ++i) {
1900 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1902 t_args [i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
1903 ctor_params [i] = new Parameter (t_args [i], p.Name, 0, null, p.Location);
1907 // Create generic anonymous type host with generic arguments
1908 // named upon properties names
1910 AnonymousTypeClass a_type = new AnonymousTypeClass (parent.NamespaceEntry.SlaveDeclSpace,
1911 new MemberName (name, new TypeArguments (loc, t_args), loc), parameters, loc);
1913 if (parameters.Count > 0)
1914 a_type.SetParameterInfo (null);
1916 Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC,
1917 new Parameters (ctor_params), null, loc);
1918 c.OptAttributes = a_type.GetDebuggerHiddenAttribute ();
1919 c.Block = new ToplevelBlock (c.Parameters, loc);
1922 // Create fields and contructor body with field initialization
1925 for (int i = 0; i < parameters.Count; ++i) {
1926 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1928 Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY,
1929 "<" + p.Name + ">", null, p.Location);
1931 if (!a_type.AddField (f)) {
1933 Report.Error (833, p.Location, "`{0}': An anonymous type cannot have multiple properties with the same name",
1938 c.Block.AddStatement (new StatementExpression (
1939 new Assign (new MemberAccess (new This (p.Location), f.Name),
1940 c.Block.GetParameterReference (p.Name, p.Location))));
1942 ToplevelBlock get_block = new ToplevelBlock (p.Location);
1943 get_block.AddStatement (new Return (
1944 new MemberAccess (new This (p.Location), f.Name), p.Location));
1945 Accessor get_accessor = new Accessor (get_block, 0, null, p.Location);
1946 Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC, false,
1947 new MemberName (p.Name, p.Location), null, get_accessor, null, false);
1948 a_type.AddProperty (prop);
1954 a_type.AddConstructor (c);
1958 protected override bool AddToContainer (MemberCore symbol, string name)
1960 MemberCore mc = (MemberCore) defined_names [name];
1963 defined_names.Add (name, symbol);
1967 Report.SymbolRelatedToPreviousError (mc);
1971 void DefineOverrides ()
1973 Location loc = Location;
1975 Method equals = new Method (this, null, TypeManager.system_boolean_expr,
1976 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("Equals", loc),
1977 new Parameters (new Parameter (TypeManager.system_object_expr, "obj", 0, null, loc)),
1978 GetDebuggerHiddenAttribute ());
1980 Method tostring = new Method (this, null, TypeManager.system_string_expr,
1981 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("ToString", loc),
1982 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
1984 ToplevelBlock equals_block = new ToplevelBlock (equals.Parameters, loc);
1985 TypeExpr current_type;
1987 current_type = new ConstructedType (TypeBuilder, TypeParameters, loc);
1989 current_type = new TypeExpression (TypeBuilder, loc);
1991 equals_block.AddVariable (current_type, "other", loc);
1992 LocalVariableReference other_variable = new LocalVariableReference (equals_block, "other", loc);
1994 MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
1995 new SimpleName ("System", loc), "Collections", loc), "Generic", loc);
1997 Expression rs_equals = null;
1998 Expression string_concat = new StringConstant ("<empty type>", loc);
1999 Expression rs_hashcode = new IntConstant (-2128831035, loc);
2000 for (int i = 0; i < parameters.Count; ++i) {
2001 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
2002 Field f = (Field) Fields [i];
2004 MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
2005 system_collections_generic, "EqualityComparer",
2006 new TypeArguments (loc, new SimpleName (TypeParameters [i].Name, loc)), loc),
2009 ArrayList arguments_equal = new ArrayList (2);
2010 arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2011 arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name)));
2013 Expression field_equal = new Invocation (new MemberAccess (equality_comparer,
2014 "Equals", loc), arguments_equal);
2016 ArrayList arguments_hashcode = new ArrayList (1);
2017 arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2018 Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer,
2019 "GetHashCode", loc), arguments_hashcode);
2021 rs_hashcode = new Binary (Binary.Operator.Multiply,
2022 new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode),
2025 Expression field_to_string = new Conditional (new Binary (Binary.Operator.Inequality,
2026 new MemberAccess (new This (f.Location), f.Name), new NullConstant (loc)),
2027 new Invocation (new MemberAccess (
2028 new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
2029 new StringConstant ("<null>", loc));
2031 if (rs_equals == null) {
2032 rs_equals = field_equal;
2033 string_concat = new Binary (Binary.Operator.Addition,
2034 new StringConstant (p.Name + " = ", loc),
2040 // Implementation of ToString () body using string concatenation
2042 string_concat = new Binary (Binary.Operator.Addition,
2043 new Binary (Binary.Operator.Addition,
2045 new StringConstant (", " + p.Name + " = ", loc)),
2048 rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal);
2052 // Equals (object obj) override
2054 equals_block.AddStatement (new StatementExpression (
2055 new Assign (other_variable,
2056 new As (equals_block.GetParameterReference ("obj", loc),
2057 current_type, loc), loc)));
2059 Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc));
2060 if (rs_equals != null)
2061 equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals);
2062 equals_block.AddStatement (new Return (equals_test, loc));
2064 equals.Block = equals_block;
2065 equals.ResolveMembers ();
2069 // GetHashCode () override
2071 Method hashcode = new Method (this, null, TypeManager.system_int32_expr,
2072 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("GetHashCode", loc),
2073 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
2076 // Modified FNV with good avalanche behavior and uniform
2077 // distribution with larger hash sizes.
2079 // const int FNV_prime = 16777619;
2080 // int hash = (int) 2166136261;
2081 // foreach (int d in data)
2082 // hash = (hash ^ d) * FNV_prime;
2083 // hash += hash << 13;
2084 // hash ^= hash >> 7;
2085 // hash += hash << 3;
2086 // hash ^= hash >> 17;
2087 // hash += hash << 5;
2089 ToplevelBlock hashcode_block = new ToplevelBlock (loc);
2090 hashcode_block.AddVariable (TypeManager.system_int32_expr, "hash", loc);
2091 LocalVariableReference hash_variable = new LocalVariableReference (hashcode_block, "hash", loc);
2092 hashcode_block.AddStatement (new StatementExpression (
2093 new Assign (hash_variable, rs_hashcode)));
2095 hashcode_block.AddStatement (new StatementExpression (
2096 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2097 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (13, loc)))));
2098 hashcode_block.AddStatement (new StatementExpression (
2099 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2100 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (7, loc)))));
2101 hashcode_block.AddStatement (new StatementExpression (
2102 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2103 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (3, loc)))));
2104 hashcode_block.AddStatement (new StatementExpression (
2105 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2106 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (17, loc)))));
2107 hashcode_block.AddStatement (new StatementExpression (
2108 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2109 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (5, loc)))));
2111 hashcode_block.AddStatement (new Return (hash_variable, loc));
2112 hashcode.Block = hashcode_block;
2113 hashcode.ResolveMembers ();
2114 AddMethod (hashcode);
2117 // ToString () override
2120 ToplevelBlock tostring_block = new ToplevelBlock (loc);
2121 tostring_block.AddStatement (new Return (string_concat, loc));
2122 tostring.Block = tostring_block;
2123 tostring.ResolveMembers ();
2124 AddMethod (tostring);
2127 public override bool DefineMembers ()
2131 return base.DefineMembers ();
2134 Attributes GetDebuggerHiddenAttribute ()
2136 return new Attributes (new Attribute (null, null,
2137 "System.Diagnostics.DebuggerHiddenAttribute", null, Location, false));
2140 public override string GetSignatureForError ()
2142 return SignatureForError;
2145 public ArrayList Parameters {