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 if (ec.InferReturnType)
1546 aec_dispose = aec.Set (EmitContext.Flags.InferReturnType);
1547 if (ec.IsInProbingMode)
1548 aec_dispose = aec.Set (EmitContext.Flags.ProbingMode);
1549 if (ec.IsInFieldInitializer)
1550 aec_dispose = aec.Set (EmitContext.Flags.InFieldInitializer);
1552 Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1553 RootScope, Parameters, Block);
1556 bool res = aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable);
1558 if (ec.InferReturnType)
1559 ReturnType = aec.ReturnType;
1561 if (aec_dispose != null) {
1562 aec_dispose.Dispose ();
1568 public abstract Expression Resolve (EmitContext ec);
1570 public virtual bool Define (EmitContext ec)
1572 Report.Debug (64, "DEFINE ANONYMOUS METHOD #3", this, ec, aec, Block);
1574 if (aec == null && !Compatible (ec))
1577 // Don't define anything when we are in probing scope (nested anonymous methods)
1578 if (ec.IsInProbingMode)
1581 method = DoCreateMethodHost (ec);
1586 if (!method.ResolveMembers ())
1588 return method.Define ();
1591 protected abstract Method DoCreateMethodHost (EmitContext ec);
1593 public Block Container {
1594 get { return container; }
1597 public GenericMethod GenericMethod {
1598 get { return generic; }
1601 public abstract bool IsIterator {
1605 protected class AnonymousMethodMethod : Method
1607 public readonly AnonymousContainer AnonymousMethod;
1608 public readonly ScopeInfo Scope;
1610 public AnonymousMethodMethod (AnonymousContainer am, ScopeInfo scope,
1611 GenericMethod generic, TypeExpr return_type,
1612 int mod, MemberName name, Parameters parameters)
1613 : base (scope != null ? scope : am.Host,
1614 generic, return_type, mod | Modifiers.COMPILER_GENERATED, false, name, parameters, null)
1616 this.AnonymousMethod = am;
1619 if (scope != null) {
1620 scope.CheckMembersDefined ();
1621 scope.AddMethod (this);
1623 ModFlags |= Modifiers.STATIC;
1624 am.Host.PartialContainer.AddMethod (this);
1629 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1631 EmitContext aec = AnonymousMethod.aec;
1633 aec.MethodIsStatic = Scope == null;
1639 public class AnonymousMethod : AnonymousContainer
1644 // The value return by the Compatible call, this ensure that
1645 // the code works even if invoked more than once (Resolve called
1646 // more than once, due to the way Convert.ImplicitConversion works
1648 RootScopeInfo root_scope;
1651 public AnonymousMethod (RootScopeInfo root_scope,
1652 DeclSpace host, GenericMethod generic,
1653 Parameters parameters, Block container,
1654 ToplevelBlock block, Type return_type, Type delegate_type,
1656 : base (host, generic, parameters, container, block,
1657 return_type, 0, loc)
1659 this.DelegateType = delegate_type;
1660 this.root_scope = root_scope;
1663 public override string ContainerType {
1664 get { return "anonymous method"; }
1667 public override RootScopeInfo RootScope {
1668 get { return root_scope; }
1671 public override ScopeInfo Scope {
1672 get { return scope; }
1675 public override bool IsIterator {
1676 get { return false; }
1679 public override string GetSignatureForError ()
1681 return TypeManager.CSharpName (DelegateType);
1685 // Creates the host for the anonymous method
1687 protected override Method DoCreateMethodHost (EmitContext ec)
1689 MemberCore mc = ec.ResolveContext as MemberCore;
1690 string name = CompilerGeneratedClass.MakeName (mc.Name, null);
1691 MemberName member_name;
1693 Report.Debug (128, "CREATE METHOD HOST #0", RootScope);
1698 Report.Debug (128, "CREATE METHOD HOST #1", this, Block, Block.ScopeInfo,
1699 RootScope, Location);
1701 for (b = Block.Parent; b != null; b = b.Parent) {
1702 Report.Debug (128, "CREATE METHOD HOST #2", this, Block,
1704 if (b.ScopeInfo != null) {
1705 scope = b.ScopeInfo;
1711 scope.CheckMembersDefined ();
1713 ArrayList scopes = new ArrayList ();
1715 for (b = b.Parent; b != null; b = b.Parent) {
1716 if (b.ScopeInfo != null)
1717 scopes.Add (b.ScopeInfo);
1721 Report.Debug (128, "CREATE METHOD HOST #1", this, scope, scopes);
1723 foreach (ScopeInfo si in scopes)
1724 scope.CaptureScope (si);
1726 Report.Debug (128, "CREATE METHOD HOST", this, Block, container,
1727 RootScope, scope, scopes, Location);
1729 GenericMethod generic_method = null;
1731 if (TypeManager.IsGenericType (DelegateType)) {
1732 TypeArguments args = new TypeArguments (Location);
1734 Type dt = DelegateType.GetGenericTypeDefinition ();
1736 Type[] tparam = TypeManager.GetTypeArguments (dt);
1737 for (int i = 0; i < tparam.Length; i++)
1738 args.Add (new SimpleName (tparam [i].Name, Location));
1740 member_name = new MemberName (name, args, Location);
1742 Report.Debug (128, "CREATE METHOD HOST #5", this, DelegateType,
1743 TypeManager.GetTypeArguments (DelegateType),
1746 generic_method = new GenericMethod (
1747 Host.NamespaceEntry, scope, member_name,
1748 new TypeExpression (ReturnType, Location), Parameters);
1750 generic_method.SetParameterInfo (null);
1753 member_name = new MemberName (name, Location);
1755 return new AnonymousMethodMethod (
1756 this, scope, generic_method, new TypeExpression (ReturnType, Location),
1757 scope == null ? Modifiers.PRIVATE : Modifiers.INTERNAL, member_name, Parameters);
1760 public override Expression Resolve (EmitContext ec)
1765 return new AnonymousDelegate (this, DelegateType, Location).Resolve (ec);
1768 public MethodInfo GetMethodBuilder (EmitContext ec)
1770 MethodInfo builder = method.MethodBuilder;
1771 if ((Scope != null) && Scope.IsGeneric) {
1772 Type scope_type = Scope.GetScopeType (ec);
1773 if (scope_type == null)
1774 throw new InternalErrorException ();
1776 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1777 ec.ContainerType, scope_type, builder.Name,
1778 MemberTypes.Method, Expression.AllBindingFlags | BindingFlags.NonPublic, Location);
1781 throw new InternalErrorException ();
1782 builder = (MethodInfo) mg.Methods [0];
1786 if (!DelegateType.IsGenericType)
1789 Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1790 return builder.MakeGenericMethod (targs);
1796 public static void Error_AddressOfCapturedVar (string name, Location loc)
1798 Report.Error (1686, loc,
1799 "Local variable `{0}' or its members cannot have their " +
1800 "address taken and be used inside an anonymous method block",
1806 // This will emit the code for the delegate, as well delegate creation on the host
1808 public class AnonymousDelegate : DelegateCreation {
1809 readonly AnonymousMethod am;
1812 // if target_type is null, this means that we do not know the type
1813 // for this delegate, and we want to infer it from the various
1814 // returns (implicit and explicit) from the body of this anonymous
1817 // for example, the lambda: x => 1
1819 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1826 public override Expression DoResolve (EmitContext ec)
1828 eclass = ExprClass.Value;
1832 public override void Emit (EmitContext ec)
1834 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE");
1835 //ec.ig.Emit (OpCodes.Pop);
1838 // Now emit the delegate creation.
1840 if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1841 Report.Debug (128, "EMIT ANONYMOUS DELEGATE", this, am, am.Scope, loc);
1842 delegate_instance_expression = am.Scope.GetScopeInitializer (ec);
1844 if (delegate_instance_expression == null)
1845 throw new InternalErrorException ();
1848 constructor_method = Delegate.GetConstructor (ec.ContainerType, type);
1850 if (type.IsGenericType && type is TypeBuilder)
1851 constructor_method = TypeBuilder.GetConstructor (type, (ConstructorInfo)constructor_method);
1854 delegate_method = am.GetMethodBuilder (ec);
1857 //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE DONE");
1858 //ec.ig.Emit (OpCodes.Pop);
1860 Report.Debug (128, "EMIT ANONYMOUS DELEGATE DONE", this, am, am.Scope, loc);
1865 // Anonymous type container
1867 public class AnonymousTypeClass : CompilerGeneratedClass
1869 static int types_counter;
1870 public const string ClassNamePrefix = "<>__AnonType";
1871 public const string SignatureForError = "anonymous type";
1873 static readonly IntConstant FNV_prime = new IntConstant (16777619, Location.Null);
1875 readonly ArrayList parameters;
1877 private AnonymousTypeClass (DeclSpace parent, MemberName name, ArrayList parameters, Location loc)
1878 : base (parent, name, Modifiers.SEALED, loc)
1880 this.parameters = parameters;
1883 public static AnonymousTypeClass Create (TypeContainer parent, ArrayList parameters, Location loc)
1885 if (RootContext.Version <= LanguageVersion.ISO_2)
1886 Report.FeatureIsNotISO1 (loc, "anonymous types");
1888 string name = ClassNamePrefix + types_counter++;
1890 SimpleName [] t_args = new SimpleName [parameters.Count];
1891 Parameter [] ctor_params = new Parameter [parameters.Count];
1892 for (int i = 0; i < parameters.Count; ++i) {
1893 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1895 t_args [i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
1896 ctor_params [i] = new Parameter (t_args [i], p.Name, 0, null, p.Location);
1900 // Create generic anonymous type host with generic arguments
1901 // named upon properties names
1903 AnonymousTypeClass a_type = new AnonymousTypeClass (parent.NamespaceEntry.SlaveDeclSpace,
1904 new MemberName (name, new TypeArguments (loc, t_args), loc), parameters, loc);
1906 if (parameters.Count > 0)
1907 a_type.SetParameterInfo (null);
1909 Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC,
1910 new Parameters (ctor_params), null, loc);
1911 c.OptAttributes = a_type.GetDebuggerHiddenAttribute ();
1912 c.Block = new ToplevelBlock (c.Parameters, loc);
1915 // Create fields and contructor body with field initialization
1918 for (int i = 0; i < parameters.Count; ++i) {
1919 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1921 Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY,
1922 "<" + p.Name + ">", null, p.Location);
1924 if (!a_type.AddField (f)) {
1926 Report.Error (833, p.Location, "`{0}': An anonymous type cannot have multiple properties with the same name",
1931 c.Block.AddStatement (new StatementExpression (
1932 new Assign (new MemberAccess (new This (p.Location), f.Name),
1933 c.Block.GetParameterReference (p.Name, p.Location))));
1935 ToplevelBlock get_block = new ToplevelBlock (p.Location);
1936 get_block.AddStatement (new Return (
1937 new MemberAccess (new This (p.Location), f.Name), p.Location));
1938 Accessor get_accessor = new Accessor (get_block, 0, null, p.Location);
1939 Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC, false,
1940 new MemberName (p.Name, p.Location), null, get_accessor, null, false);
1941 a_type.AddProperty (prop);
1947 a_type.AddConstructor (c);
1951 protected override bool AddToContainer (MemberCore symbol, string name)
1953 MemberCore mc = (MemberCore) defined_names [name];
1956 defined_names.Add (name, symbol);
1960 Report.SymbolRelatedToPreviousError (mc);
1964 void DefineOverrides ()
1966 Location loc = Location;
1968 Method equals = new Method (this, null, TypeManager.system_boolean_expr,
1969 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("Equals", loc),
1970 new Parameters (new Parameter (TypeManager.system_object_expr, "obj", 0, null, loc)),
1971 GetDebuggerHiddenAttribute ());
1973 Method tostring = new Method (this, null, TypeManager.system_string_expr,
1974 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("ToString", loc),
1975 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
1977 ToplevelBlock equals_block = new ToplevelBlock (equals.Parameters, loc);
1978 TypeExpr current_type;
1980 current_type = new ConstructedType (TypeBuilder, TypeParameters, loc);
1982 current_type = new TypeExpression (TypeBuilder, loc);
1984 equals_block.AddVariable (current_type, "other", loc);
1985 LocalVariableReference other_variable = new LocalVariableReference (equals_block, "other", loc);
1987 MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
1988 new SimpleName ("System", loc), "Collections", loc), "Generic", loc);
1990 Expression rs_equals = null;
1991 Expression string_concat = new StringConstant ("<empty type>", loc);
1992 Expression rs_hashcode = new IntConstant (-2128831035, loc);
1993 for (int i = 0; i < parameters.Count; ++i) {
1994 AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
1995 Field f = (Field) Fields [i];
1997 MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
1998 system_collections_generic, "EqualityComparer",
1999 new TypeArguments (loc, new SimpleName (TypeParameters [i].Name, loc)), loc),
2002 ArrayList arguments_equal = new ArrayList (2);
2003 arguments_equal.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2004 arguments_equal.Add (new Argument (new MemberAccess (other_variable, f.Name)));
2006 Expression field_equal = new Invocation (new MemberAccess (equality_comparer,
2007 "Equals", loc), arguments_equal);
2009 ArrayList arguments_hashcode = new ArrayList (1);
2010 arguments_hashcode.Add (new Argument (new MemberAccess (new This (f.Location), f.Name)));
2011 Expression field_hashcode = new Invocation (new MemberAccess (equality_comparer,
2012 "GetHashCode", loc), arguments_hashcode);
2014 rs_hashcode = new Binary (Binary.Operator.Multiply,
2015 new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode),
2018 Expression field_to_string = new Conditional (new Binary (Binary.Operator.Inequality,
2019 new MemberAccess (new This (f.Location), f.Name), new NullConstant (loc)),
2020 new Invocation (new MemberAccess (
2021 new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
2022 new StringConstant ("<null>", loc));
2024 if (rs_equals == null) {
2025 rs_equals = field_equal;
2026 string_concat = new Binary (Binary.Operator.Addition,
2027 new StringConstant (p.Name + " = ", loc),
2033 // Implementation of ToString () body using string concatenation
2035 string_concat = new Binary (Binary.Operator.Addition,
2036 new Binary (Binary.Operator.Addition,
2038 new StringConstant (", " + p.Name + " = ", loc)),
2041 rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal);
2045 // Equals (object obj) override
2047 equals_block.AddStatement (new StatementExpression (
2048 new Assign (other_variable,
2049 new As (equals_block.GetParameterReference ("obj", loc),
2050 current_type, loc), loc)));
2052 Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc));
2053 if (rs_equals != null)
2054 equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals);
2055 equals_block.AddStatement (new Return (equals_test, loc));
2057 equals.Block = equals_block;
2058 equals.ResolveMembers ();
2062 // GetHashCode () override
2064 Method hashcode = new Method (this, null, TypeManager.system_int32_expr,
2065 Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("GetHashCode", loc),
2066 Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
2069 // Modified FNV with good avalanche behavior and uniform
2070 // distribution with larger hash sizes.
2072 // const int FNV_prime = 16777619;
2073 // int hash = (int) 2166136261;
2074 // foreach (int d in data)
2075 // hash = (hash ^ d) * FNV_prime;
2076 // hash += hash << 13;
2077 // hash ^= hash >> 7;
2078 // hash += hash << 3;
2079 // hash ^= hash >> 17;
2080 // hash += hash << 5;
2082 ToplevelBlock hashcode_block = new ToplevelBlock (loc);
2083 hashcode_block.AddVariable (TypeManager.system_int32_expr, "hash", loc);
2084 LocalVariableReference hash_variable = new LocalVariableReference (hashcode_block, "hash", loc);
2085 hashcode_block.AddStatement (new StatementExpression (
2086 new Assign (hash_variable, rs_hashcode)));
2088 hashcode_block.AddStatement (new StatementExpression (
2089 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2090 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (13, loc)))));
2091 hashcode_block.AddStatement (new StatementExpression (
2092 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2093 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (7, loc)))));
2094 hashcode_block.AddStatement (new StatementExpression (
2095 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2096 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (3, loc)))));
2097 hashcode_block.AddStatement (new StatementExpression (
2098 new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable,
2099 new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (17, loc)))));
2100 hashcode_block.AddStatement (new StatementExpression (
2101 new CompoundAssign (Binary.Operator.Addition, hash_variable,
2102 new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (5, loc)))));
2104 hashcode_block.AddStatement (new Return (hash_variable, loc));
2105 hashcode.Block = hashcode_block;
2106 hashcode.ResolveMembers ();
2107 AddMethod (hashcode);
2110 // ToString () override
2113 ToplevelBlock tostring_block = new ToplevelBlock (loc);
2114 tostring_block.AddStatement (new Return (string_concat, loc));
2115 tostring.Block = tostring_block;
2116 tostring.ResolveMembers ();
2117 AddMethod (tostring);
2120 public override bool DefineMembers ()
2124 return base.DefineMembers ();
2127 Attributes GetDebuggerHiddenAttribute ()
2129 return new Attributes (new Attribute (null, null,
2130 "System.Diagnostics.DebuggerHiddenAttribute", null, Location, false));
2133 public override string GetSignatureForError ()
2135 return SignatureForError;
2138 public ArrayList Parameters {