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