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