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