12feb35f3737869ee08cc57fdb8a5406ea276666
[mono.git] / mcs / mcs / flowanalysis.cs
1 //
2 // flowanalyis.cs: The control flow analysis code
3 //
4 // Author:
5 //   Martin Baulig (martin@ximian.com)
6 //
7 // (C) 2001, 2002, 2003 Ximian, Inc.
8 //
9
10 using System;
11 using System.Text;
12 using System.Collections;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Diagnostics;
16
17 namespace Mono.CSharp
18 {
19         public enum TriState : byte {
20                 // Never < Sometimes < Always
21                 Never,
22                 Sometimes,
23                 Always
24         }
25
26         // <summary>
27         //   A new instance of this class is created every time a new block is resolved
28         //   and if there's branching in the block's control flow.
29         // </summary>
30         public abstract class FlowBranching
31         {
32                 // <summary>
33                 //   The type of a FlowBranching.
34                 // </summary>
35                 public enum BranchingType : byte {
36                         // Normal (conditional or toplevel) block.
37                         Block,
38
39                         // Conditional.
40                         Conditional,
41
42                         // A loop block.
43                         Loop,
44
45                         // The statement embedded inside a loop
46                         Embedded,
47
48                         // part of a block headed by a jump target
49                         Labeled,
50
51                         // Try/Catch block.
52                         Exception,
53
54                         // Switch block.
55                         Switch,
56
57                         // Switch section.
58                         SwitchSection,
59
60                         // The toplevel block of a function
61                         Toplevel
62                 }
63
64                 // <summary>
65                 //   The type of one sibling of a branching.
66                 // </summary>
67                 public enum SiblingType : byte {
68                         Block,
69                         Conditional,
70                         SwitchSection,
71                         Try,
72                         Catch,
73                         Finally
74                 }
75
76                 public sealed class Reachability
77                 {
78                         TriState returns, throws, barrier;
79
80                         public TriState Returns {
81                                 get { return returns; }
82                         }
83                         public TriState Throws {
84                                 get { return throws; }
85                         }
86                         public TriState Barrier {
87                                 get { return barrier; }
88                         }
89
90                         Reachability (TriState returns, TriState throws, TriState barrier)
91                         {
92                                 this.returns = returns;
93                                 this.throws = throws;
94                                 this.barrier = barrier;
95                         }
96
97                         public Reachability Clone ()
98                         {
99                                 return new Reachability (returns, throws, barrier);
100                         }
101
102                         public static TriState TriState_Meet (TriState a, TriState b)
103                         {
104                                 // (1) if both are Never, return Never
105                                 // (2) if both are Always, return Always
106                                 // (3) otherwise, return Sometimes
107                                 // note that (3) => (3') if both are Sometimes, return Sometimes
108                                 return a == b ? a : TriState.Sometimes;
109                         }
110
111                         public static TriState TriState_Max (TriState a, TriState b)
112                         {
113                                 return ((byte) a > (byte) b) ? a : b;
114                         }
115
116                         public void Meet (Reachability b)
117                         {
118                                 if ((AlwaysReturns && b.AlwaysHasBarrier) || (AlwaysHasBarrier && b.AlwaysReturns))
119                                         returns = TriState.Always;
120                                 else
121                                         returns = TriState_Meet (returns, b.returns);
122
123                                 throws = TriState_Meet (throws, b.throws);
124                                 barrier = TriState_Meet (barrier, b.barrier);
125                         }
126
127                         public void Or (Reachability b)
128                         {
129                                 returns = TriState_Max (returns, b.returns);
130                                 throws = TriState_Max (throws, b.throws);
131                                 barrier = TriState_Max (barrier, b.barrier);
132                         }
133
134                         public static Reachability Always ()
135                         {
136                                 return new Reachability (TriState.Never, TriState.Never, TriState.Never);
137                         }
138
139                         TriState Unreachable {
140                                 get { return TriState_Max (returns, TriState_Max (throws, barrier)); }
141                         }
142
143                         TriState Reachable {
144                                 get {
145                                         TriState unreachable = Unreachable;
146                                         if (unreachable == TriState.Sometimes)
147                                                 return TriState.Sometimes;
148                                         return unreachable == TriState.Always ? TriState.Never : TriState.Always;
149                                 }
150                         }
151
152                         public bool AlwaysReturns {
153                                 get { return returns == TriState.Always; }
154                         }
155
156                         public bool AlwaysThrows {
157                                 get { return throws == TriState.Always; }
158                         }
159
160                         public bool AlwaysHasBarrier {
161                                 get { return barrier == TriState.Always; }
162                         }
163
164                         public bool IsUnreachable {
165                                 get { return Unreachable == TriState.Always; }
166                         }
167
168                         public void SetReturns ()
169                         {
170                                 returns = TriState.Always;
171                         }
172
173                         public void SetThrows ()
174                         {
175                                 throws = TriState.Always;
176                         }
177
178                         public void SetBarrier ()
179                         {
180                                 barrier = TriState.Always;
181                         }
182
183                         static string ShortName (TriState returns)
184                         {
185                                 switch (returns) {
186                                 case TriState.Never:
187                                         return "N";
188                                 case TriState.Sometimes:
189                                         return "S";
190                                 default:
191                                         return "A";
192                                 }
193                         }
194
195                         public override string ToString ()
196                         {
197                                 return String.Format ("[{0}:{1}:{2}:{3}]",
198                                                       ShortName (returns), ShortName (throws), ShortName (barrier),
199                                                       ShortName (Reachable));
200                         }
201                 }
202
203                 public static FlowBranching CreateBranching (FlowBranching parent, BranchingType type, Block block, Location loc)
204                 {
205                         switch (type) {
206                         case BranchingType.Exception:
207                         case BranchingType.Labeled:
208                         case BranchingType.Toplevel:
209                                 throw new InvalidOperationException ();
210
211                         case BranchingType.Switch:
212                                 return new FlowBranchingBreakable (parent, type, SiblingType.SwitchSection, block, loc);
213
214                         case BranchingType.SwitchSection:
215                                 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
216
217                         case BranchingType.Block:
218                                 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
219
220                         case BranchingType.Loop:
221                                 return new FlowBranchingBreakable (parent, type, SiblingType.Conditional, block, loc);
222
223                         case BranchingType.Embedded:
224                                 return new FlowBranchingContinuable (parent, type, SiblingType.Conditional, block, loc);
225
226                         default:
227                                 return new FlowBranchingBlock (parent, type, SiblingType.Conditional, block, loc);
228                         }
229                 }
230
231                 // <summary>
232                 //   The type of this flow branching.
233                 // </summary>
234                 public readonly BranchingType Type;
235
236                 // <summary>
237                 //   The block this branching is contained in.  This may be null if it's not
238                 //   a top-level block and it doesn't declare any local variables.
239                 // </summary>
240                 public readonly Block Block;
241
242                 // <summary>
243                 //   The parent of this branching or null if this is the top-block.
244                 // </summary>
245                 public readonly FlowBranching Parent;
246
247                 // <summary>
248                 //   Start-Location of this flow branching.
249                 // </summary>
250                 public readonly Location Location;
251
252                 protected VariableMap param_map, local_map;
253
254                 static int next_id = 0;
255                 int id;
256
257                 // <summary>
258                 //   The vector contains a BitArray with information about which local variables
259                 //   and parameters are already initialized at the current code position.
260                 // </summary>
261                 public class UsageVector {
262                         // <summary>
263                         //   The type of this branching.
264                         // </summary>
265                         public readonly SiblingType Type;
266
267                         // <summary>
268                         //   Start location of this branching.
269                         // </summary>
270                         public Location Location;
271
272                         // <summary>
273                         //   This is only valid for SwitchSection, Try, Catch and Finally.
274                         // </summary>
275                         public readonly Block Block;
276
277                         // <summary>
278                         //   The number of parameters in this block.
279                         // </summary>
280                         public readonly int CountParameters;
281
282                         // <summary>
283                         //   The number of locals in this block.
284                         // </summary>
285                         public readonly int CountLocals;
286
287                         // <summary>
288                         //   If not null, then we inherit our state from this vector and do a
289                         //   copy-on-write.  If null, then we're the first sibling in a top-level
290                         //   block and inherit from the empty vector.
291                         // </summary>
292                         public readonly UsageVector InheritsFrom;
293
294                         // <summary>
295                         //   This is used to construct a list of UsageVector's.
296                         // </summary>
297                         public UsageVector Next;
298
299                         //
300                         // Private.
301                         //
302                         MyBitVector locals, parameters;
303                         Reachability reachability;
304
305                         static int next_id = 0;
306                         int id;
307
308                         //
309                         // Normally, you should not use any of these constructors.
310                         //
311                         public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc, int num_params, int num_locals)
312                         {
313                                 this.Type = type;
314                                 this.Block = block;
315                                 this.Location = loc;
316                                 this.InheritsFrom = parent;
317                                 this.CountParameters = num_params;
318                                 this.CountLocals = num_locals;
319
320                                 locals = num_locals == 0 
321                                         ? MyBitVector.Empty
322                                         : new MyBitVector (parent == null ? MyBitVector.Empty : parent.locals, num_locals);
323
324                                 parameters = num_params == 0
325                                         ? MyBitVector.Empty
326                                         : new MyBitVector (parent == null ? MyBitVector.Empty : parent.parameters, num_params);
327
328                                 reachability = parent == null ? Reachability.Always () : parent.Reachability.Clone ();
329
330                                 id = ++next_id;
331                         }
332
333                         public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc)
334                                 : this (type, parent, block, loc, parent.CountParameters, parent.CountLocals)
335                         { }
336
337                         public UsageVector (MyBitVector parameters, MyBitVector locals, Reachability reachability, Block block, Location loc)
338                         {
339                                 this.Type = SiblingType.Block;
340                                 this.Location = loc;
341                                 this.Block = block;
342
343                                 this.reachability = reachability;
344                                 this.parameters = parameters;
345                                 this.locals = locals;
346
347                                 id = ++next_id;
348                         }
349
350                         // <summary>
351                         //   This does a deep copy of the usage vector.
352                         // </summary>
353                         public UsageVector Clone ()
354                         {
355                                 UsageVector retval = new UsageVector (Type, null, Block, Location, CountParameters, CountLocals);
356
357                                 retval.locals = locals.Clone ();
358                                 retval.parameters = parameters.Clone ();
359                                 retval.reachability = reachability.Clone ();
360
361                                 return retval;
362                         }
363
364                         public bool IsAssigned (VariableInfo var, bool ignoreReachability)
365                         {
366                                 if (!ignoreReachability && !var.IsParameter && Reachability.IsUnreachable)
367                                         return true;
368
369                                 return var.IsAssigned (var.IsParameter ? parameters : locals);
370                         }
371
372                         public void SetAssigned (VariableInfo var)
373                         {
374                                 if (!var.IsParameter && Reachability.IsUnreachable)
375                                         return;
376
377                                 var.SetAssigned (var.IsParameter ? parameters : locals);
378                         }
379
380                         public bool IsFieldAssigned (VariableInfo var, string name)
381                         {
382                                 if (!var.IsParameter && Reachability.IsUnreachable)
383                                         return true;
384
385                                 return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name);
386                         }
387
388                         public void SetFieldAssigned (VariableInfo var, string name)
389                         {
390                                 if (!var.IsParameter && Reachability.IsUnreachable)
391                                         return;
392
393                                 var.SetFieldAssigned (var.IsParameter ? parameters : locals, name);
394                         }
395
396                         public Reachability Reachability {
397                                 get { return reachability; }
398                         }
399
400                         public void Return ()
401                         {
402                                 if (!reachability.IsUnreachable)
403                                         reachability.SetReturns ();
404                         }
405
406                         public void Throw ()
407                         {
408                                 if (!reachability.IsUnreachable) {
409                                         reachability.SetThrows ();
410                                         reachability.SetBarrier ();
411                                 }
412                         }
413
414                         public void Goto ()
415                         {
416                                 if (!reachability.IsUnreachable)
417                                         reachability.SetBarrier ();
418                         }
419
420                         public static UsageVector MergeSiblings (UsageVector sibling_list, Location loc)
421                         {
422                                 if (sibling_list.Next == null)
423                                         return sibling_list;
424
425                                 MyBitVector locals = null;
426                                 MyBitVector parameters = null;
427                                 Reachability reachability = null;
428
429                                 for (UsageVector child = sibling_list; child != null; child = child.Next) {
430                                         Report.Debug (2, "    MERGING SIBLING   ", reachability, child);
431
432                                         if (reachability == null)
433                                                 reachability = child.Reachability.Clone ();
434                                         else
435                                                 reachability.Meet (child.Reachability);
436
437                                         // A local variable is initialized after a flow branching if it
438                                         // has been initialized in all its branches which do neither
439                                         // always return or always throw an exception.
440                                         //
441                                         // If a branch may return, but does not always return, then we
442                                         // can treat it like a never-returning branch here: control will
443                                         // only reach the code position after the branching if we did not
444                                         // return here.
445                                         //
446                                         // It's important to distinguish between always and sometimes
447                                         // returning branches here:
448                                         //
449                                         //    1   int a;
450                                         //    2   if (something) {
451                                         //    3      return;
452                                         //    4      a = 5;
453                                         //    5   }
454                                         //    6   Console.WriteLine (a);
455                                         //
456                                         // The if block in lines 3-4 always returns, so we must not look
457                                         // at the initialization of `a' in line 4 - thus it'll still be
458                                         // uninitialized in line 6.
459                                         //
460                                         // On the other hand, the following is allowed:
461                                         //
462                                         //    1   int a;
463                                         //    2   if (something)
464                                         //    3      a = 5;
465                                         //    4   else
466                                         //    5      return;
467                                         //    6   Console.WriteLine (a);
468                                         //
469                                         // Here, `a' is initialized in line 3 and we must not look at
470                                         // line 5 since it always returns.
471                                         // 
472                                         bool unreachable = child.Reachability.IsUnreachable;
473
474                                         Report.Debug (2, "    MERGING SIBLING #1", reachability,
475                                                       child.Type, child.Reachability.IsUnreachable, unreachable);
476
477                                         if (!unreachable)
478                                                 MyBitVector.And (ref locals, child.locals);
479
480                                         // An `out' parameter must be assigned in all branches which do
481                                         // not always throw an exception.
482                                         if (!child.Reachability.AlwaysThrows)
483                                                 MyBitVector.And (ref parameters, child.parameters);
484
485                                         Report.Debug (2, "    MERGING SIBLING #2", parameters, locals);
486                                 }
487                                 
488                                 if (reachability == null)
489                                         throw new InternalErrorException ("Cannot happen: the loop above runs at least twice");
490
491                                 return new UsageVector (parameters, locals, reachability, null, loc);
492                         }
493
494                         // <summary>
495                         //   Merges a child branching.
496                         // </summary>
497                         public UsageVector MergeChild (UsageVector child, bool overwrite)
498                         {
499                                 Report.Debug (2, "    MERGING CHILD EFFECTS", this, child, reachability, Type);
500
501                                 Reachability new_r = child.Reachability;
502
503                                 //
504                                 // We've now either reached the point after the branching or we will
505                                 // never get there since we always return or always throw an exception.
506                                 //
507                                 // If we can reach the point after the branching, mark all locals and
508                                 // parameters as initialized which have been initialized in all branches
509                                 // we need to look at (see above).
510                                 //
511
512                                 if ((Type == SiblingType.SwitchSection) && !new_r.IsUnreachable) {
513                                         Report.Error (163, Location,
514                                                       "Control cannot fall through from one " +
515                                                       "case label to another");
516                                         return child;
517                                 }
518
519                                 MyBitVector.Or (ref locals, child.locals);
520                                 MyBitVector.Or (ref parameters, child.parameters);
521
522                                 if (overwrite)
523                                         reachability = new_r.Clone ();
524                                 else
525                                         reachability.Or (new_r);
526
527                                 return child;
528                         }
529
530                         public void MergeOrigins (UsageVector o_vectors)
531                         {
532                                 Report.Debug (1, "  MERGING BREAK ORIGINS", this);
533
534                                 if (o_vectors == null)
535                                         return;
536
537                                 if (reachability.IsUnreachable) {
538                                         if (locals != null)
539                                                 locals.SetAll (true);
540                                         if (parameters != null)
541                                                 parameters.SetAll (true);
542                                 }
543
544                                 for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) {
545                                         Report.Debug (1, "    MERGING BREAK ORIGIN", vector);
546                                         MyBitVector.And (ref locals, vector.locals);
547                                         MyBitVector.And (ref parameters, vector.parameters);
548                                         reachability.Meet (vector.Reachability);
549                                 }
550
551                                 Report.Debug (1, "  MERGING BREAK ORIGINS DONE", this);
552                         }
553
554                         //
555                         // Debugging stuff.
556                         //
557
558                         public override string ToString ()
559                         {
560                                 return String.Format ("Vector ({0},{1},{2}-{3}-{4})", Type, id, reachability, parameters, locals);
561                         }
562                 }
563
564                 // <summary>
565                 //   Creates a new flow branching which is contained in `parent'.
566                 //   You should only pass non-null for the `block' argument if this block
567                 //   introduces any new variables - in this case, we need to create a new
568                 //   usage vector with a different size than our parent's one.
569                 // </summary>
570                 protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype,
571                                          Block block, Location loc)
572                 {
573                         Parent = parent;
574                         Block = block;
575                         Location = loc;
576                         Type = type;
577                         id = ++next_id;
578
579                         UsageVector vector;
580                         if (Block != null) {
581                                 param_map = Block.ParameterMap;
582                                 local_map = Block.LocalMap;
583
584                                 UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
585                                 vector = new UsageVector (
586                                         stype, parent_vector, Block, loc,
587                                         param_map.Length, local_map.Length);
588                         } else {
589                                 param_map = Parent.param_map;
590                                 local_map = Parent.local_map;
591                                 vector = new UsageVector (
592                                         stype, Parent.CurrentUsageVector, null, loc);
593                         }
594
595                         AddSibling (vector);
596                 }
597
598                 public abstract UsageVector CurrentUsageVector {
599                         get;
600                 }                               
601
602                 // <summary>
603                 //   Creates a sibling of the current usage vector.
604                 // </summary>
605                 public virtual void CreateSibling (Block block, SiblingType type)
606                 {
607                         UsageVector vector = new UsageVector (
608                                 type, Parent.CurrentUsageVector, block, Location);
609                         AddSibling (vector);
610
611                         Report.Debug (1, "  CREATED SIBLING", CurrentUsageVector);
612                 }
613
614                 public void CreateSibling ()
615                 {
616                         CreateSibling (null, SiblingType.Conditional);
617                 }
618
619                 protected abstract void AddSibling (UsageVector uv);
620
621                 protected abstract UsageVector Merge ();
622
623                 // <summary>
624                 //   Merge a child branching.
625                 // </summary>
626                 public UsageVector MergeChild (FlowBranching child)
627                 {
628                         bool overwrite = child.Type == BranchingType.Labeled ||
629                                 (child.Type == BranchingType.Block && child.Block.Implicit);
630                         Report.Debug (2, "  MERGING CHILD", this, child);
631                         UsageVector result = CurrentUsageVector.MergeChild (child.Merge (), overwrite);
632                         Report.Debug (2, "  MERGING CHILD DONE", this, result);
633                         return result;
634                 }
635
636                 public virtual bool InTryWithCatch ()
637                 {
638                         return Parent.InTryWithCatch ();
639                 }
640
641                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
642                 public virtual bool AddBreakOrigin (UsageVector vector, Location loc)
643                 {
644                         return Parent.AddBreakOrigin (vector, loc);
645                 }
646
647                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
648                 public virtual bool AddContinueOrigin (UsageVector vector, Location loc)
649                 {
650                         return Parent.AddContinueOrigin (vector, loc);
651                 }
652
653                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
654                 public virtual bool AddReturnOrigin (UsageVector vector, Location loc)
655                 {
656                         return Parent.AddReturnOrigin (vector, loc);
657                 }
658
659                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
660                 public virtual bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
661                 {
662                         return Parent.AddGotoOrigin (vector, goto_stmt);
663                 }
664
665                 public virtual void StealFinallyClauses (ref ArrayList list)
666                 {
667                         Parent.StealFinallyClauses (ref list);
668                 }
669
670                 public bool IsAssigned (VariableInfo vi)
671                 {
672                         return CurrentUsageVector.IsAssigned (vi, false);
673                 }
674
675                 public bool IsFieldAssigned (VariableInfo vi, string field_name)
676                 {
677                         return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name);
678                 }
679
680                 public void SetAssigned (VariableInfo vi)
681                 {
682                         CurrentUsageVector.SetAssigned (vi);
683                 }
684
685                 public void SetFieldAssigned (VariableInfo vi, string name)
686                 {
687                         CurrentUsageVector.SetFieldAssigned (vi, name);
688                 }
689
690                 public override string ToString ()
691                 {
692                         StringBuilder sb = new StringBuilder ();
693                         sb.Append (GetType ());
694                         sb.Append (" (");
695
696                         sb.Append (id);
697                         sb.Append (",");
698                         sb.Append (Type);
699                         if (Block != null) {
700                                 sb.Append (" - ");
701                                 sb.Append (Block.ID);
702                                 sb.Append (" - ");
703                                 sb.Append (Block.StartLocation);
704                         }
705                         sb.Append (" - ");
706                         // sb.Append (Siblings.Length);
707                         // sb.Append (" - ");
708                         sb.Append (CurrentUsageVector);
709                         sb.Append (")");
710                         return sb.ToString ();
711                 }
712
713                 public string Name {
714                         get { return String.Format ("{0} ({1}:{2}:{3})", GetType (), id, Type, Location); }
715                 }
716         }
717
718         public class FlowBranchingBlock : FlowBranching
719         {
720                 UsageVector sibling_list = null;
721
722                 public FlowBranchingBlock (FlowBranching parent, BranchingType type,
723                                            SiblingType stype, Block block, Location loc)
724                         : base (parent, type, stype, block, loc)
725                 { }
726
727                 public override UsageVector CurrentUsageVector {
728                         get { return sibling_list; }
729                 }
730
731                 protected override void AddSibling (UsageVector sibling)
732                 {
733                         sibling.Next = sibling_list;
734                         sibling_list = sibling;
735                 }
736
737                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
738                 {
739                         LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
740                         if (stmt == null)
741                                 return Parent.AddGotoOrigin (vector, goto_stmt);
742
743                         // forward jump
744                         goto_stmt.SetResolvedTarget (stmt);
745                         stmt.AddUsageVector (vector);
746                         return false;
747                 }
748
749                 protected override UsageVector Merge ()
750                 {
751                         Report.Debug (2, "  MERGING SIBLINGS", Name);
752                         UsageVector vector = UsageVector.MergeSiblings (sibling_list, Location);
753                         Report.Debug (2, "  MERGING SIBLINGS DONE", Name, vector);
754                         return vector;
755                 }
756         }
757
758         public class FlowBranchingBreakable : FlowBranchingBlock
759         {
760                 UsageVector break_origins;
761
762                 public FlowBranchingBreakable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
763                         : base (parent, type, stype, block, loc)
764                 { }
765
766                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
767                 {
768                         vector = vector.Clone ();
769                         vector.Next = break_origins;
770                         break_origins = vector;
771                         return false;
772                 }
773
774                 protected override UsageVector Merge ()
775                 {
776                         UsageVector vector = base.Merge ();
777                         vector.MergeOrigins (break_origins);
778                         return vector;
779                 }
780         }
781
782         public class FlowBranchingContinuable : FlowBranchingBlock
783         {
784                 UsageVector continue_origins;
785
786                 public FlowBranchingContinuable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
787                         : base (parent, type, stype, block, loc)
788                 { }
789
790                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
791                 {
792                         vector = vector.Clone ();
793                         vector.Next = continue_origins;
794                         continue_origins = vector;
795                         return false;
796                 }
797
798                 protected override UsageVector Merge ()
799                 {
800                         UsageVector vector = base.Merge ();
801                         vector.MergeOrigins (continue_origins);
802                         return vector;
803                 }
804         }
805
806         public class FlowBranchingLabeled : FlowBranchingBlock
807         {
808                 LabeledStatement stmt;
809                 UsageVector actual;
810
811                 public FlowBranchingLabeled (FlowBranching parent, LabeledStatement stmt)
812                         : base (parent, BranchingType.Labeled, SiblingType.Conditional, null, stmt.loc)
813                 {
814                         this.stmt = stmt;
815                         CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
816                         actual = CurrentUsageVector.Clone ();
817
818                         // stand-in for backward jumps
819                         CurrentUsageVector.Reachability.Meet (Reachability.Always ());
820                 }
821
822                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
823                 {
824                         if (goto_stmt.Target != stmt.Name)
825                                 return Parent.AddGotoOrigin (vector, goto_stmt);
826
827                         // backward jump
828                         goto_stmt.SetResolvedTarget (stmt);
829                         actual.MergeOrigins (vector.Clone ());
830
831                         return false;
832                 }
833
834                 protected override UsageVector Merge ()
835                 {
836                         UsageVector vector = base.Merge ();
837
838                         if (actual.Reachability.IsUnreachable)
839                                 Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
840
841                         actual.MergeChild (vector, false);
842                         return actual;
843                 }
844         }
845
846         public class FlowBranchingToplevel : FlowBranchingBlock
847         {
848                 public FlowBranchingToplevel (FlowBranching parent, ToplevelBlock stmt)
849                         : base (parent, BranchingType.Toplevel, SiblingType.Conditional, stmt, stmt.loc)
850                 {
851                 }
852
853                 // <summary>
854                 //   Check whether all `out' parameters have been assigned.
855                 // </summary>
856                 void CheckOutParameters (UsageVector vector, Location loc)
857                 {
858                         for (int i = 0; i < param_map.Count; i++) {
859                                 VariableInfo var = param_map [i];
860
861                                 if (var == null)
862                                         continue;
863
864                                 if (vector.IsAssigned (var, false))
865                                         continue;
866
867                                 Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
868                                         var.Name);
869                         }
870                 }
871
872                 public override bool InTryWithCatch ()
873                 {
874                         return false;
875                 }
876
877                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
878                 {
879                         Report.Error (139, loc, "No enclosing loop out of which to break or continue");
880                         return false;
881                 }
882
883                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
884                 {
885                         Report.Error (139, loc, "No enclosing loop out of which to break or continue");
886                         return false;
887                 }
888
889                 public override bool AddReturnOrigin (UsageVector vector, Location loc)
890                 {
891                         CheckOutParameters (vector, loc);
892                         return false;
893                 }
894
895                 public override void StealFinallyClauses (ref ArrayList list)
896                 {
897                         // nothing to do
898                 }
899
900                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
901                 {
902                         string name = goto_stmt.Target;
903                         LabeledStatement s = Block.LookupLabel (name);
904                         if (s != null)
905                                 throw new InternalErrorException ("Shouldn't get here");
906
907                         if (Parent == null) {
908                                 Report.Error (159, goto_stmt.loc, "No such label `{0}' in this scope", name);
909                                 return false;
910                         }
911
912                         int errors = Report.Errors;
913                         Parent.AddGotoOrigin (vector, goto_stmt);
914                         if (errors == Report.Errors)
915                                 Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
916                         return false;
917                 }
918
919                 public Reachability End ()
920                 {
921                         UsageVector result = Merge ();
922
923                         Report.Debug (4, "MERGE TOP BLOCK", Location, result);
924
925                         if (!result.Reachability.AlwaysThrows && !result.Reachability.AlwaysHasBarrier)
926                                 CheckOutParameters (result, Location);
927
928                         return result.Reachability;
929                 }
930         }
931
932         public class FlowBranchingException : FlowBranching
933         {
934                 ExceptionStatement stmt;
935                 UsageVector current_vector;
936                 UsageVector catch_vectors;
937                 UsageVector finally_vector;
938
939                 UsageVector break_origins;
940                 UsageVector continue_origins;
941                 UsageVector return_origins;
942                 GotoOrigin goto_origins;
943
944                 class GotoOrigin {
945                         public GotoOrigin Next;
946                         public Goto GotoStmt;
947                         public UsageVector Vector;
948
949                         public GotoOrigin (UsageVector vector, Goto goto_stmt, GotoOrigin next)
950                         {
951                                 Vector = vector;
952                                 GotoStmt = goto_stmt;
953                                 Next = next;
954                         }
955                 }
956
957                 bool emit_finally;
958
959                 public FlowBranchingException (FlowBranching parent,
960                                                ExceptionStatement stmt)
961                         : base (parent, BranchingType.Exception, SiblingType.Try,
962                                 null, stmt.loc)
963                 {
964                         this.stmt = stmt;
965                         this.emit_finally = true;
966                 }
967
968                 protected override void AddSibling (UsageVector sibling)
969                 {
970                         switch (sibling.Type) {
971                         case SiblingType.Try:
972                         case SiblingType.Catch:
973                                 sibling.Next = catch_vectors;
974                                 catch_vectors = sibling;
975                                 break;
976                         case SiblingType.Finally:
977                                 finally_vector = sibling;
978                                 break;
979                         default:
980                                 throw new InvalidOperationException ();
981                         }
982                         current_vector = sibling;
983                 }
984
985                 public override UsageVector CurrentUsageVector {
986                         get { return current_vector; }
987                 }
988
989                 public override bool InTryWithCatch ()
990                 {
991                         if (finally_vector == null) {
992                                 Try t = stmt as Try;
993                                 if (t != null && t.HasCatch)
994                                         return true;
995                         }
996
997                         return base.InTryWithCatch ();
998                 }
999
1000                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
1001                 {
1002                         if (finally_vector != null) {
1003                                 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
1004                         } else {
1005                                 vector = vector.Clone ();
1006                                 vector.Location = loc;
1007                                 vector.Next = break_origins;
1008                                 break_origins = vector;
1009                         }
1010                         return true;
1011                 }
1012
1013                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
1014                 {
1015                         if (finally_vector != null) {
1016                                 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
1017                         } else {
1018                                 vector = vector.Clone ();
1019                                 vector.Location = loc;
1020                                 vector.Next = continue_origins;
1021                                 continue_origins = vector;
1022                         }
1023                         return true;
1024                 }
1025
1026                 public override bool AddReturnOrigin (UsageVector vector, Location loc)
1027                 {
1028                         if (finally_vector != null) {
1029                                 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
1030                         } else {
1031                                 vector = vector.Clone ();
1032                                 vector.Location = loc;
1033                                 vector.Next = return_origins;
1034                                 return_origins = vector;
1035                         }
1036                         return true;
1037                 }
1038
1039                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
1040                 {
1041                         LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
1042                         if (s != null)
1043                                 throw new InternalErrorException ("Shouldn't get here");
1044
1045                         if (finally_vector != null)
1046                                 Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
1047                         else
1048                                 goto_origins = new GotoOrigin (vector.Clone (), goto_stmt, goto_origins);
1049                         return true;
1050                 }
1051
1052                 public override void StealFinallyClauses (ref ArrayList list)
1053                 {
1054                         if (list == null)
1055                                 list = new ArrayList ();
1056                         list.Add (stmt);
1057                         emit_finally = false;
1058                         base.StealFinallyClauses (ref list);
1059                 }
1060
1061                 public bool EmitFinally {
1062                         get { return emit_finally; }
1063                 }
1064
1065                 protected override UsageVector Merge ()
1066                 {
1067                         Report.Debug (2, "  MERGING TRY/CATCH", Name);
1068                         UsageVector vector = UsageVector.MergeSiblings (catch_vectors, Location);
1069                         Report.Debug (2, "  MERGING TRY/CATCH DONE", vector);
1070
1071                         if (finally_vector != null)
1072                                 vector.MergeChild (finally_vector, false);
1073
1074                         for (UsageVector origin = break_origins; origin != null; origin = origin.Next) {
1075                                 if (finally_vector != null)
1076                                         origin.MergeChild (finally_vector, false);
1077                                 if (!origin.Reachability.IsUnreachable)
1078                                         Parent.AddBreakOrigin (origin, origin.Location);
1079                         }
1080
1081                         for (UsageVector origin = continue_origins; origin != null; origin = origin.Next) {
1082                                 if (finally_vector != null)
1083                                         origin.MergeChild (finally_vector, false);
1084                                 if (!origin.Reachability.IsUnreachable)
1085                                         Parent.AddContinueOrigin (origin, origin.Location);
1086                         }
1087
1088                         for (UsageVector origin = return_origins; origin != null; origin = origin.Next) {
1089                                 if (finally_vector != null)
1090                                         origin.MergeChild (finally_vector, false);
1091                                 if (!origin.Reachability.IsUnreachable)
1092                                         Parent.AddReturnOrigin (origin, origin.Location);
1093                         }
1094
1095                         for (GotoOrigin origin = goto_origins; origin != null; origin = origin.Next) {
1096                                 if (finally_vector != null)
1097                                         origin.Vector.MergeChild (finally_vector, false);
1098                                 if (!origin.Vector.Reachability.IsUnreachable)
1099                                         Parent.AddGotoOrigin (origin.Vector, origin.GotoStmt);
1100                         }
1101
1102                         return vector;
1103                 }
1104         }
1105
1106         // <summary>
1107         //   This is used by the flow analysis code to keep track of the type of local variables
1108         //   and variables.
1109         //
1110         //   The flow code uses a BitVector to keep track of whether a variable has been assigned
1111         //   or not.  This is easy for fundamental types (int, char etc.) or reference types since
1112         //   you can only assign the whole variable as such.
1113         //
1114         //   For structs, we also need to keep track of all its fields.  To do this, we allocate one
1115         //   bit for the struct itself (it's used if you assign/access the whole struct) followed by
1116         //   one bit for each of its fields.
1117         //
1118         //   This class computes this `layout' for each type.
1119         // </summary>
1120         public class TypeInfo
1121         {
1122                 public readonly Type Type;
1123
1124                 // <summary>
1125                 //   Total number of bits a variable of this type consumes in the flow vector.
1126                 // </summary>
1127                 public readonly int TotalLength;
1128
1129                 // <summary>
1130                 //   Number of bits the simple fields of a variable of this type consume
1131                 //   in the flow vector.
1132                 // </summary>
1133                 public readonly int Length;
1134
1135                 // <summary>
1136                 //   This is only used by sub-structs.
1137                 // </summary>
1138                 public readonly int Offset;
1139
1140                 // <summary>
1141                 //   If this is a struct.
1142                 // </summary>
1143                 public readonly bool IsStruct;       
1144
1145                 // <summary>
1146                 //   If this is a struct, all fields which are structs theirselves.
1147                 // </summary>
1148                 public TypeInfo[] SubStructInfo;
1149
1150                 protected readonly StructInfo struct_info;
1151                 private static Hashtable type_hash = new Hashtable ();
1152
1153                 public static TypeInfo GetTypeInfo (Type type)
1154                 {
1155                         TypeInfo info = (TypeInfo) type_hash [type];
1156                         if (info != null)
1157                                 return info;
1158
1159                         info = new TypeInfo (type);
1160                         type_hash.Add (type, info);
1161                         return info;
1162                 }
1163
1164                 public static TypeInfo GetTypeInfo (TypeContainer tc)
1165                 {
1166                         TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
1167                         if (info != null)
1168                                 return info;
1169
1170                         info = new TypeInfo (tc);
1171                         type_hash.Add (tc.TypeBuilder, info);
1172                         return info;
1173                 }
1174
1175                 private TypeInfo (Type type)
1176                 {
1177                         this.Type = type;
1178
1179                         struct_info = StructInfo.GetStructInfo (type);
1180                         if (struct_info != null) {
1181                                 Length = struct_info.Length;
1182                                 TotalLength = struct_info.TotalLength;
1183                                 SubStructInfo = struct_info.StructFields;
1184                                 IsStruct = true;
1185                         } else {
1186                                 Length = 0;
1187                                 TotalLength = 1;
1188                                 IsStruct = false;
1189                         }
1190                 }
1191
1192                 private TypeInfo (TypeContainer tc)
1193                 {
1194                         this.Type = tc.TypeBuilder;
1195
1196                         struct_info = StructInfo.GetStructInfo (tc);
1197                         if (struct_info != null) {
1198                                 Length = struct_info.Length;
1199                                 TotalLength = struct_info.TotalLength;
1200                                 SubStructInfo = struct_info.StructFields;
1201                                 IsStruct = true;
1202                         } else {
1203                                 Length = 0;
1204                                 TotalLength = 1;
1205                                 IsStruct = false;
1206                         }
1207                 }
1208
1209                 protected TypeInfo (StructInfo struct_info, int offset)
1210                 {
1211                         this.struct_info = struct_info;
1212                         this.Offset = offset;
1213                         this.Length = struct_info.Length;
1214                         this.TotalLength = struct_info.TotalLength;
1215                         this.SubStructInfo = struct_info.StructFields;
1216                         this.Type = struct_info.Type;
1217                         this.IsStruct = true;
1218                 }
1219
1220                 public int GetFieldIndex (string name)
1221                 {
1222                         if (struct_info == null)
1223                                 return 0;
1224
1225                         return struct_info [name];
1226                 }
1227
1228                 public TypeInfo GetSubStruct (string name)
1229                 {
1230                         if (struct_info == null)
1231                                 return null;
1232
1233                         return struct_info.GetStructField (name);
1234                 }
1235
1236                 // <summary>
1237                 //   A struct's constructor must always assign all fields.
1238                 //   This method checks whether it actually does so.
1239                 // </summary>
1240                 public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
1241                 {
1242                         if (struct_info == null)
1243                                 return true;
1244
1245                         bool ok = true;
1246                         for (int i = 0; i < struct_info.Count; i++) {
1247                                 FieldInfo field = struct_info.Fields [i];
1248
1249                                 if (!branching.IsFieldAssigned (vi, field.Name)) {
1250                                         Report.Error (171, loc,
1251                                                 "Field `{0}' must be fully assigned before control leaves the constructor",
1252                                                 TypeManager.GetFullNameSignature (field));
1253                                         ok = false;
1254                                 }
1255                         }
1256
1257                         return ok;
1258                 }
1259
1260                 public override string ToString ()
1261                 {
1262                         return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
1263                                               Type, Offset, Length, TotalLength);
1264                 }
1265
1266                 protected class StructInfo {
1267                         public readonly Type Type;
1268                         public readonly FieldInfo[] Fields;
1269                         public readonly TypeInfo[] StructFields;
1270                         public readonly int Count;
1271                         public readonly int CountPublic;
1272                         public readonly int CountNonPublic;
1273                         public readonly int Length;
1274                         public readonly int TotalLength;
1275                         public readonly bool HasStructFields;
1276
1277                         private static Hashtable field_type_hash = new Hashtable ();
1278                         private Hashtable struct_field_hash;
1279                         private Hashtable field_hash;
1280
1281                         protected bool InTransit = false;
1282
1283                         // Private constructor.  To save memory usage, we only need to create one instance
1284                         // of this class per struct type.
1285                         private StructInfo (Type type)
1286                         {
1287                                 this.Type = type;
1288
1289                                 field_type_hash.Add (type, this);
1290
1291                                 if (type is TypeBuilder) {
1292                                         TypeContainer tc = TypeManager.LookupTypeContainer (type);
1293
1294                                         ArrayList fields = null;
1295                                         if (tc != null)
1296                                                 fields = tc.Fields;
1297
1298                                         ArrayList public_fields = new ArrayList ();
1299                                         ArrayList non_public_fields = new ArrayList ();
1300
1301                                         if (fields != null) {
1302                                                 foreach (FieldMember field in fields) {
1303                                                         if ((field.ModFlags & Modifiers.STATIC) != 0)
1304                                                                 continue;
1305                                                         if ((field.ModFlags & Modifiers.PUBLIC) != 0)
1306                                                                 public_fields.Add (field.FieldBuilder);
1307                                                         else
1308                                                                 non_public_fields.Add (field.FieldBuilder);
1309                                                 }
1310                                         }
1311
1312                                         CountPublic = public_fields.Count;
1313                                         CountNonPublic = non_public_fields.Count;
1314                                         Count = CountPublic + CountNonPublic;
1315
1316                                         Fields = new FieldInfo [Count];
1317                                         public_fields.CopyTo (Fields, 0);
1318                                         non_public_fields.CopyTo (Fields, CountPublic);
1319                                 } else {
1320                                         FieldInfo[] public_fields = type.GetFields (
1321                                                 BindingFlags.Instance|BindingFlags.Public);
1322                                         FieldInfo[] non_public_fields = type.GetFields (
1323                                                 BindingFlags.Instance|BindingFlags.NonPublic);
1324
1325                                         CountPublic = public_fields.Length;
1326                                         CountNonPublic = non_public_fields.Length;
1327                                         Count = CountPublic + CountNonPublic;
1328
1329                                         Fields = new FieldInfo [Count];
1330                                         public_fields.CopyTo (Fields, 0);
1331                                         non_public_fields.CopyTo (Fields, CountPublic);
1332                                 }
1333
1334                                 struct_field_hash = new Hashtable ();
1335                                 field_hash = new Hashtable ();
1336
1337                                 Length = 0;
1338                                 StructFields = new TypeInfo [Count];
1339                                 StructInfo[] sinfo = new StructInfo [Count];
1340
1341                                 InTransit = true;
1342
1343                                 for (int i = 0; i < Count; i++) {
1344                                         FieldInfo field = (FieldInfo) Fields [i];
1345
1346                                         sinfo [i] = GetStructInfo (field.FieldType);
1347                                         if (sinfo [i] == null)
1348                                                 field_hash.Add (field.Name, ++Length);
1349                                         else if (sinfo [i].InTransit) {
1350                                                 Report.Error (523, String.Format (
1351                                                                       "Struct member `{0}.{1}' of type `{2}' causes " +
1352                                                                       "a cycle in the structure layout",
1353                                                                       type, field.Name, sinfo [i].Type));
1354                                                 sinfo [i] = null;
1355                                                 return;
1356                                         }
1357                                 }
1358
1359                                 InTransit = false;
1360
1361                                 TotalLength = Length + 1;
1362                                 for (int i = 0; i < Count; i++) {
1363                                         FieldInfo field = (FieldInfo) Fields [i];
1364
1365                                         if (sinfo [i] == null)
1366                                                 continue;
1367
1368                                         field_hash.Add (field.Name, TotalLength);
1369
1370                                         HasStructFields = true;
1371                                         StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1372                                         struct_field_hash.Add (field.Name, StructFields [i]);
1373                                         TotalLength += sinfo [i].TotalLength;
1374                                 }
1375                         }
1376
1377                         public int this [string name] {
1378                                 get {
1379                                         if (field_hash.Contains (name))
1380                                                 return (int) field_hash [name];
1381                                         else
1382                                                 return 0;
1383                                 }
1384                         }
1385
1386                         public TypeInfo GetStructField (string name)
1387                         {
1388                                 return (TypeInfo) struct_field_hash [name];
1389                         }
1390
1391                         public static StructInfo GetStructInfo (Type type)
1392                         {
1393                                 if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
1394                                     TypeManager.IsBuiltinType (type))
1395                                         return null;
1396
1397                                 StructInfo info = (StructInfo) field_type_hash [type];
1398                                 if (info != null)
1399                                         return info;
1400
1401                                 return new StructInfo (type);
1402                         }
1403
1404                         public static StructInfo GetStructInfo (TypeContainer tc)
1405                         {
1406                                 StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
1407                                 if (info != null)
1408                                         return info;
1409
1410                                 return new StructInfo (tc.TypeBuilder);
1411                         }
1412                 }
1413         }
1414
1415         // <summary>
1416         //   This is used by the flow analysis code to store information about a single local variable
1417         //   or parameter.  Depending on the variable's type, we need to allocate one or more elements
1418         //   in the BitVector - if it's a fundamental or reference type, we just need to know whether
1419         //   it has been assigned or not, but for structs, we need this information for each of its fields.
1420         // </summary>
1421         public class VariableInfo {
1422                 public readonly string Name;
1423                 public readonly TypeInfo TypeInfo;
1424
1425                 // <summary>
1426                 //   The bit offset of this variable in the flow vector.
1427                 // </summary>
1428                 public readonly int Offset;
1429
1430                 // <summary>
1431                 //   The number of bits this variable needs in the flow vector.
1432                 //   The first bit always specifies whether the variable as such has been assigned while
1433                 //   the remaining bits contain this information for each of a struct's fields.
1434                 // </summary>
1435                 public readonly int Length;
1436
1437                 // <summary>
1438                 //   If this is a parameter of local variable.
1439                 // </summary>
1440                 public readonly bool IsParameter;
1441
1442                 public readonly LocalInfo LocalInfo;
1443                 public readonly int ParameterIndex;
1444
1445                 readonly VariableInfo Parent;
1446                 VariableInfo[] sub_info;
1447
1448                 protected VariableInfo (string name, Type type, int offset)
1449                 {
1450                         this.Name = name;
1451                         this.Offset = offset;
1452                         this.TypeInfo = TypeInfo.GetTypeInfo (type);
1453
1454                         Length = TypeInfo.TotalLength;
1455
1456                         Initialize ();
1457                 }
1458
1459                 protected VariableInfo (VariableInfo parent, TypeInfo type)
1460                 {
1461                         this.Name = parent.Name;
1462                         this.TypeInfo = type;
1463                         this.Offset = parent.Offset + type.Offset;
1464                         this.Parent = parent;
1465                         this.Length = type.TotalLength;
1466
1467                         this.IsParameter = parent.IsParameter;
1468                         this.LocalInfo = parent.LocalInfo;
1469                         this.ParameterIndex = parent.ParameterIndex;
1470
1471                         Initialize ();
1472                 }
1473
1474                 protected void Initialize ()
1475                 {
1476                         TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1477                         if (sub_fields != null) {
1478                                 sub_info = new VariableInfo [sub_fields.Length];
1479                                 for (int i = 0; i < sub_fields.Length; i++) {
1480                                         if (sub_fields [i] != null)
1481                                                 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1482                                 }
1483                         } else
1484                                 sub_info = new VariableInfo [0];
1485                 }
1486
1487                 public VariableInfo (LocalInfo local_info, int offset)
1488                         : this (local_info.Name, local_info.VariableType, offset)
1489                 {
1490                         this.LocalInfo = local_info;
1491                         this.IsParameter = false;
1492                 }
1493
1494                 public VariableInfo (string name, Type type, int param_idx, int offset)
1495                         : this (name, type, offset)
1496                 {
1497                         this.ParameterIndex = param_idx;
1498                         this.IsParameter = true;
1499                 }
1500
1501                 public bool IsAssigned (EmitContext ec)
1502                 {
1503                         return !ec.DoFlowAnalysis ||
1504                                 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1505                                 ec.CurrentBranching.IsAssigned (this);
1506                 }
1507
1508                 public bool IsAssigned (EmitContext ec, Location loc)
1509                 {
1510                         if (IsAssigned (ec))
1511                                 return true;
1512
1513                         Report.Error (165, loc,
1514                                       "Use of unassigned local variable `" + Name + "'");
1515                         ec.CurrentBranching.SetAssigned (this);
1516                         return false;
1517                 }
1518
1519                 public bool IsAssigned (MyBitVector vector)
1520                 {
1521                         if (vector == null)
1522                                 return true;
1523
1524                         if (vector [Offset])
1525                                 return true;
1526
1527                         for (VariableInfo parent = Parent; parent != null; parent = parent.Parent)
1528                                 if (vector [parent.Offset])
1529                                         return true;
1530
1531                         // Return unless this is a struct.
1532                         if (!TypeInfo.IsStruct)
1533                                 return false;
1534
1535                         // Ok, so each field must be assigned.
1536                         for (int i = 0; i < TypeInfo.Length; i++) {
1537                                 if (!vector [Offset + i + 1])
1538                                         return false;
1539                         }
1540
1541                         // Ok, now check all fields which are structs.
1542                         for (int i = 0; i < sub_info.Length; i++) {
1543                                 VariableInfo sinfo = sub_info [i];
1544                                 if (sinfo == null)
1545                                         continue;
1546
1547                                 if (!sinfo.IsAssigned (vector))
1548                                         return false;
1549                         }
1550
1551                         vector [Offset] = true;
1552                         return true;
1553                 }
1554
1555                 public void SetAssigned (EmitContext ec)
1556                 {
1557                         if (ec.DoFlowAnalysis)
1558                                 ec.CurrentBranching.SetAssigned (this);
1559                 }
1560
1561                 public void SetAssigned (MyBitVector vector)
1562                 {
1563                         vector [Offset] = true;
1564                 }
1565
1566                 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
1567                 {
1568                         if (!ec.DoFlowAnalysis ||
1569                                 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1570                                 ec.CurrentBranching.IsFieldAssigned (this, name))
1571                                 return true;
1572
1573                         Report.Error (170, loc,
1574                                       "Use of possibly unassigned field `" + name + "'");
1575                         ec.CurrentBranching.SetFieldAssigned (this, name);
1576                         return false;
1577                 }
1578
1579                 public bool IsFieldAssigned (MyBitVector vector, string field_name)
1580                 {
1581                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1582
1583                         if (field_idx == 0)
1584                                 return true;
1585
1586                         return vector [Offset + field_idx];
1587                 }
1588
1589                 public void SetFieldAssigned (EmitContext ec, string name)
1590                 {
1591                         if (ec.DoFlowAnalysis)
1592                                 ec.CurrentBranching.SetFieldAssigned (this, name);
1593                 }
1594
1595                 public void SetFieldAssigned (MyBitVector vector, string field_name)
1596                 {
1597                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1598
1599                         if (field_idx == 0)
1600                                 return;
1601
1602                         vector [Offset + field_idx] = true;
1603                 }
1604
1605                 public VariableInfo GetSubStruct (string name)
1606                 {
1607                         TypeInfo type = TypeInfo.GetSubStruct (name);
1608
1609                         if (type == null)
1610                                 return null;
1611
1612                         return new VariableInfo (this, type);
1613                 }
1614
1615                 public override string ToString ()
1616                 {
1617                         return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1618                                               Name, TypeInfo, Offset, Length, IsParameter);
1619                 }
1620         }
1621
1622         // <summary>
1623         //   This is used by the flow code to hold the `layout' of the flow vector for
1624         //   all locals and all parameters (ie. we create one instance of this class for the
1625         //   locals and another one for the params).
1626         // </summary>
1627         public class VariableMap {
1628                 // <summary>
1629                 //   The number of variables in the map.
1630                 // </summary>
1631                 public readonly int Count;
1632
1633                 // <summary>
1634                 //   Total length of the flow vector for this map.
1635                 // <summary>
1636                 public readonly int Length;
1637
1638                 VariableInfo[] map;
1639
1640                 public VariableMap (Parameters ip)
1641                 {
1642                         Count = ip != null ? ip.Count : 0;
1643                         
1644                         // Dont bother allocating anything!
1645                         if (Count == 0)
1646                                 return;
1647                         
1648                         Length = 0;
1649
1650                         for (int i = 0; i < Count; i++) {
1651                                 Parameter.Modifier mod = ip.ParameterModifier (i);
1652
1653                                 if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
1654                                         continue;
1655
1656                                 // Dont allocate till we find an out var.
1657                                 if (map == null)
1658                                         map = new VariableInfo [Count];
1659
1660                                 map [i] = new VariableInfo (ip.ParameterName (i),
1661                                         TypeManager.GetElementType (ip.ParameterType (i)), i, Length);
1662
1663                                 Length += map [i].Length;
1664                         }
1665                 }
1666
1667                 public VariableMap (LocalInfo[] locals)
1668                         : this (null, locals)
1669                 { }
1670
1671                 public VariableMap (VariableMap parent, LocalInfo[] locals)
1672                 {
1673                         int offset = 0, start = 0;
1674                         if (parent != null && parent.map != null) {
1675                                 offset = parent.Length;
1676                                 start = parent.Count;
1677                         }
1678
1679                         Count = locals.Length + start;
1680                         
1681                         if (Count == 0)
1682                                 return;
1683                         
1684                         map = new VariableInfo [Count];
1685                         Length = offset;
1686
1687                         if (parent != null && parent.map != null) {
1688                                 parent.map.CopyTo (map, 0);
1689                         }
1690
1691                         for (int i = start; i < Count; i++) {
1692                                 LocalInfo li = locals [i-start];
1693
1694                                 if (li.VariableType == null)
1695                                         continue;
1696
1697                                 map [i] = li.VariableInfo = new VariableInfo (li, Length);
1698                                 Length += map [i].Length;
1699                         }
1700                 }
1701
1702                 // <summary>
1703                 //   Returns the VariableInfo for variable @index or null if we don't need to
1704                 //   compute assignment info for this variable.
1705                 // </summary>
1706                 public VariableInfo this [int index] {
1707                         get {
1708                                 if (map == null)
1709                                         return null;
1710                                 
1711                                 return map [index];
1712                         }
1713                 }
1714
1715                 public override string ToString ()
1716                 {
1717                         return String.Format ("VariableMap ({0}:{1})", Count, Length);
1718                 }
1719         }
1720
1721         // <summary>
1722         //   This is a special bit vector which can inherit from another bit vector doing a
1723         //   copy-on-write strategy.  The inherited vector may have a smaller size than the
1724         //   current one.
1725         // </summary>
1726         public class MyBitVector {
1727                 public readonly int Count;
1728                 public MyBitVector InheritsFrom;
1729                 public static readonly MyBitVector Empty = new MyBitVector ();
1730
1731                 BitArray vector;
1732
1733                 MyBitVector ()
1734                 {
1735                         InheritsFrom = null;
1736                         Count = 0;
1737                 }
1738
1739                 public MyBitVector (MyBitVector InheritsFrom, int Count)
1740                 {
1741                         if (InheritsFrom != null) {
1742                                 while (InheritsFrom.InheritsFrom != null)
1743                                         InheritsFrom = InheritsFrom.InheritsFrom;                               
1744                                 if (InheritsFrom.Count >= Count && InheritsFrom.vector == null)
1745                                         InheritsFrom = null;
1746                         }
1747
1748                         this.InheritsFrom = InheritsFrom;
1749                         this.Count = Count;
1750                 }
1751
1752                 // <summary>
1753                 //   Get/set bit `index' in the bit vector.
1754                 // </summary>
1755                 public bool this [int index]
1756                 {
1757                         get {
1758                                 if (index >= Count)
1759                                         throw new ArgumentOutOfRangeException ();
1760
1761                                 // We're doing a "copy-on-write" strategy here; as long
1762                                 // as nobody writes to the array, we can use our parent's
1763                                 // copy instead of duplicating the vector.
1764
1765                                 if (vector != null)
1766                                         return vector [index];
1767                                 if (InheritsFrom == null)
1768                                         return true;
1769                                 if (index < InheritsFrom.Count)
1770                                         return InheritsFrom [index];
1771                                 return false;
1772                         }
1773
1774                         set {
1775                                 // Only copy the vector if we're actually modifying it.
1776                                 if (this [index] != value) {
1777                                         if (vector == null)
1778                                                 initialize_vector ();
1779                                         vector [index] = value;
1780                                 }
1781                         }
1782                 }
1783
1784                 // <summary>
1785                 //   Performs an `or' operation on the bit vector.  The `new_vector' may have a
1786                 //   different size than the current one.
1787                 // </summary>
1788                 private void Or (MyBitVector new_vector)
1789                 {
1790                         int min = new_vector.Count;
1791                         if (Count < min)
1792                                 min = Count;
1793
1794                         for (int i = 0; i < min; i++)
1795                                 this [i] |= new_vector [i];
1796                 }
1797
1798                 // <summary>
1799                 //   Perfonrms an `and' operation on the bit vector.  The `new_vector' may have
1800                 //   a different size than the current one.
1801                 // </summary>
1802                 private void And (MyBitVector new_vector)
1803                 {
1804                         int min = new_vector.Count;
1805                         if (Count < min)
1806                                 min = Count;
1807
1808                         for (int i = 0; i < min; i++)
1809                                 this [i] &= new_vector [i];
1810
1811                         for (int i = min; i < Count; i++)
1812                                 this [i] = false;
1813                 }
1814
1815                 public static void And (ref MyBitVector target, MyBitVector vector)
1816                 {
1817                         if (vector == null)
1818                                 return;
1819                         if (target == null)
1820                                 target = vector.Clone ();
1821                         else
1822                                 target.And (vector);
1823                 }
1824
1825                 public static void Or (ref MyBitVector target, MyBitVector vector)
1826                 {
1827                         if (target == null)
1828                                 return;
1829                         if (vector == null)
1830                                 target.SetAll (true);
1831                         else
1832                                 target.Or (vector);
1833                 }
1834
1835                 // <summary>
1836                 //   This does a deep copy of the bit vector.
1837                 // </summary>
1838                 public MyBitVector Clone ()
1839                 {
1840                         if (Count == 0)
1841                                 return Empty;
1842                         MyBitVector retval = new MyBitVector (this, Count);
1843                         retval.initialize_vector ();
1844                         return retval;
1845                 }
1846
1847                 public void SetAll (bool value)
1848                 {
1849                         InheritsFrom = value ? null : Empty;
1850                         vector = null;
1851                 }
1852
1853                 void initialize_vector ()
1854                 {
1855                         if (InheritsFrom == null) {
1856                                 vector = new BitArray (Count, true);
1857                                 return;
1858                         }
1859
1860                         vector = new BitArray (Count, false);
1861
1862                         int min = InheritsFrom.Count;
1863                         if (min > Count)
1864                                 min = Count;
1865
1866                         for (int i = 0; i < min; i++)
1867                                 vector [i] = InheritsFrom [i];
1868
1869                         InheritsFrom = null;
1870                 }
1871
1872                 StringBuilder Dump (StringBuilder sb)
1873                 {
1874                         if (vector == null)
1875                                 return InheritsFrom == null ? sb.Append ("/") : InheritsFrom.Dump (sb.Append ("="));
1876                         for (int i = 0; i < Count; i++)
1877                                 sb.Append (this [i] ? "1" : "0");
1878                         return sb;
1879                 }
1880
1881                 public override string ToString ()
1882                 {
1883                         return Dump (new StringBuilder ("{")).Append ("}").ToString ();
1884                 }
1885         }
1886 }