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