2003-11-06 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / gmcs / 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                         foreach (UsageVector child in children) {
722                                 Report.Debug (2, "  MERGING CHILD", child, child.AlwaysBreaks, child.AlwaysReturns,
723                                               child.IsUnreachable, child.Locals, child.Parameters,
724                                               child.Returns, child.Breaks, child.Reachable);
725
726                                 reachable = AndFlowReturns (reachable, child.Reachable);
727
728                                 // Ignore unreachable children.
729                                 if (child.IsUnreachable)
730                                         continue;
731
732                                 returns = AndFlowReturns (returns, child.Returns);
733                                 breaks = AndFlowReturns (breaks, child.Breaks);
734                                         
735                                 // A local variable is initialized after a flow branching if it
736                                 // has been initialized in all its branches which do neither
737                                 // always return or always throw an exception.
738                                 //
739                                 // If a branch may return, but does not always return, then we
740                                 // can treat it like a never-returning branch here: control will
741                                 // only reach the code position after the branching if we did not
742                                 // return here.
743                                 //
744                                 // It's important to distinguish between always and sometimes
745                                 // returning branches here:
746                                 //
747                                 //    1   int a;
748                                 //    2   if (something) {
749                                 //    3      return;
750                                 //    4      a = 5;
751                                 //    5   }
752                                 //    6   Console.WriteLine (a);
753                                 //
754                                 // The if block in lines 3-4 always returns, so we must not look
755                                 // at the initialization of `a' in line 4 - thus it'll still be
756                                 // uninitialized in line 6.
757                                 //
758                                 // On the other hand, the following is allowed:
759                                 //
760                                 //    1   int a;
761                                 //    2   if (something)
762                                 //    3      a = 5;
763                                 //    4   else
764                                 //    5      return;
765                                 //    6   Console.WriteLine (a);
766                                 //
767                                 // Here, `a' is initialized in line 3 and we must not look at
768                                 // line 5 since it always returns.
769                                 // 
770                                 if (!child.AlwaysReturns && !child.AlwaysBreaks)
771                                         MyBitVector.And (ref locals, child.LocalVector);
772
773                                 // An `out' parameter must be assigned in all branches which do
774                                 // not always throw an exception.
775                                 if ((child.Type != SiblingType.Catch) &&
776                                     (child.ParameterVector != null) && (child.Breaks != FlowReturns.Exception))
777                                         MyBitVector.And (ref parameters, child.ParameterVector);
778                         }
779
780                         Report.Debug (2, "MERGING CHILDREN DONE", Type, parameters, locals, returns, breaks, reachable,
781                                       Infinite, MayLeaveLoop, this);
782
783                         if (Infinite && !MayLeaveLoop) {
784                                 Report.Debug (1, "INFINITE", returns, breaks, this);
785
786                                 if (returns == FlowReturns.Never) {
787                                         // We're actually infinite.
788                                         breaks = FlowReturns.Unreachable;
789                                         returns = FlowReturns.Unreachable;
790                                 } else if ((returns == FlowReturns.Sometimes) || (returns == FlowReturns.Always)) {
791                                         // If we're an infinite loop and do not break, the code after
792                                         // the loop can never be reached.  However, if we may return
793                                         // from the loop, then we do always return (or stay in the loop
794                                         // forever).
795                                         returns = FlowReturns.Always;
796                                 }
797                         }
798
799                         if (returns == FlowReturns.Undefined)
800                                 returns = FlowReturns.Never;
801                         if (breaks == FlowReturns.Undefined)
802                                 breaks = FlowReturns.Never;
803
804                         return new MergeResult (parameters, locals, returns, breaks, reachable, MayLeaveLoop);
805                 }
806
807                 protected abstract MergeResult Merge ();
808
809                 // <summary>
810                 //   Merge a child branching.
811                 // </summary>
812                 public FlowReturns MergeChild (FlowBranching child)
813                 {
814                         MergeResult result = child.Merge ();
815
816                         CurrentUsageVector.MergeChild (
817                                 result.Parameters, result.Locals, result.Returns, result.Breaks, result.Reachable);
818
819                         if ((child.Type != BranchingType.LoopBlock) && (child.Type != BranchingType.SwitchSection))
820                                 MayLeaveLoop |= child.MayLeaveLoop;
821
822                         if (result.Reachable == FlowReturns.Exception)
823                                 return FlowReturns.Exception;
824                         else
825                                 return result.Returns;
826                 }
827
828                 // <summary>
829                 //   Does the toplevel merging.
830                 // </summary>
831                 public FlowReturns MergeTopBlock ()
832                 {
833                         if ((Type != BranchingType.Block) || (Block == null))
834                                 throw new NotSupportedException ();
835
836                         UsageVector vector = new UsageVector (
837                                 SiblingType.Conditional, null, Location, param_map.Length, local_map.Length);
838
839                         MergeResult result = Merge ();
840                         vector.MergeChild (result.Parameters, result.Locals, result.Returns, result.Breaks, result.Reachable);
841
842                         if (vector.Reachable != FlowReturns.Exception)
843                                 CheckOutParameters (vector.Parameters, Location);
844                         else
845                                 return FlowReturns.Exception;
846
847                         return result.Returns;
848                 }
849
850                 public virtual bool InTryBlock ()
851                 {
852                         if (Parent != null)
853                                 return Parent.InTryBlock ();
854                         else
855                                 return false;
856                 }
857
858                 public virtual void AddFinallyVector (UsageVector vector)
859                 {
860                         if (Parent != null)
861                                 Parent.AddFinallyVector (vector);
862                         else
863                                 throw new NotSupportedException ();
864                 }
865
866                 public bool IsAssigned (VariableInfo vi)
867                 {
868                         return CurrentUsageVector.IsAssigned (vi);
869                 }
870
871                 public bool IsFieldAssigned (VariableInfo vi, string field_name)
872                 {
873                         if (CurrentUsageVector.IsAssigned (vi))
874                                 return true;
875
876                         return CurrentUsageVector.IsFieldAssigned (vi, field_name);
877                 }
878
879                 public void SetAssigned (VariableInfo vi)
880                 {
881                         CurrentUsageVector.SetAssigned (vi);
882                 }
883
884                 public void SetFieldAssigned (VariableInfo vi, string name)
885                 {
886                         CurrentUsageVector.SetFieldAssigned (vi, name);
887                 }
888
889                 public override string ToString ()
890                 {
891                         StringBuilder sb = new StringBuilder ();
892                         sb.Append (GetType ());
893                         sb.Append (" (");
894
895                         sb.Append (id);
896                         sb.Append (",");
897                         sb.Append (Type);
898                         if (Block != null) {
899                                 sb.Append (" - ");
900                                 sb.Append (Block.ID);
901                                 sb.Append (" - ");
902                                 sb.Append (Block.StartLocation);
903                         }
904                         sb.Append (" - ");
905                         // sb.Append (Siblings.Length);
906                         // sb.Append (" - ");
907                         sb.Append (CurrentUsageVector);
908                         sb.Append (")");
909                         return sb.ToString ();
910                 }
911         }
912
913         public class FlowBranchingBlock : FlowBranching
914         {
915                 UsageVector current_vector;
916                 ArrayList siblings = new ArrayList ();
917
918                 public FlowBranchingBlock (FlowBranching parent, BranchingType type, SiblingType stype,
919                                            Block block, Location loc)
920                         : base (parent, type, stype, block, loc)
921                 { }
922
923                 public override UsageVector CurrentUsageVector {
924                         get { return current_vector; }
925                 }
926
927                 protected override void AddSibling (UsageVector sibling)
928                 {
929                         siblings.Add (sibling);
930                         current_vector = sibling;
931                 }
932
933                 public override void Break ()
934                 {
935                         if (Type == BranchingType.SwitchSection)
936                                 CurrentUsageVector.NeverReachable ();
937                         else {
938                                 if (Type == BranchingType.LoopBlock)
939                                         MayLeaveLoop = true;
940                                 CurrentUsageVector.Break ();
941                         }
942                 }
943
944                 public override void Return ()
945                 {
946                         CurrentUsageVector.Return ();
947                 }
948
949                 public override void Goto ()
950                 {
951                         CurrentUsageVector.Unreachable ();
952                 }
953
954                 public override void Throw ()
955                 {
956                         CurrentUsageVector.Throw ();
957                 }
958
959                 public override void Label (ArrayList origin_vectors)
960                 {
961                         CurrentUsageVector.MergeJumpOrigins (origin_vectors);
962                 }
963
964                 protected override MergeResult Merge ()
965                 {
966                         MergeResult result = Merge (siblings);
967                         if (Type == BranchingType.LoopBlock)
968                                 result.MayLeaveLoop = false;
969                         return result;
970                 }
971         }
972
973         public class FlowBranchingException : FlowBranching
974         {
975                 ArrayList finally_vectors;
976
977                 bool has_params;
978                 UsageVector current_vector;
979                 UsageVector try_vector;
980                 ArrayList catch_vectors = new ArrayList ();
981                 UsageVector finally_vector;
982
983                 public FlowBranchingException (FlowBranching parent, BranchingType type, Block block, Location loc)
984                         : base (parent, type, SiblingType.Try, block, loc)
985                 {
986                         finally_vectors = new ArrayList ();
987                         has_params = current_vector.HasParameters;
988                 }
989
990                 protected override void AddSibling (UsageVector sibling)
991                 {
992                         if (sibling.Type == SiblingType.Try) {
993                                 try_vector = sibling;
994                                 catch_vectors.Add (sibling);
995                         } else if (sibling.Type == SiblingType.Catch)
996                                 catch_vectors.Add (sibling);
997                         else if (sibling.Type == SiblingType.Finally) {
998                                 // sibling.MergeFinallyOrigins (finally_vectors);
999                                 finally_vector = sibling;
1000                         } else
1001                                 throw new InvalidOperationException ();
1002
1003                         current_vector = sibling;
1004                 }
1005
1006                 public override UsageVector CurrentUsageVector {
1007                         get { return current_vector; }
1008                 }
1009
1010                 public override bool InTryBlock ()
1011                 {
1012                         return true;
1013                 }
1014
1015                 public override void AddFinallyVector (UsageVector vector)
1016                 {
1017                         finally_vectors.Add (vector.Clone ());
1018                 }
1019
1020                 public override void Break ()
1021                 {
1022                         CurrentUsageVector.Break ();
1023                 }
1024
1025                 public override void Return ()
1026                 {
1027                         CurrentUsageVector.Return ();
1028                 }
1029
1030                 public override void Goto ()
1031                 {
1032                         CurrentUsageVector.Unreachable ();
1033                 }
1034
1035                 public override void Throw ()
1036                 {
1037                         CurrentUsageVector.Throw ();
1038                 }
1039
1040                 public override void Label (ArrayList origin_vectors)
1041                 {
1042                         CurrentUsageVector.MergeJumpOrigins (origin_vectors);
1043                 }
1044
1045                 protected void MergeFinally (MyBitVector f_params, ref MergeResult result)
1046                 {
1047                         foreach (UsageVector vector in finally_vectors) {
1048                                 MyBitVector temp_params = f_params.Clone ();
1049                                 temp_params.Or (vector.Parameters);
1050
1051                                 CheckOutParameters (temp_params, Location);
1052                         }
1053                 }
1054
1055                 protected override MergeResult Merge ()
1056                 {
1057                         MergeResult result = Merge (catch_vectors);
1058
1059                         if (has_params) {
1060                                 if (finally_vector != null) {
1061                                         MergeFinally (finally_vector.Parameters, ref result);
1062                                         MyBitVector.Or (ref result.Parameters, finally_vector.ParameterVector);
1063                                 } else
1064                                         MergeFinally (result.Parameters, ref result);
1065                         }
1066
1067                         if (finally_vector != null)
1068                                 MyBitVector.Or (ref result.Locals, finally_vector.LocalVector);
1069
1070                         return result;
1071                 }
1072         }
1073
1074         // <summary>
1075         //   This is used by the flow analysis code to keep track of the type of local variables
1076         //   and variables.
1077         //
1078         //   The flow code uses a BitVector to keep track of whether a variable has been assigned
1079         //   or not.  This is easy for fundamental types (int, char etc.) or reference types since
1080         //   you can only assign the whole variable as such.
1081         //
1082         //   For structs, we also need to keep track of all its fields.  To do this, we allocate one
1083         //   bit for the struct itself (it's used if you assign/access the whole struct) followed by
1084         //   one bit for each of its fields.
1085         //
1086         //   This class computes this `layout' for each type.
1087         // </summary>
1088         public class TypeInfo
1089         {
1090                 public readonly Type Type;
1091
1092                 // <summary>
1093                 //   Total number of bits a variable of this type consumes in the flow vector.
1094                 // </summary>
1095                 public readonly int TotalLength;
1096
1097                 // <summary>
1098                 //   Number of bits the simple fields of a variable of this type consume
1099                 //   in the flow vector.
1100                 // </summary>
1101                 public readonly int Length;
1102
1103                 // <summary>
1104                 //   This is only used by sub-structs.
1105                 // </summary>
1106                 public readonly int Offset;
1107
1108                 // <summary>
1109                 //   If this is a struct.
1110                 // </summary>
1111                 public readonly bool IsStruct;       
1112
1113                 // <summary>
1114                 //   If this is a struct, all fields which are structs theirselves.
1115                 // </summary>
1116                 public TypeInfo[] SubStructInfo;
1117
1118                 protected readonly StructInfo struct_info;
1119                 private static Hashtable type_hash = new Hashtable ();
1120
1121                 public static TypeInfo GetTypeInfo (Type type)
1122                 {
1123                         TypeInfo info = (TypeInfo) type_hash [type];
1124                         if (info != null)
1125                                 return info;
1126
1127                         info = new TypeInfo (type);
1128                         type_hash.Add (type, info);
1129                         return info;
1130                 }
1131
1132                 public static TypeInfo GetTypeInfo (TypeContainer tc)
1133                 {
1134                         TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
1135                         if (info != null)
1136                                 return info;
1137
1138                         info = new TypeInfo (tc);
1139                         type_hash.Add (tc.TypeBuilder, info);
1140                         return info;
1141                 }
1142
1143                 private TypeInfo (Type type)
1144                 {
1145                         this.Type = type;
1146
1147                         struct_info = StructInfo.GetStructInfo (type);
1148                         if (struct_info != null) {
1149                                 Length = struct_info.Length;
1150                                 TotalLength = struct_info.TotalLength;
1151                                 SubStructInfo = struct_info.StructFields;
1152                                 IsStruct = true;
1153                         } else {
1154                                 Length = 0;
1155                                 TotalLength = 1;
1156                                 IsStruct = false;
1157                         }
1158                 }
1159
1160                 private TypeInfo (TypeContainer tc)
1161                 {
1162                         this.Type = tc.TypeBuilder;
1163
1164                         struct_info = StructInfo.GetStructInfo (tc);
1165                         if (struct_info != null) {
1166                                 Length = struct_info.Length;
1167                                 TotalLength = struct_info.TotalLength;
1168                                 SubStructInfo = struct_info.StructFields;
1169                                 IsStruct = true;
1170                         } else {
1171                                 Length = 0;
1172                                 TotalLength = 1;
1173                                 IsStruct = false;
1174                         }
1175                 }
1176
1177                 protected TypeInfo (StructInfo struct_info, int offset)
1178                 {
1179                         this.struct_info = struct_info;
1180                         this.Offset = offset;
1181                         this.Length = struct_info.Length;
1182                         this.TotalLength = struct_info.TotalLength;
1183                         this.SubStructInfo = struct_info.StructFields;
1184                         this.Type = struct_info.Type;
1185                         this.IsStruct = true;
1186                 }
1187
1188                 public int GetFieldIndex (string name)
1189                 {
1190                         if (struct_info == null)
1191                                 return 0;
1192
1193                         return struct_info [name];
1194                 }
1195
1196                 public TypeInfo GetSubStruct (string name)
1197                 {
1198                         if (struct_info == null)
1199                                 return null;
1200
1201                         return struct_info.GetStructField (name);
1202                 }
1203
1204                 // <summary>
1205                 //   A struct's constructor must always assign all fields.
1206                 //   This method checks whether it actually does so.
1207                 // </summary>
1208                 public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
1209                 {
1210                         if (struct_info == null)
1211                                 return true;
1212
1213                         bool ok = true;
1214                         for (int i = 0; i < struct_info.Count; i++) {
1215                                 FieldInfo field = struct_info.Fields [i];
1216
1217                                 if (!branching.IsFieldAssigned (vi, field.Name)) {
1218                                         Report.Error (171, loc,
1219                                                       "Field `" + TypeManager.CSharpName (Type) +
1220                                                       "." + field.Name + "' must be fully initialized " +
1221                                                       "before control leaves the constructor");
1222                                         ok = false;
1223                                 }
1224                         }
1225
1226                         return ok;
1227                 }
1228
1229                 public override string ToString ()
1230                 {
1231                         return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
1232                                               Type, Offset, Length, TotalLength);
1233                 }
1234
1235                 protected class StructInfo {
1236                         public readonly Type Type;
1237                         public readonly FieldInfo[] Fields;
1238                         public readonly TypeInfo[] StructFields;
1239                         public readonly int Count;
1240                         public readonly int CountPublic;
1241                         public readonly int CountNonPublic;
1242                         public readonly int Length;
1243                         public readonly int TotalLength;
1244                         public readonly bool HasStructFields;
1245
1246                         private static Hashtable field_type_hash = new Hashtable ();
1247                         private Hashtable struct_field_hash;
1248                         private Hashtable field_hash;
1249
1250                         protected bool InTransit = false;
1251
1252                         // Private constructor.  To save memory usage, we only need to create one instance
1253                         // of this class per struct type.
1254                         private StructInfo (Type type)
1255                         {
1256                                 this.Type = type;
1257
1258                                 field_type_hash.Add (type, this);
1259
1260                                 if (type is TypeBuilder) {
1261                                         TypeContainer tc = TypeManager.LookupTypeContainer (type);
1262
1263                                         ArrayList fields = tc.Fields;
1264
1265                                         ArrayList public_fields = new ArrayList ();
1266                                         ArrayList non_public_fields = new ArrayList ();
1267
1268                                         if (fields != null) {
1269                                                 foreach (Field field in fields) {
1270                                                         if ((field.ModFlags & Modifiers.STATIC) != 0)
1271                                                                 continue;
1272                                                         if ((field.ModFlags & Modifiers.PUBLIC) != 0)
1273                                                                 public_fields.Add (field.FieldBuilder);
1274                                                         else
1275                                                                 non_public_fields.Add (field.FieldBuilder);
1276                                                 }
1277                                         }
1278
1279                                         CountPublic = public_fields.Count;
1280                                         CountNonPublic = non_public_fields.Count;
1281                                         Count = CountPublic + CountNonPublic;
1282
1283                                         Fields = new FieldInfo [Count];
1284                                         public_fields.CopyTo (Fields, 0);
1285                                         non_public_fields.CopyTo (Fields, CountPublic);
1286                                 } else {
1287                                         FieldInfo[] public_fields = type.GetFields (
1288                                                 BindingFlags.Instance|BindingFlags.Public);
1289                                         FieldInfo[] non_public_fields = type.GetFields (
1290                                                 BindingFlags.Instance|BindingFlags.NonPublic);
1291
1292                                         CountPublic = public_fields.Length;
1293                                         CountNonPublic = non_public_fields.Length;
1294                                         Count = CountPublic + CountNonPublic;
1295
1296                                         Fields = new FieldInfo [Count];
1297                                         public_fields.CopyTo (Fields, 0);
1298                                         non_public_fields.CopyTo (Fields, CountPublic);
1299                                 }
1300
1301                                 struct_field_hash = new Hashtable ();
1302                                 field_hash = new Hashtable ();
1303
1304                                 Length = 0;
1305                                 StructFields = new TypeInfo [Count];
1306                                 StructInfo[] sinfo = new StructInfo [Count];
1307
1308                                 InTransit = true;
1309
1310                                 for (int i = 0; i < Count; i++) {
1311                                         FieldInfo field = (FieldInfo) Fields [i];
1312
1313                                         sinfo [i] = GetStructInfo (field.FieldType);
1314                                         if (sinfo [i] == null)
1315                                                 field_hash.Add (field.Name, ++Length);
1316                                         else if (sinfo [i].InTransit) {
1317                                                 Report.Error (523, String.Format (
1318                                                                       "Struct member '{0}.{1}' of type '{2}' causes " +
1319                                                                       "a cycle in the structure layout",
1320                                                                       type, field.Name, sinfo [i].Type));
1321                                                 sinfo [i] = null;
1322                                                 return;
1323                                         }
1324                                 }
1325
1326                                 InTransit = false;
1327
1328                                 TotalLength = Length + 1;
1329                                 for (int i = 0; i < Count; i++) {
1330                                         FieldInfo field = (FieldInfo) Fields [i];
1331
1332                                         if (sinfo [i] == null)
1333                                                 continue;
1334
1335                                         field_hash.Add (field.Name, TotalLength);
1336
1337                                         HasStructFields = true;
1338                                         StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1339                                         struct_field_hash.Add (field.Name, StructFields [i]);
1340                                         TotalLength += sinfo [i].TotalLength;
1341                                 }
1342                         }
1343
1344                         public int this [string name] {
1345                                 get {
1346                                         if (field_hash.Contains (name))
1347                                                 return (int) field_hash [name];
1348                                         else
1349                                                 return 0;
1350                                 }
1351                         }
1352
1353                         public TypeInfo GetStructField (string name)
1354                         {
1355                                 return (TypeInfo) struct_field_hash [name];
1356                         }
1357
1358                         public static StructInfo GetStructInfo (Type type)
1359                         {
1360                                 if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
1361                                     TypeManager.IsBuiltinType (type))
1362                                         return null;
1363
1364                                 StructInfo info = (StructInfo) field_type_hash [type];
1365                                 if (info != null)
1366                                         return info;
1367
1368                                 return new StructInfo (type);
1369                         }
1370
1371                         public static StructInfo GetStructInfo (TypeContainer tc)
1372                         {
1373                                 StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
1374                                 if (info != null)
1375                                         return info;
1376
1377                                 return new StructInfo (tc.TypeBuilder);
1378                         }
1379                 }
1380         }
1381
1382         // <summary>
1383         //   This is used by the flow analysis code to store information about a single local variable
1384         //   or parameter.  Depending on the variable's type, we need to allocate one or more elements
1385         //   in the BitVector - if it's a fundamental or reference type, we just need to know whether
1386         //   it has been assigned or not, but for structs, we need this information for each of its fields.
1387         // </summary>
1388         public class VariableInfo {
1389                 public readonly string Name;
1390                 public readonly TypeInfo TypeInfo;
1391
1392                 // <summary>
1393                 //   The bit offset of this variable in the flow vector.
1394                 // </summary>
1395                 public readonly int Offset;
1396
1397                 // <summary>
1398                 //   The number of bits this variable needs in the flow vector.
1399                 //   The first bit always specifies whether the variable as such has been assigned while
1400                 //   the remaining bits contain this information for each of a struct's fields.
1401                 // </summary>
1402                 public readonly int Length;
1403
1404                 // <summary>
1405                 //   If this is a parameter of local variable.
1406                 // </summary>
1407                 public readonly bool IsParameter;
1408
1409                 public readonly LocalInfo LocalInfo;
1410                 public readonly int ParameterIndex;
1411
1412                 readonly VariableInfo Parent;
1413                 VariableInfo[] sub_info;
1414
1415                 protected VariableInfo (string name, Type type, int offset)
1416                 {
1417                         this.Name = name;
1418                         this.Offset = offset;
1419                         this.TypeInfo = TypeInfo.GetTypeInfo (type);
1420
1421                         Length = TypeInfo.TotalLength;
1422
1423                         Initialize ();
1424                 }
1425
1426                 protected VariableInfo (VariableInfo parent, TypeInfo type)
1427                 {
1428                         this.Name = parent.Name;
1429                         this.TypeInfo = type;
1430                         this.Offset = parent.Offset + type.Offset;
1431                         this.Parent = parent;
1432                         this.Length = type.TotalLength;
1433
1434                         this.IsParameter = parent.IsParameter;
1435                         this.LocalInfo = parent.LocalInfo;
1436                         this.ParameterIndex = parent.ParameterIndex;
1437
1438                         Initialize ();
1439                 }
1440
1441                 protected void Initialize ()
1442                 {
1443                         TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1444                         if (sub_fields != null) {
1445                                 sub_info = new VariableInfo [sub_fields.Length];
1446                                 for (int i = 0; i < sub_fields.Length; i++) {
1447                                         if (sub_fields [i] != null)
1448                                                 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1449                                 }
1450                         } else
1451                                 sub_info = new VariableInfo [0];
1452                 }
1453
1454                 public VariableInfo (LocalInfo local_info, int offset)
1455                         : this (local_info.Name, local_info.VariableType, offset)
1456                 {
1457                         this.LocalInfo = local_info;
1458                         this.IsParameter = false;
1459                 }
1460
1461                 public VariableInfo (string name, Type type, int param_idx, int offset)
1462                         : this (name, type, offset)
1463                 {
1464                         this.ParameterIndex = param_idx;
1465                         this.IsParameter = true;
1466                 }
1467
1468                 public bool IsAssigned (EmitContext ec)
1469                 {
1470                         return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this);
1471                 }
1472
1473                 public bool IsAssigned (EmitContext ec, Location loc)
1474                 {
1475                         if (IsAssigned (ec))
1476                                 return true;
1477
1478                         Report.Error (165, loc,
1479                                       "Use of unassigned local variable `" + Name + "'");
1480                         ec.CurrentBranching.SetAssigned (this);
1481                         return false;
1482                 }
1483
1484                 public bool IsAssigned (MyBitVector vector)
1485                 {
1486                         if (vector [Offset])
1487                                 return true;
1488
1489                         for (VariableInfo parent = Parent; parent != null; parent = parent.Parent)
1490                                 if (vector [parent.Offset])
1491                                         return true;
1492
1493                         // Return unless this is a struct.
1494                         if (!TypeInfo.IsStruct)
1495                                 return false;
1496
1497                         // Ok, so each field must be assigned.
1498                         for (int i = 0; i < TypeInfo.Length; i++) {
1499                                 if (!vector [Offset + i + 1])
1500                                         return false;
1501                         }
1502
1503                         // Ok, now check all fields which are structs.
1504                         for (int i = 0; i < sub_info.Length; i++) {
1505                                 VariableInfo sinfo = sub_info [i];
1506                                 if (sinfo == null)
1507                                         continue;
1508
1509                                 if (!sinfo.IsAssigned (vector))
1510                                         return false;
1511                         }
1512
1513                         vector [Offset] = true;
1514                         return true;
1515                 }
1516
1517                 public void SetAssigned (EmitContext ec)
1518                 {
1519                         if (ec.DoFlowAnalysis)
1520                                 ec.CurrentBranching.SetAssigned (this);
1521                 }
1522
1523                 public void SetAssigned (MyBitVector vector)
1524                 {
1525                         vector [Offset] = true;
1526                 }
1527
1528                 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
1529                 {
1530                         if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsFieldAssigned (this, name))
1531                                 return true;
1532
1533                         Report.Error (170, loc,
1534                                       "Use of possibly unassigned field `" + name + "'");
1535                         ec.CurrentBranching.SetFieldAssigned (this, name);
1536                         return false;
1537                 }
1538
1539                 public bool IsFieldAssigned (MyBitVector vector, string field_name)
1540                 {
1541                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1542
1543                         if (field_idx == 0)
1544                                 return true;
1545
1546                         return vector [Offset + field_idx];
1547                 }
1548
1549                 public void SetFieldAssigned (EmitContext ec, string name)
1550                 {
1551                         if (ec.DoFlowAnalysis)
1552                                 ec.CurrentBranching.SetFieldAssigned (this, name);
1553                 }
1554
1555                 public void SetFieldAssigned (MyBitVector vector, string field_name)
1556                 {
1557                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1558
1559                         if (field_idx == 0)
1560                                 return;
1561
1562                         vector [Offset + field_idx] = true;
1563                 }
1564
1565                 public VariableInfo GetSubStruct (string name)
1566                 {
1567                         TypeInfo type = TypeInfo.GetSubStruct (name);
1568
1569                         if (type == null)
1570                                 return null;
1571
1572                         return new VariableInfo (this, type);
1573                 }
1574
1575                 public override string ToString ()
1576                 {
1577                         return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1578                                               Name, TypeInfo, Offset, Length, IsParameter);
1579                 }
1580         }
1581
1582         // <summary>
1583         //   This is used by the flow code to hold the `layout' of the flow vector for
1584         //   all locals and all parameters (ie. we create one instance of this class for the
1585         //   locals and another one for the params).
1586         // </summary>
1587         public class VariableMap {
1588                 // <summary>
1589                 //   The number of variables in the map.
1590                 // </summary>
1591                 public readonly int Count;
1592
1593                 // <summary>
1594                 //   Total length of the flow vector for this map.
1595                 // <summary>
1596                 public readonly int Length;
1597
1598                 // <summary>
1599                 //   Type and name of all the variables.
1600                 //   Note that this is null for variables for which we do not need to compute
1601                 //   assignment info.
1602                 // </summary>
1603                 public readonly Type[] VariableTypes;
1604                 public readonly string[] VariableNames;
1605
1606                 VariableInfo[] map;
1607
1608                 public VariableMap (InternalParameters ip)
1609                 {
1610                         Count = ip != null ? ip.Count : 0;
1611                         map = new VariableInfo [Count];
1612                         VariableNames = new string [Count];
1613                         VariableTypes = new Type [Count];
1614                         Length = 0;
1615
1616                         for (int i = 0; i < Count; i++) {
1617                                 Parameter.Modifier mod = ip.ParameterModifier (i);
1618
1619                                 if ((mod & Parameter.Modifier.OUT) == 0)
1620                                         continue;
1621
1622                                 VariableNames [i] = ip.ParameterName (i);
1623                                 VariableTypes [i] = TypeManager.GetElementType (ip.ParameterType (i));
1624
1625                                 map [i] = new VariableInfo (VariableNames [i], VariableTypes [i], i, Length);
1626                                 Length += map [i].Length;
1627                         }
1628                 }
1629
1630                 public VariableMap (LocalInfo[] locals)
1631                         : this (null, locals)
1632                 { }
1633
1634                 public VariableMap (VariableMap parent, LocalInfo[] locals)
1635                 {
1636                         int offset = 0, start = 0;
1637                         if (parent != null) {
1638                                 offset = parent.Length;
1639                                 start = parent.Count;
1640                         }
1641
1642                         Count = locals.Length + start;
1643                         map = new VariableInfo [Count];
1644                         VariableNames = new string [Count];
1645                         VariableTypes = new Type [Count];
1646                         Length = offset;
1647
1648                         if (parent != null) {
1649                                 parent.map.CopyTo (map, 0);
1650                                 parent.VariableNames.CopyTo (VariableNames, 0);
1651                                 parent.VariableTypes.CopyTo (VariableTypes, 0);
1652                         }
1653
1654                         for (int i = start; i < Count; i++) {
1655                                 LocalInfo li = locals [i-start];
1656
1657                                 if (li.VariableType == null)
1658                                         continue;
1659
1660                                 VariableNames [i] = li.Name;
1661                                 VariableTypes [i] = li.VariableType;
1662
1663                                 map [i] = li.VariableInfo = new VariableInfo (li, Length);
1664                                 Length += map [i].Length;
1665                         }
1666                 }
1667
1668                 // <summary>
1669                 //   Returns the VariableInfo for variable @index or null if we don't need to
1670                 //   compute assignment info for this variable.
1671                 // </summary>
1672                 public VariableInfo this [int index] {
1673                         get {
1674                                 return map [index];
1675                         }
1676                 }
1677
1678                 public override string ToString ()
1679                 {
1680                         return String.Format ("VariableMap ({0}:{1})", Count, Length);
1681                 }
1682         }
1683
1684         // <summary>
1685         //   This is a special bit vector which can inherit from another bit vector doing a
1686         //   copy-on-write strategy.  The inherited vector may have a smaller size than the
1687         //   current one.
1688         // </summary>
1689         public class MyBitVector {
1690                 public readonly int Count;
1691                 public readonly MyBitVector InheritsFrom;
1692
1693                 bool is_dirty;
1694                 BitArray vector;
1695
1696                 public MyBitVector (int Count)
1697                         : this (null, Count)
1698                 { }
1699
1700                 public MyBitVector (MyBitVector InheritsFrom, int Count)
1701                 {
1702                         this.InheritsFrom = InheritsFrom;
1703                         this.Count = Count;
1704                 }
1705
1706                 // <summary>
1707                 //   Checks whether this bit vector has been modified.  After setting this to true,
1708                 //   we won't use the inherited vector anymore, but our own copy of it.
1709                 // </summary>
1710                 public bool IsDirty {
1711                         get {
1712                                 return is_dirty;
1713                         }
1714
1715                         set {
1716                                 if (!is_dirty)
1717                                         initialize_vector ();
1718                         }
1719                 }
1720
1721                 // <summary>
1722                 //   Get/set bit `index' in the bit vector.
1723                 // </summary>
1724                 public bool this [int index]
1725                 {
1726                         get {
1727                                 if (index > Count)
1728                                         throw new ArgumentOutOfRangeException ();
1729
1730                                 // We're doing a "copy-on-write" strategy here; as long
1731                                 // as nobody writes to the array, we can use our parent's
1732                                 // copy instead of duplicating the vector.
1733
1734                                 if (vector != null)
1735                                         return vector [index];
1736                                 else if (InheritsFrom != null) {
1737                                         BitArray inherited = InheritsFrom.Vector;
1738
1739                                         if (index < inherited.Count)
1740                                                 return inherited [index];
1741                                         else
1742                                                 return false;
1743                                 } else
1744                                         return false;
1745                         }
1746
1747                         set {
1748                                 if (index > Count)
1749                                         throw new ArgumentOutOfRangeException ();
1750
1751                                 // Only copy the vector if we're actually modifying it.
1752
1753                                 if (this [index] != value) {
1754                                         initialize_vector ();
1755
1756                                         vector [index] = value;
1757                                 }
1758                         }
1759                 }
1760
1761                 // <summary>
1762                 //   If you explicitly convert the MyBitVector to a BitArray, you will get a deep
1763                 //   copy of the bit vector.
1764                 // </summary>
1765                 public static explicit operator BitArray (MyBitVector vector)
1766                 {
1767                         vector.initialize_vector ();
1768                         return vector.Vector;
1769                 }
1770
1771                 // <summary>
1772                 //   Performs an `or' operation on the bit vector.  The `new_vector' may have a
1773                 //   different size than the current one.
1774                 // </summary>
1775                 public void Or (MyBitVector new_vector)
1776                 {
1777                         BitArray new_array = new_vector.Vector;
1778
1779                         initialize_vector ();
1780
1781                         int upper;
1782                         if (vector.Count < new_array.Count)
1783                                 upper = vector.Count;
1784                         else
1785                                 upper = new_array.Count;
1786
1787                         for (int i = 0; i < upper; i++)
1788                                 vector [i] = vector [i] | new_array [i];
1789                 }
1790
1791                 // <summary>
1792                 //   Perfonrms an `and' operation on the bit vector.  The `new_vector' may have
1793                 //   a different size than the current one.
1794                 // </summary>
1795                 public void And (MyBitVector new_vector)
1796                 {
1797                         BitArray new_array = new_vector.Vector;
1798
1799                         initialize_vector ();
1800
1801                         int lower, upper;
1802                         if (vector.Count < new_array.Count)
1803                                 lower = upper = vector.Count;
1804                         else {
1805                                 lower = new_array.Count;
1806                                 upper = vector.Count;
1807                         }
1808
1809                         for (int i = 0; i < lower; i++)
1810                                 vector [i] = vector [i] & new_array [i];
1811
1812                         for (int i = lower; i < upper; i++)
1813                                 vector [i] = false;
1814                 }
1815
1816                 public static void And (ref MyBitVector target, MyBitVector vector)
1817                 {
1818                         if (target != null)
1819                                 target.And (vector);
1820                         else
1821                                 target = vector.Clone ();
1822                 }
1823
1824                 public static void Or (ref MyBitVector target, MyBitVector vector)
1825                 {
1826                         if (target != null)
1827                                 target.Or (vector);
1828                         else
1829                                 target = vector.Clone ();
1830                 }
1831
1832                 // <summary>
1833                 //   This does a deep copy of the bit vector.
1834                 // </summary>
1835                 public MyBitVector Clone ()
1836                 {
1837                         MyBitVector retval = new MyBitVector (Count);
1838
1839                         retval.Vector = Vector;
1840
1841                         return retval;
1842                 }
1843
1844                 BitArray Vector {
1845                         get {
1846                                 if (vector != null)
1847                                         return vector;
1848                                 else if (!is_dirty && (InheritsFrom != null))
1849                                         return InheritsFrom.Vector;
1850
1851                                 initialize_vector ();
1852
1853                                 return vector;
1854                         }
1855
1856                         set {
1857                                 initialize_vector ();
1858
1859                                 for (int i = 0; i < System.Math.Min (vector.Count, value.Count); i++)
1860                                         vector [i] = value [i];
1861                         }
1862                 }
1863
1864                 void initialize_vector ()
1865                 {
1866                         if (vector != null)
1867                                 return;
1868
1869                         vector = new BitArray (Count, false);
1870                         if (InheritsFrom != null)
1871                                 Vector = InheritsFrom.Vector;
1872
1873                         is_dirty = true;
1874                 }
1875
1876                 public override string ToString ()
1877                 {
1878                         StringBuilder sb = new StringBuilder ("MyBitVector (");
1879
1880                         BitArray vector = Vector;
1881                         sb.Append (Count);
1882                         sb.Append (",");
1883                         if (!IsDirty)
1884                                 sb.Append ("INHERITED - ");
1885                         for (int i = 0; i < vector.Count; i++) {
1886                                 if (i > 0)
1887                                         sb.Append (",");
1888                                 sb.Append (vector [i]);
1889                         }
1890                         
1891                         sb.Append (")");
1892                         return sb.ToString ();
1893                 }
1894         }
1895 }