* driver.cs (BadAssembly): Handle all the ugliness of DefineDynamicAssembly.
[mono.git] / mcs / mcs / anonymous.cs
1 //
2 // anonymous.cs: Support for anonymous methods
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximain.com)
6 //
7 // (C) 2003, 2004 Novell, Inc.
8 //
9 // TODO: Ideally, we should have the helper classes emited as a hierarchy to map
10 // their nesting, and have the visibility set to private, instead of NestedAssembly
11 //
12 //
13 //
14
15 using System;
16 using System.Text;
17 using System.Collections;
18 using System.Reflection;
19 using System.Reflection.Emit;
20
21 namespace Mono.CSharp {
22
23         public abstract class CompilerGeneratedClass : Class
24         {
25                 GenericMethod generic_method;
26                 static int next_index = 0;
27
28                 private static MemberName MakeProxyName (GenericMethod generic, Location loc)
29                 {
30                         string name = String.Format ("<>c__CompilerGenerated{0}", ++next_index);
31                         if (generic != null) {
32                                 TypeArguments args = new TypeArguments (loc);
33                                 foreach (TypeParameter tparam in generic.CurrentTypeParameters)
34                                         args.Add (new SimpleName (tparam.Name, loc));
35                                 return new MemberName (name, args, loc);
36                         } else
37                                 return new MemberName (name, loc);
38                 }
39
40                 protected string MakeName (string prefix)
41                 {
42                         return String.Format ("<>c__{0}{1}", prefix, ++next_index);
43                 }
44
45                 protected CompilerGeneratedClass (TypeContainer parent, GenericMethod generic,
46                                                   int mod, Location loc)
47                         : base (parent.NamespaceEntry, parent,
48                                 MakeProxyName (generic, loc), mod, null)
49                 {
50                         this.generic_method = generic;
51
52                         if (generic != null) {
53                                 ArrayList list = new ArrayList ();
54                                 foreach (TypeParameter tparam in generic.TypeParameters) {
55                                         if (tparam.Constraints != null)
56                                                 list.Add (tparam.Constraints.Clone ());
57                                 }
58                                 SetParameterInfo (list);
59                         }
60
61                         parent.AddCompilerGeneratedClass (this);
62                 }
63
64                 protected override bool DefineNestedTypes ()
65                 {
66                         RootContext.RegisterCompilerGeneratedType (TypeBuilder);
67                         return base.DefineNestedTypes ();
68                 }
69
70                 protected override bool DoDefineMembers ()
71                 {
72                         members_defined = true;
73
74                         if (!base.DoDefineMembers ())
75                                 return false;
76
77                         if (CompilerGenerated != null) {
78                                 foreach (CompilerGeneratedClass c in CompilerGenerated) {
79                                         if (!c.DefineMembers ())
80                                                 throw new InternalErrorException ();
81                                 }
82                         }
83
84                         return true;
85                 }
86
87                 protected override bool DoResolveMembers ()
88                 {
89                         if (CompilerGenerated != null) {
90                                 foreach (CompilerGeneratedClass c in CompilerGenerated) {
91                                         if (!c.ResolveMembers ())
92                                                 return false;
93                                 }
94                         }
95
96                         return base.DoResolveMembers ();
97                 }
98
99                 public GenericMethod GenericMethod {
100                         get { return generic_method; }
101                 }
102
103                 public TypeExpr InflateType (Type it)
104                 {
105 #if GMCS_SOURCE
106                         if (generic_method == null)
107                                 return new TypeExpression (it, Location);
108
109                         if (it.IsGenericParameter && (it.DeclaringMethod != null)) {
110                                 int pos = it.GenericParameterPosition;
111                                 it = CurrentTypeParameters [pos].Type;
112                         } else if (it.IsGenericType) {
113                                 Type[] args = it.GetGenericArguments ();
114
115                                 TypeArguments inflated = new TypeArguments (Location);
116                                 foreach (Type t in args)
117                                         inflated.Add (InflateType (t));
118
119                                 return new ConstructedType (it, inflated, Location);
120                         } else if (it.IsArray) {
121                                 TypeExpr et_expr = InflateType (it.GetElementType ());
122                                 int rank = it.GetArrayRank ();
123
124                                 Type et = et_expr.ResolveAsTypeTerminal (this, false).Type;
125                                 it = et.MakeArrayType (rank);
126                         }
127 #endif
128
129                         return new TypeExpression (it, Location);
130                 }
131
132                 public Field CaptureVariable (string name, TypeExpr type)
133                 {
134                         if (members_defined)
135                                 throw new InternalErrorException ("Helper class already defined!");
136                         if (type == null)
137                                 throw new ArgumentNullException ();
138
139                         return new CapturedVariableField (this, name, type);
140                 }
141
142                 bool members_defined;
143
144                 internal void CheckMembersDefined ()
145                 {
146                         if (members_defined)
147                                 throw new InternalErrorException ("Helper class already defined!");
148                 }
149
150                 protected class CapturedVariableField : Field
151                 {
152                         public CapturedVariableField (CompilerGeneratedClass helper, string name,
153                                                       TypeExpr type)
154                                 : base (helper, type, Modifiers.INTERNAL, name, null, helper.Location)
155                         {
156                                 helper.AddField (this);
157                         }
158                 }
159         }
160
161         public class ScopeInfo : CompilerGeneratedClass
162         {
163                 public readonly AnonymousMethodHost RootScope;
164                 public readonly int ID = ++next_id;
165                 public Block ScopeBlock;
166
167                 static int next_id;
168
169                 public ScopeInfo (AnonymousMethodHost root, Block block)
170                         : base (root, null, Modifiers.PUBLIC, block.StartLocation)
171                 {
172                         this.RootScope = root;
173                         ScopeBlock = block;
174
175                         Report.Debug (64, "NEW SCOPE", this, root, block);
176
177                         root.AddScope (this);
178                 }
179
180                 public ScopeInfo (ToplevelBlock toplevel, TypeContainer parent,
181                                   GenericMethod generic, Location loc)
182                         : base (parent, generic, 0, loc)
183                 {
184                         RootScope = (AnonymousMethodHost) this;
185                         ScopeBlock = toplevel;
186
187                         Report.Debug (64, "NEW ROOT SCOPE", this);
188                 }
189
190                 protected CapturedScope scope_instance;
191                 protected ScopeInitializer scope_initializer;
192
193                 Hashtable locals = new Hashtable ();
194
195                 public virtual AnonymousMethodHost Host {
196                         get { return RootScope; }
197                 }
198
199                 public Variable ScopeInstance {
200                         get { return scope_instance; }
201                 }
202
203                 public void EmitScopeInstance (EmitContext ec)
204                 {
205                         if (scope_initializer == null) {
206                                 //
207                                 // This is needed if someone overwrites the Emit method
208                                 // of Statement and manually calls Block.Emit without
209                                 // this snippet first:
210                                 // 
211                                 //   ec.EmitScopeInitFromBlock (The_Block);
212                                 //   The_Block.Emit (ec);
213                                 // 
214                                 throw new InternalErrorException ();
215                         }
216
217                         scope_initializer.Emit (ec);
218                 }
219
220                 public ExpressionStatement GetScopeInitializer (EmitContext ec)
221                 {
222                         Report.Debug (64, "GET SCOPE INITIALIZER",
223                                       this, GetType (), scope_initializer, ScopeBlock);
224
225                         if (scope_initializer == null) {
226                                 scope_initializer = CreateScopeInitializer ();
227                                 if (scope_initializer.Resolve (ec) == null)
228                                         throw new InternalErrorException ();
229                         }
230
231                         return scope_initializer;
232                 }
233
234                 public Type GetScopeType (EmitContext ec)
235                 {
236                         if (!IsGeneric)
237                                 return TypeBuilder;
238
239                         TypeArguments targs = new TypeArguments (Location);
240
241                         if (ec.DeclContainer.Parent.IsGeneric)
242                                 foreach (TypeParameter t in ec.DeclContainer.Parent.TypeParameters)
243                                         targs.Add (new TypeParameterExpr (t, Location));
244                         if (ec.DeclContainer.IsGeneric)
245                                 foreach (TypeParameter t in ec.DeclContainer.CurrentTypeParameters)
246                                         targs.Add (new TypeParameterExpr (t, Location));
247
248                         TypeExpr te = new ConstructedType (TypeBuilder, targs, Location);
249                         te = te.ResolveAsTypeTerminal (ec, false);
250                         if ((te == null) || (te.Type == null))
251                                 return null;
252                         return te.Type;
253                 }
254
255                 protected override bool DoResolveMembers ()
256                 {
257                         Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
258                                       Parent.IsGeneric, GenericMethod);
259
260                         if (Host != this)
261                                 scope_instance = new CapturedScope (Host, this);
262
263                         return base.DoResolveMembers ();
264                 }
265
266                 public Variable AddLocal (LocalInfo local)
267                 {
268                         Variable var = (Variable) locals [local];
269                         if (var == null) {
270                                 var = new CapturedLocal (this, local);
271                                 locals.Add (local, var);
272                                 local.IsCaptured = true;
273                         }
274                         return var;
275                 }
276
277                 public Variable GetCapturedVariable (LocalInfo local)
278                 {
279                         return (Variable) locals [local];
280                 }
281
282                 protected string MakeFieldName (string local_name)
283                 {
284                         return "<" + ID + ":" + local_name + ">";
285                 }
286
287                 protected virtual ScopeInitializer CreateScopeInitializer ()
288                 {
289                         return new ScopeInitializer (this);
290                 }
291
292                 protected abstract class CapturedVariable : Variable
293                 {
294                         public readonly ScopeInfo Scope;
295                         public readonly Field Field;
296
297                         public FieldExpr FieldInstance;
298
299                         protected CapturedVariable (ScopeInfo scope, string name, Type type)
300                         {
301                                 this.Scope = scope;
302                                 this.Field = scope.CaptureVariable (
303                                         scope.MakeFieldName (name), scope.RootScope.InflateType (type));
304                         }
305
306                         public override Type Type {
307                                 get { return Field.MemberType; }
308                         }
309
310                         public override bool HasInstance {
311                                 get { return true; }
312                         }
313
314                         public override bool NeedsTemporary {
315                                 get { return true; }
316                         }
317
318                         protected FieldInfo GetField (EmitContext ec)
319                         {
320                                 if (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)
321                                         return Field.FieldBuilder;
322                                 else
323                                         return FieldInstance.FieldInfo;
324                         }
325
326                         public override void EmitInstance (EmitContext ec)
327                         {
328                                 ec.CurrentBlock.Toplevel.EmitScopeInstance (ec, Scope);
329                         }
330
331                         public override void Emit (EmitContext ec)
332                         {
333                                 ec.ig.Emit (OpCodes.Ldfld, GetField (ec));
334                         }
335
336                         public override void EmitAssign (EmitContext ec)
337                         {
338                                 ec.ig.Emit (OpCodes.Stfld, GetField (ec));
339                         }
340
341                         public override void EmitAddressOf (EmitContext ec)
342                         {
343                                 ec.ig.Emit (OpCodes.Ldflda, GetField (ec));
344                         }
345                 }
346
347                 protected class CapturedParameter : CapturedVariable {
348                         public readonly Parameter Parameter;
349                         public readonly int Idx;
350
351                         public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
352                                 : base (scope, par.Name, par.ParameterType)
353                         {
354                                 this.Parameter = par;
355                                 this.Idx = idx;
356                         }
357
358                         public override string ToString ()
359                         {
360                                 return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
361                                                       Parameter.Name, Idx);
362                         }
363                 }
364
365                 protected class CapturedLocal : CapturedVariable {
366                         public readonly LocalInfo Local;
367
368                         public CapturedLocal (ScopeInfo scope, LocalInfo local)
369                                 : base (scope, local.Name, local.VariableType)
370                         {
371                                 this.Local = local;
372                         }
373
374                         public override string ToString ()
375                         {
376                                 return String.Format ("{0} ({1}:{2})", GetType (), Field,
377                                                       Local.Name);
378                         }
379                 }
380
381                 protected class CapturedThis : CapturedVariable {
382                         public CapturedThis (AnonymousMethodHost host)
383                                 : base (host, "<>THIS", host.ParentType)
384                         { }
385                 }
386
387                 protected class CapturedScope : CapturedVariable {
388                         public readonly ScopeInfo ChildScope;
389
390                         public CapturedScope (ScopeInfo root, ScopeInfo child)
391                                 : base (root, child.ID + "_scope",
392                                         child.IsGeneric ? child.CurrentType : child.TypeBuilder)
393                         {
394                                 this.ChildScope = child;
395                         }
396                 }
397
398                 static void DoPath (StringBuilder sb, ScopeInfo start)
399                 {
400                         sb.Append ((start.ID).ToString ());
401                 }
402                 
403                 public override string ToString ()
404                 {
405                         StringBuilder sb = new StringBuilder ();
406                         
407                         sb.Append ("{");
408                         DoPath (sb, this);
409                         sb.Append ("}");
410
411                         return sb.ToString ();
412                 }
413
414                 protected class ScopeInitializer : ExpressionStatement
415                 {
416                         ScopeInfo scope;
417                         LocalBuilder scope_instance;
418                         ConstructorInfo scope_ctor;
419
420                         bool initialized;
421
422                         public ScopeInitializer (ScopeInfo scope)
423                         {
424                                 this.scope = scope;
425                                 this.loc = scope.Location;
426                                 eclass = ExprClass.Value;
427                         }
428
429                         public ScopeInfo Scope {
430                                 get { return scope; }
431                         }
432
433                         public override Expression DoResolve (EmitContext ec)
434                         {
435                                 if (scope_ctor != null)
436                                         return this;
437
438                                 Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
439                                               ec, ec.CurrentBlock);
440
441                                 type = Scope.GetScopeType (ec);
442                                 if (type == null)
443                                         throw new InternalErrorException ();
444
445                                 if (!DoResolveInternal (ec))
446                                         throw new InternalErrorException ();
447
448                                 return this;
449                         }
450
451                         protected virtual bool DoResolveInternal (EmitContext ec)
452                         {
453                                 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookupFinal (
454                                         ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
455                                         AllBindingFlags | BindingFlags.DeclaredOnly, loc);
456                                 if (mg == null)
457                                         throw new InternalErrorException ();
458
459                                 scope_ctor = (ConstructorInfo) mg.Methods [0];
460
461                                 if (Scope.ScopeInstance == null)
462                                         scope_instance = ec.ig.DeclareLocal (type);
463                                 else {
464                                         Type root = Scope.Host.GetScopeType (ec);
465                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
466                                                 type, root, Scope.scope_instance.Field.Name, loc);
467                                         if (fe == null)
468                                                 throw new InternalErrorException ();
469
470                                         fe.InstanceExpression = this;
471                                         Scope.scope_instance.FieldInstance = fe;
472                                 }
473
474                                 foreach (CapturedLocal local in Scope.locals.Values) {
475                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
476                                                 ec.ContainerType, type, local.Field.Name, loc);
477                                         Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope,
478                                                       Scope, ec, ec.ContainerType, type,
479                                                       local.Field, local.Field.Name, loc, fe);
480                                         if (fe == null)
481                                                 throw new InternalErrorException ();
482
483                                         fe.InstanceExpression = this;
484                                         local.FieldInstance = fe;
485                                 }
486
487                                 return true;
488                         }
489
490                         protected virtual void EmitParameterReference (EmitContext ec,
491                                                                        CapturedParameter cp)
492                         {
493                                 int extra = ec.IsStatic ? 0 : 1;
494                                 ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
495                         }
496
497                         static int next_id;
498                         int id = ++next_id;
499
500                         protected virtual void DoEmit (EmitContext ec)
501                         {
502                                 if (ec.CurrentBlock.Toplevel == Scope.ScopeBlock.Toplevel)
503                                         DoEmitInstance (ec);
504                                 else
505                                         ec.ig.Emit (OpCodes.Ldarg_0);
506                         }
507
508                         protected void DoEmitInstance (EmitContext ec)
509                         {
510                                 ec.ig.Emit (OpCodes.Ldloc, scope_instance);
511                         }
512
513                         protected virtual void EmitScopeConstructor (EmitContext ec)
514                         {
515                                 ec.ig.Emit (OpCodes.Newobj, scope_ctor);
516                         }
517
518                         public override void Emit (EmitContext ec)
519                         {
520                                 if (!initialized)
521                                         throw new InternalErrorException (
522                                                 "Scope {0} not initialized yet", scope);
523
524                                 DoEmit (ec);
525                         }
526
527                         public override void EmitStatement (EmitContext ec)
528                         {
529                                 if (initialized)
530                                         return;
531
532                                 DoEmitStatement (ec);
533                                 initialized = true;
534                         }
535
536                         protected virtual void DoEmitStatement (EmitContext ec)
537                         {
538                                 Report.Debug (64, "EMIT SCOPE INIT", this, id,
539                                               Scope, scope_instance, ec);
540
541                                 ec.ig.Emit (OpCodes.Nop);
542                                 ec.ig.Emit (OpCodes.Ldc_I4, id);
543                                 ec.ig.Emit (OpCodes.Pop);
544                                 ec.ig.Emit (OpCodes.Nop);
545
546                                 if (Scope != Scope.Host)
547                                         Scope.Host.EmitScopeInstance (ec);
548                                 else if (Scope.ScopeInstance != null)
549                                         ec.ig.Emit (OpCodes.Ldarg_0);
550                                 EmitScopeConstructor (ec);
551                                 if (Scope.ScopeInstance != null)
552                                         Scope.ScopeInstance.EmitAssign (ec);
553                                 else
554                                         ec.ig.Emit (OpCodes.Stloc, scope_instance);
555                         }
556                 }
557         }
558
559         public class AnonymousMethodHost : ScopeInfo
560         {
561                 public AnonymousMethodHost (ToplevelBlock toplevel, TypeContainer parent,
562                                             GenericMethod generic, Location loc)
563                         : base (toplevel, parent, generic, loc)
564                 {
565                         scopes = new ArrayList ();
566                 }
567
568                 ArrayList scopes;
569                 TypeExpr parent_type;
570                 CapturedVariableField parent_link;
571                 CapturedThis this_variable;
572                 Hashtable captured_params;
573
574                 public override AnonymousMethodHost Host {
575                         get { return this; }
576                 }
577
578                 public virtual bool IsIterator {
579                         get { return false; }
580                 }
581
582                 public AnonymousMethodHost ParentHost {
583                         get { return Parent as AnonymousMethodHost; }
584                 }
585
586                 public Type ParentType {
587                         get { return parent_type.Type; }
588                 }
589
590                 public Field ParentLink {
591                         get { return parent_link; }
592                 }
593
594                 protected CapturedThis THIS {
595                         get { return this_variable; }
596                 }
597
598                 public bool HostsParameters {
599                         get { return captured_params != null; }
600                 }
601
602                 public Variable CaptureThis ()
603                 {
604                         if (ParentHost != null)
605                                 return ParentHost.CaptureThis ();
606
607                         CheckMembersDefined ();
608                         if (this_variable == null)
609                                 this_variable = new CapturedThis (this);
610                         return this_variable;
611                 }
612
613                 public Variable GetCapturedParameter (Parameter par)
614                 {
615                         if (captured_params != null)
616                                 return (Variable) captured_params [par];
617                         else
618                                 return null;
619                 }
620
621                 public bool IsParameterCaptured (string name)
622                 {                       
623                         if (captured_params != null)
624                                 return captured_params [name] != null;
625                         return false;
626                 }
627
628                 public Variable AddParameter (Parameter par, int idx)
629                 {
630                         if (captured_params == null)
631                                 captured_params = new Hashtable ();
632
633                         Variable var = (Variable) captured_params [par];
634                         if (var == null) {
635                                 var = new CapturedParameter (this, par, idx);
636                                 captured_params.Add (par, var);
637                                 par.IsCaptured = true;
638                         }
639
640                         return var;
641                 }
642
643                 public void AddScope (ScopeInfo scope)
644                 {
645                         scopes.Add (scope);
646                 }
647
648                 bool linked;
649                 public void LinkScopes ()
650                 {
651                         if (linked)
652                                 return;
653
654                         linked = true;
655                         if (ParentHost != null)
656                                 ParentHost.LinkScopes ();
657
658                         foreach (ScopeInfo si in scopes) {
659                                 if (!si.Define ())
660                                         throw new InternalErrorException ();
661                                 if (si.DefineType () == null)
662                                         throw new InternalErrorException ();
663                         }
664                 }
665
666                 protected override ScopeInitializer CreateScopeInitializer ()
667                 {
668                         return new AnonymousMethodHostInitializer (this);
669                 }
670
671                 protected override bool DefineNestedTypes ()
672                 {
673                         if (Parent.IsGeneric) {
674                                 parent_type = new ConstructedType (
675                                         Parent.TypeBuilder, Parent.TypeParameters, Location);
676                                 parent_type = parent_type.ResolveAsTypeTerminal (this, false);
677                                 if ((parent_type == null) || (parent_type.Type == null))
678                                         return false;
679                         } else {
680                                 parent_type = new TypeExpression (Parent.TypeBuilder, Location);
681                         }
682
683                         CompilerGeneratedClass parent = Parent as CompilerGeneratedClass;
684                         if (parent != null)
685                                 parent_link = new CapturedVariableField (this, "<>parent", parent_type);
686
687                         return base.DefineNestedTypes ();
688                 }
689
690                 protected override bool DoDefineMembers ()
691                 {
692                         ArrayList args = new ArrayList ();
693                         if (this is IteratorHost)
694                                 args.Add (new Parameter (
695                                         TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
696                                         null, Location));
697
698                         Field pfield;
699                         if (Parent is CompilerGeneratedClass)
700                                 pfield = parent_link;
701                         else
702                                 pfield = this_variable !=  null ? this_variable.Field : null;
703                         if (pfield != null)
704                                 args.Add (new Parameter (
705                                         pfield.MemberType, "parent", Parameter.Modifier.NONE,
706                                         null, Location));
707
708                         if (HostsParameters) {
709                                 foreach (CapturedParameter cp in captured_params.Values) {
710                                         args.Add (new Parameter (
711                                                           cp.Field.MemberType, cp.Field.Name,
712                                                           Parameter.Modifier.NONE, null, Location));
713                                 }
714                         }
715
716                         Parameter[] ctor_params = new Parameter [args.Count];
717                         args.CopyTo (ctor_params, 0);
718                         Constructor ctor = new Constructor (
719                                 this, MemberName.Name, Modifiers.PUBLIC,
720                                 new Parameters (ctor_params),
721                                 new GeneratedBaseInitializer (Location),
722                                 Location);
723                         AddConstructor (ctor);
724
725                         ctor.Block = new ToplevelBlock (null, Location);
726                         ctor.Block.AddStatement (new TheCtor (this));
727
728                         return base.DoDefineMembers ();
729                 }
730
731                 protected virtual void EmitScopeConstructor (EmitContext ec)
732                 {
733                         int pos = (this is IteratorHost) ? 2 : 1;
734
735                         Field pfield;
736                         if (Parent is CompilerGeneratedClass)
737                                 pfield = parent_link;
738                         else
739                                 pfield = this_variable !=  null ? this_variable.Field : null;
740
741                         if (pfield != null) {
742                                 ec.ig.Emit (OpCodes.Ldarg_0);
743                                 ec.ig.Emit (OpCodes.Ldarg, pos);
744                                 ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
745                                 pos++;
746                         }
747
748                         if (HostsParameters) {
749                                 foreach (CapturedParameter cp in captured_params.Values) {
750                                         ec.ig.Emit (OpCodes.Ldarg_0);
751                                         ParameterReference.EmitLdArg (ec.ig, pos++);
752                                         ec.ig.Emit (OpCodes.Stfld, cp.Field.FieldBuilder);
753                                 }
754                         }
755                 }
756
757                 protected class TheCtor : Statement
758                 {
759                         AnonymousMethodHost host;
760
761                         public TheCtor (AnonymousMethodHost host)
762                         {
763                                 this.host = host;
764                         }
765
766                         public override bool Resolve (EmitContext ec)
767                         {
768                                 return true;
769                         }
770
771                         protected override void DoEmit (EmitContext ec)
772                         {
773                                 host.EmitScopeConstructor (ec);
774                         }
775                 }
776
777                 protected class AnonymousMethodHostInitializer : ScopeInitializer
778                 {
779                         AnonymousMethodHost host;
780
781                         public AnonymousMethodHostInitializer (AnonymousMethodHost host)
782                                 : base (host)
783                         {
784                                 this.host = host;
785                         }
786
787                         public AnonymousMethodHost Host {
788                                 get { return host; }
789                         }
790
791                         protected override bool DoResolveInternal (EmitContext ec)
792                         {
793                                 Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
794                                               this, Host, Host.ParentType, loc);
795
796                                 if (Host.THIS != null) {
797                                         FieldExpr fe = (FieldExpr) Expression.MemberLookup (
798                                                 ec.ContainerType, type, Host.THIS.Field.Name, loc);
799                                         if (fe == null)
800                                                 throw new InternalErrorException ();
801
802                                         fe.InstanceExpression = this;
803                                         Host.THIS.FieldInstance = fe;
804                                 }
805
806                                 //
807                                 // Copy the parameter values, if any
808                                 //
809                                 if (Host.HostsParameters) {
810                                         foreach (CapturedParameter cp in Host.captured_params.Values) {
811                                                 FieldExpr fe = (FieldExpr) Expression.MemberLookup (
812                                                         ec.ContainerType, type, cp.Field.Name, loc);
813                                                 if (fe == null)
814                                                         throw new InternalErrorException ();
815
816                                                 fe.InstanceExpression = this;
817                                                 cp.FieldInstance = fe;
818                                         }
819                                 }
820
821                                 return base.DoResolveInternal (ec);
822                         }
823
824                         protected virtual bool IsGetEnumerator {
825                                 get { return false; }
826                         }
827
828                         protected override void EmitScopeConstructor (EmitContext ec)
829                         {
830                                 if (host.THIS != null) {
831                                         ec.ig.Emit (OpCodes.Ldarg_0);
832                                         if (IsGetEnumerator)
833                                                 ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
834                                         else if (host.THIS.Type.IsValueType)
835                                                 Expression.LoadFromPtr (ec.ig, host.THIS.Type);
836                                 } else if (host.ParentLink != null)
837                                         ec.ig.Emit (OpCodes.Ldarg_0);
838
839                                 if (Host.HostsParameters) {
840                                         foreach (CapturedParameter cp in Host.captured_params.Values) {
841                                                 EmitParameterReference (ec, cp);
842                                         }
843                                 }
844
845                                 base.EmitScopeConstructor (ec);
846                         }
847                 }
848
849         }
850
851         public interface IAnonymousContainer
852         {
853                 Block Container {
854                         get;
855                 }
856
857                 GenericMethod GenericMethod {
858                         get;
859                 }
860
861                 AnonymousMethodHost RootScope {
862                         get;
863                 }
864
865                 bool IsIterator {
866                         get;
867                 }
868         }
869
870         public interface IAnonymousHost
871         {
872                 //
873                 // Invoked if a yield statement is found in the body
874                 //
875                 void SetYields ();
876
877                 //
878                 // Invoked if an anonymous method is found in the body
879                 //
880                 void AddAnonymousMethod (AnonymousMethodExpression anonymous);
881         }
882
883         public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
884         {
885                 public readonly AnonymousMethodExpression Parent;
886                 public readonly TypeContainer Host;
887                 public readonly Parameters Parameters;
888
889                 public ToplevelBlock Block;
890                 protected AnonymousMethod anonymous;
891
892                 protected readonly Block container;
893                 protected readonly GenericMethod generic;
894
895                 public Block Container {
896                         get { return container; }
897                 }
898
899                 public GenericMethod GenericMethod {
900                         get { return generic; }
901                 }
902
903                 public AnonymousMethod AnonymousMethod {
904                         get { return anonymous; }
905                 }
906
907                 public AnonymousMethodHost RootScope {
908                         get { return root_scope; }
909                 }
910
911                 public AnonymousMethodExpression (AnonymousMethodExpression parent,
912                                                   GenericMethod generic, TypeContainer host,
913                                                   Parameters parameters, Block container,
914                                                   Location loc)
915                 {
916                         this.Parent = parent;
917                         this.generic = parent != null ? null : generic;
918                         this.Host = host;
919                         this.Parameters = parameters;
920                         this.container = container;
921                         this.loc = loc;
922
923                         Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host,
924                                       container, loc);
925
926                         if (parent != null)
927                                 parent.AddAnonymousMethod (this);
928                 }
929
930                 ArrayList children;
931                 AnonymousMethodHost root_scope;
932
933                 static int next_index;
934
935                 void IAnonymousHost.SetYields ()
936                 {
937                         throw new InvalidOperationException ();
938                 }
939
940                 public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
941                 {
942                         if (children == null)
943                                 children = new ArrayList ();
944                         children.Add (anonymous);
945                 }
946
947                 public bool CreateAnonymousHelpers ()
948                 {
949                         Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
950                                       this, Host, container, loc);
951
952                         if (container != null)
953                                 root_scope = container.Toplevel.CreateAnonymousMethodHost (Host);
954
955                         if (children != null) {
956                                 foreach (AnonymousMethodExpression child in children) {
957                                         if (!child.CreateAnonymousHelpers ())
958                                                 return false;
959                                 }
960                         }
961
962                         return true;
963                 }
964
965                 public override string ExprClassName {
966                         get {
967                                 return "anonymous method";
968                         }
969                 }
970
971                 void Error_ParameterMismatch (Type t)
972                 {
973                         Report.Error (1661, loc, "Anonymous method could not be converted to delegate `" +
974                                       "{0}' since there is a parameter mismatch",
975                                       TypeManager.CSharpName (t));
976                 }
977
978                 public bool ImplicitStandardConversionExists (Type delegate_type)
979                 {
980                         if (Parameters == null)
981                                 return true;
982
983                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
984                                 Host.TypeBuilder, delegate_type, loc);
985                         MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
986                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
987
988                         if (Parameters.Count != invoke_pd.Count)
989                                 return false;
990
991                         for (int i = 0; i < Parameters.Count; ++i) {
992                                 if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i))
993                                         return false;
994                         }
995                         return true;
996                 }
997
998                 //
999                 // Returns true if this anonymous method can be implicitly
1000                 // converted to the delegate type `delegate_type'
1001                 //
1002                 public Expression Compatible (EmitContext ec, Type delegate_type)
1003                 {
1004                         if (anonymous != null)
1005                                 return anonymous.AnonymousDelegate;
1006
1007                         if (!ec.IsAnonymousMethodAllowed) {
1008                                 Report.Error (1706, loc,
1009                                               "Anonymous methods are not allowed in the " +
1010                                               "attribute declaration");
1011                                 return null;
1012                         }
1013
1014                         if (!TypeManager.IsDelegateType (delegate_type)){
1015                                 Report.Error (1660, loc,
1016                                               "Cannot convert anonymous method block to type " +
1017                                               "`{0}' because it is not a delegate type",
1018                                               TypeManager.CSharpName (delegate_type));
1019                                 return null;
1020                         }
1021
1022                         //
1023                         // At this point its the first time we know the return type that is 
1024                         // needed for the anonymous method.  We create the method here.
1025                         //
1026
1027                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
1028                                 ec.ContainerType, delegate_type, loc);
1029                         MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
1030                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
1031
1032                         Parameters parameters;
1033                         if (Parameters == null) {
1034                                 //
1035                                 // We provide a set of inaccessible parameters
1036                                 //
1037                                 Parameter [] fixedpars = new Parameter [invoke_pd.Count];
1038                                                                 
1039                                 for (int i = 0; i < invoke_pd.Count; i++) {
1040                                         Parameter.Modifier i_mod = invoke_pd.ParameterModifier (i);
1041                                         if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
1042                                                 Report.Error (1688, loc, "Cannot convert anonymous " +
1043                                                               "method block without a parameter list " +
1044                                                               "to delegate type `{0}' because it has " +
1045                                                               "one or more `out' parameters.",
1046                                                               TypeManager.CSharpName (delegate_type));
1047                                                 return null;
1048                                         }
1049                                         fixedpars [i] = new Parameter (
1050                                                 invoke_pd.ParameterType (i), "+" + (++next_index),
1051                                                 invoke_pd.ParameterModifier (i), null, loc);
1052                                 }
1053                                                                 
1054                                 parameters = new Parameters (fixedpars);
1055                                 if (!parameters.Resolve (ec))
1056                                         return null;
1057                         } else {
1058                                 if (Parameters.Count != invoke_pd.Count) {
1059                                         Report.SymbolRelatedToPreviousError (delegate_type);
1060                                         Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
1061                                                 TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
1062                                         Error_ParameterMismatch (delegate_type);
1063                                         return null;
1064                                 }
1065
1066                                 for (int i = 0; i < Parameters.Count; ++i) {
1067                                         Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
1068                                         if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
1069                                                 if (p_mod == Parameter.Modifier.NONE)
1070                                                         Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
1071                                                                 (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
1072                                                 else
1073                                                         Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
1074                                                                 (i+1).ToString (), Parameter.GetModifierSignature (p_mod));
1075                                                 Error_ParameterMismatch (delegate_type);
1076                                                 return null;
1077                                         }
1078
1079                                         if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
1080                                                 Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
1081                                                         (i+1).ToString (),
1082                                                         TypeManager.CSharpName (Parameters.ParameterType (i)),
1083                                                         TypeManager.CSharpName (invoke_pd.ParameterType (i)));
1084                                                 Error_ParameterMismatch (delegate_type);
1085                                                 return null;
1086                                         }
1087                                 }
1088
1089                                 parameters = Parameters;
1090                         }
1091
1092                         //
1093                         // Second: the return type of the delegate must be compatible with 
1094                         // the anonymous type.   Instead of doing a pass to examine the block
1095                         // we satisfy the rule by setting the return type on the EmitContext
1096                         // to be the delegate type return type.
1097                         //
1098
1099                         //MethodBuilder builder = method_data.MethodBuilder;
1100                         //ILGenerator ig = builder.GetILGenerator ();
1101
1102                         Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
1103                                       Container, Block, invoke_mb.ReturnType, delegate_type,
1104                                       TypeManager.IsGenericType (delegate_type), loc);
1105
1106                         anonymous = new AnonymousMethod (
1107                                 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
1108                                 GenericMethod, parameters, Container, Block, invoke_mb.ReturnType,
1109                                 delegate_type, loc);
1110
1111                         if (!anonymous.Resolve (ec))
1112                                 return null;
1113
1114                         return anonymous.AnonymousDelegate;
1115                 }
1116
1117                 public override Expression DoResolve (EmitContext ec)
1118                 {
1119                         //
1120                         // Set class type, set type
1121                         //
1122
1123                         eclass = ExprClass.Value;
1124
1125                         //
1126                         // This hack means `The type is not accessible
1127                         // anywhere', we depend on special conversion
1128                         // rules.
1129                         // 
1130                         type = TypeManager.anonymous_method_type;
1131
1132                         if ((Parameters != null) && !Parameters.Resolve (ec))
1133                                 return null;
1134
1135                         return this;
1136                 }
1137
1138                 public override void Emit (EmitContext ec)
1139                 {
1140                         // nothing, as we only exist to not do anything.
1141                 }
1142
1143                 public bool IsIterator {
1144                         get { return false; }
1145                 }
1146         }
1147
1148         public abstract class AnonymousContainer : IAnonymousContainer
1149         {
1150                 // Used to generate unique method names.
1151                 protected static int anonymous_method_count;
1152
1153                 public readonly Location Location;
1154
1155                 // An array list of AnonymousMethodParameter or null
1156                 public readonly Parameters Parameters;
1157
1158                 //
1159                 // The block that makes up the body for the anonymous mehtod
1160                 //
1161                 public readonly ToplevelBlock Block;
1162
1163                 public readonly int ModFlags;
1164                 public Type ReturnType;
1165                 public readonly TypeContainer Host;
1166
1167                 //
1168                 // The implicit method we create
1169                 //
1170                 protected Method method;
1171                 protected EmitContext aec;
1172
1173                 // The emit context for the anonymous method
1174                 protected bool unreachable;
1175                 protected readonly Block container;
1176                 protected readonly GenericMethod generic;
1177
1178                 //
1179                 // Points to our container anonymous method if its present
1180                 //
1181                 public readonly AnonymousContainer ContainerAnonymousMethod;
1182
1183                 protected AnonymousContainer (AnonymousContainer parent, TypeContainer host,
1184                                               GenericMethod generic, Parameters parameters,
1185                                               Block container, ToplevelBlock block,
1186                                               Type return_type, int mod, Location loc)
1187                 {
1188                         this.ContainerAnonymousMethod = parent;
1189                         this.ReturnType = return_type;
1190                         this.ModFlags = mod;
1191                         this.Host = host;
1192
1193                         this.container = container;
1194                         this.generic = parent != null ? null : generic;
1195                         this.Parameters = parameters;
1196                         this.Block = block;
1197                         this.Location = loc;
1198                 }
1199
1200                 public Method Method {
1201                         get { return method; }
1202                 }
1203
1204                 public abstract AnonymousMethodHost RootScope {
1205                         get;
1206                 }
1207
1208                 public abstract string GetSignatureForError ();
1209
1210                 public virtual bool Resolve (EmitContext ec)
1211                 {
1212                         Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
1213                                       RootScope, Parameters, ec.IsStatic);
1214
1215                         if (ReturnType != null) {
1216                                 TypeExpr return_type_expr;
1217                                 if (RootScope != null)
1218                                         return_type_expr = RootScope.InflateType (ReturnType);
1219                                 else
1220                                         return_type_expr = new TypeExpression (ReturnType, Location);
1221                                 return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
1222                                 if ((return_type_expr == null) || (return_type_expr.Type == null))
1223                                         return false;
1224                                 ReturnType = return_type_expr.Type;
1225                         }
1226
1227                         aec = new EmitContext (
1228                                 ec.ResolveContext, ec.TypeContainer,
1229                                 RootScope != null ? RootScope : Host, Location, null, ReturnType,
1230                                 /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
1231                                 (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
1232
1233                         aec.CurrentAnonymousMethod = this;
1234                         aec.IsFieldInitializer = ec.IsFieldInitializer;
1235                         aec.IsStatic = ec.IsStatic;
1236
1237                         Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
1238                                       RootScope, Parameters, Block);
1239
1240                         bool unreachable;
1241                         if (!aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable))
1242                                 return false;
1243
1244                         Report.Debug (64, "RESOLVE ANONYMOUS METHOD #3", this, ec, aec, Block);
1245
1246                         method = DoCreateMethodHost (ec);
1247
1248                         if (RootScope != null)
1249                                 return true;
1250
1251                         if (!method.ResolveMembers ())
1252                                 return false;
1253                         return method.Define ();
1254                 }
1255
1256                 protected abstract Method DoCreateMethodHost (EmitContext ec);
1257
1258                 public Block Container {
1259                         get { return container; }
1260                 }
1261
1262                 public GenericMethod GenericMethod {
1263                         get { return generic; }
1264                 }
1265
1266                 public abstract bool IsIterator {
1267                         get;
1268                 }
1269
1270                 protected class AnonymousMethodMethod : Method
1271                 {
1272                         public AnonymousContainer AnonymousMethod;
1273
1274                         public AnonymousMethodMethod (AnonymousContainer am, GenericMethod generic,
1275                                                       TypeExpr return_type, int mod, MemberName name,
1276                                                       Parameters parameters)
1277                                 : base (am.RootScope != null ? am.RootScope : am.Host,
1278                                         generic, return_type, mod, false, name, parameters, null)
1279                         {
1280                                 this.AnonymousMethod = am;
1281
1282                                 if (am.RootScope != null) {
1283                                         am.RootScope.CheckMembersDefined ();
1284                                         am.RootScope.AddMethod (this);
1285                                 } else {
1286                                         ModFlags |= Modifiers.STATIC;
1287                                         am.Host.AddMethod (this);
1288                                 }
1289                                 Block = am.Block;
1290                         }
1291
1292                         public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
1293                         {
1294                                 EmitContext aec = AnonymousMethod.aec;
1295                                 aec.ig = ig;
1296                                 return aec;
1297                         }
1298                 }
1299         }
1300
1301         public class AnonymousMethod : AnonymousContainer
1302         {
1303                 public readonly Type DelegateType;
1304
1305                 //
1306                 // The value return by the Compatible call, this ensure that
1307                 // the code works even if invoked more than once (Resolve called
1308                 // more than once, due to the way Convert.ImplicitConversion works
1309                 //
1310                 Expression anonymous_delegate;
1311                 AnonymousMethodHost root_scope;
1312
1313                 public AnonymousMethod (AnonymousMethod parent, AnonymousMethodHost root_scope,
1314                                         TypeContainer host, GenericMethod generic,
1315                                         Parameters parameters, Block container,
1316                                         ToplevelBlock block, Type return_type, Type delegate_type,
1317                                         Location loc)
1318                         : base (parent, host, generic, parameters, container, block,
1319                                 return_type, 0, loc)
1320                 {
1321                         this.DelegateType = delegate_type;
1322                         this.root_scope = root_scope;
1323                 }
1324
1325                 public override AnonymousMethodHost RootScope {
1326                         get { return root_scope; }
1327                 }
1328
1329                 public override bool IsIterator {
1330                         get { return false; }
1331                 }
1332
1333                 public Expression AnonymousDelegate {
1334                         get { return anonymous_delegate; }
1335                 }
1336
1337                 public override string GetSignatureForError ()
1338                 {
1339                         return TypeManager.CSharpName (DelegateType);
1340                 }
1341
1342                 //
1343                 // Creates the host for the anonymous method
1344                 //
1345                 protected override Method DoCreateMethodHost (EmitContext ec)
1346                 {
1347                         string name = "<>c__AnonymousMethod" + anonymous_method_count++;
1348                         MemberName member_name;
1349
1350                         GenericMethod generic_method = null;
1351 #if GMCS_SOURCE
1352                         if (TypeManager.IsGenericType (DelegateType)) {
1353                                 TypeArguments args = new TypeArguments (Location);
1354
1355                                 Type dt = DelegateType.GetGenericTypeDefinition ();
1356
1357                                 Type[] tparam = TypeManager.GetTypeArguments (dt);
1358                                 for (int i = 0; i < tparam.Length; i++)
1359                                         args.Add (new SimpleName (tparam [i].Name, Location));
1360
1361                                 member_name = new MemberName (name, args, Location);
1362
1363                                 generic_method = new GenericMethod (
1364                                         RootScope.NamespaceEntry, RootScope, member_name,
1365                                         new TypeExpression (ReturnType, Location), Parameters);
1366
1367                                 generic_method.SetParameterInfo (null);
1368                         } else
1369 #endif
1370                                 member_name = new MemberName (name, Location);
1371
1372                         return new AnonymousMethodMethod (
1373                                 this, generic_method, new TypeExpression (ReturnType, Location),
1374                                 Modifiers.INTERNAL, member_name, Parameters);
1375                 }
1376
1377                 public override bool Resolve (EmitContext ec)
1378                 {
1379                         if (!base.Resolve (ec))
1380                                 return false;
1381
1382                         anonymous_delegate = new AnonymousDelegate (
1383                                 this, DelegateType, Location).Resolve (ec);
1384                         if (anonymous_delegate == null)
1385                                 return false;
1386
1387                         return true;
1388                 }
1389
1390                 public MethodInfo GetMethodBuilder (EmitContext ec)
1391                 {
1392                         MethodInfo builder = method.MethodBuilder;
1393                         if ((RootScope != null) && RootScope.IsGeneric) {
1394                                 Type scope_type = RootScope.GetScopeType (ec);
1395                                 if (scope_type == null)
1396                                         throw new InternalErrorException ();
1397
1398                                 MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
1399                                         ec.ContainerType, scope_type, builder.Name, Location);
1400
1401                                 if (mg == null)
1402                                         throw new InternalErrorException ();
1403                                 builder = (MethodInfo) mg.Methods [0];
1404                         }
1405
1406 #if GMCS_SOURCE
1407                         if (!DelegateType.IsGenericType)
1408                                 return builder;
1409
1410                         Type[] targs = TypeManager.GetTypeArguments (DelegateType);
1411                         return builder.MakeGenericMethod (targs);
1412 #else
1413                         return builder;
1414 #endif
1415                 }
1416
1417                 public static void Error_AddressOfCapturedVar (string name, Location loc)
1418                 {
1419                         Report.Error (1686, loc,
1420                                       "Local variable `{0}' or its members cannot have their " +
1421                                       "address taken and be used inside an anonymous method block",
1422                                       name);
1423                 }
1424         }
1425
1426         //
1427         // This will emit the code for the delegate, as well delegate creation on the host
1428         //
1429         public class AnonymousDelegate : DelegateCreation {
1430                 AnonymousMethod am;
1431
1432                 public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
1433                 {
1434                         type = target_type;
1435                         loc = l;
1436                         this.am = am;
1437                 }
1438
1439                 public override Expression DoResolve (EmitContext ec)
1440                 {
1441                         eclass = ExprClass.Value;
1442
1443                         return this;
1444                 }
1445                 
1446                 public override void Emit (EmitContext ec)
1447                 {
1448                         //
1449                         // Now emit the delegate creation.
1450                         //
1451                         if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
1452                                 delegate_instance_expression = am.RootScope.GetScopeInitializer (ec);
1453
1454                                 if (delegate_instance_expression == null)
1455                                         throw new InternalErrorException ();
1456                         }
1457
1458                         Expression ml = Expression.MemberLookup (
1459                                 ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
1460                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
1461                                 loc);
1462
1463                         constructor_method = ((MethodGroupExpr) ml).Methods [0];
1464                         delegate_method = am.GetMethodBuilder (ec);
1465                         base.Emit (ec);
1466                 }
1467         }
1468 }