Set null object for default timer
[mono.git] / mcs / mcs / context.cs
1 //
2 // context.cs: Various compiler contexts.
3 //
4 // Author:
5 //   Marek Safar (marek.safar@gmail.com)
6 //   Miguel de Icaza (miguel@ximian.com)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2004-2009 Novell, Inc.
10 //
11
12 using System;
13 using System.Collections.Generic;
14
15 #if STATIC
16 using IKVM.Reflection.Emit;
17 #else
18 using System.Reflection.Emit;
19 #endif
20
21 namespace Mono.CSharp
22 {
23         //
24         // Implemented by elements which can act as independent contexts
25         // during resolve phase. Used mostly for lookups.
26         //
27         public interface IMemberContext
28         {
29                 //
30                 // A scope type context, it can be inflated for generic types
31                 //
32                 TypeSpec CurrentType { get; }
33
34                 //
35                 // A scope type parameters either VAR or MVAR
36                 //
37                 TypeParameter[] CurrentTypeParameters { get; }
38
39                 //
40                 // A member definition of the context. For partial types definition use
41                 // CurrentTypeDefinition.PartialContainer otherwise the context is local
42                 //
43                 // TODO: Obsolete it in this context, dynamic context cannot guarantee sensible value
44                 //
45                 MemberCore CurrentMemberDefinition { get; }
46
47                 bool IsObsolete { get; }
48                 bool IsUnsafe { get; }
49                 bool IsStatic { get; }
50                 bool HasUnresolvedConstraints { get; }
51                 ModuleContainer Module { get; }
52
53                 string GetSignatureForError ();
54
55                 IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope);
56                 FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104);
57                 FullNamedExpression LookupNamespaceAlias (string name);
58
59                 // TODO: It has been replaced by module
60                 CompilerContext Compiler { get; }
61         }
62
63         //
64         // Block or statement resolving context
65         //
66         public class BlockContext : ResolveContext
67         {
68                 FlowBranching current_flow_branching;
69
70                 TypeSpec return_type;
71
72                 /// <summary>
73                 ///   The location where return has to jump to return the
74                 ///   value
75                 /// </summary>
76                 public Label ReturnLabel;       // TODO: It's emit dependant
77
78                 /// <summary>
79                 ///   If we already defined the ReturnLabel
80                 /// </summary>
81                 public bool HasReturnLabel;
82
83                 public int FlowOffset;
84
85                 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
86                         : base (mc)
87                 {
88                         if (returnType == null)
89                                 throw new ArgumentNullException ("returnType");
90
91                         this.return_type = returnType;
92
93                         // TODO: check for null value
94                         CurrentBlock = block;
95                 }
96
97                 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
98                         : this (rc.MemberContext, block, returnType)
99                 {
100                         if (rc.IsUnsafe)
101                                 flags |= ResolveContext.Options.UnsafeScope;
102
103                         if (rc.HasSet (ResolveContext.Options.CheckedScope))
104                                 flags |= ResolveContext.Options.CheckedScope;
105                 }
106
107                 public override FlowBranching CurrentBranching {
108                         get { return current_flow_branching; }
109                 }
110
111                 // <summary>
112                 //   Starts a new code branching.  This inherits the state of all local
113                 //   variables and parameters from the current branching.
114                 // </summary>
115                 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
116                 {
117                         current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
118                         return current_flow_branching;
119                 }
120
121                 // <summary>
122                 //   Starts a new code branching for block `block'.
123                 // </summary>
124                 public FlowBranching StartFlowBranching (Block block)
125                 {
126                         Set (Options.DoFlowAnalysis);
127
128                         current_flow_branching = FlowBranching.CreateBranching (
129                                 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
130                         return current_flow_branching;
131                 }
132
133                 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
134                 {
135                         FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
136                         current_flow_branching = branching;
137                         return branching;
138                 }
139
140                 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
141                 {
142                         FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
143                         current_flow_branching = branching;
144                         return branching;
145                 }
146
147                 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
148                 {
149                         FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
150                         current_flow_branching = branching;
151                         return branching;
152                 }
153
154                 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
155                 {
156                         FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
157                         current_flow_branching = branching;
158                         return branching;
159                 }
160
161                 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
162                 {
163                         FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
164                         current_flow_branching = branching;
165                         return branching;
166                 }
167
168                 // <summary>
169                 //   Ends a code branching.  Merges the state of locals and parameters
170                 //   from all the children of the ending branching.
171                 // </summary>
172                 public bool EndFlowBranching ()
173                 {
174                         FlowBranching old = current_flow_branching;
175                         current_flow_branching = current_flow_branching.Parent;
176
177                         FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
178                         return vector.IsUnreachable;
179                 }
180
181                 // <summary>
182                 //   Kills the current code branching.  This throws away any changed state
183                 //   information and should only be used in case of an error.
184                 // </summary>
185                 // FIXME: this is evil
186                 public void KillFlowBranching ()
187                 {
188                         current_flow_branching = current_flow_branching.Parent;
189                 }
190
191                 //
192                 // This method is used during the Resolution phase to flag the
193                 // need to define the ReturnLabel
194                 //
195                 public void NeedReturnLabel ()
196                 {
197                         if (!HasReturnLabel)
198                                 HasReturnLabel = true;
199                 }
200
201                 public TypeSpec ReturnType {
202                         get { return return_type; }
203                 }
204         }
205
206         //
207         // Expression resolving context
208         //
209         public class ResolveContext : IMemberContext
210         {
211                 [Flags]
212                 public enum Options
213                 {
214                         /// <summary>
215                         ///   This flag tracks the `checked' state of the compilation,
216                         ///   it controls whether we should generate code that does overflow
217                         ///   checking, or if we generate code that ignores overflows.
218                         ///
219                         ///   The default setting comes from the command line option to generate
220                         ///   checked or unchecked code plus any source code changes using the
221                         ///   checked/unchecked statements or expressions.   Contrast this with
222                         ///   the ConstantCheckState flag.
223                         /// </summary>
224                         CheckedScope = 1 << 0,
225
226                         /// <summary>
227                         ///   The constant check state is always set to `true' and cant be changed
228                         ///   from the command line.  The source code can change this setting with
229                         ///   the `checked' and `unchecked' statements and expressions. 
230                         /// </summary>
231                         ConstantCheckState = 1 << 1,
232
233                         AllCheckStateFlags = CheckedScope | ConstantCheckState,
234
235                         //
236                         // unsafe { ... } scope
237                         //
238                         UnsafeScope = 1 << 2,
239                         CatchScope = 1 << 3,
240                         FinallyScope = 1 << 4,
241                         FieldInitializerScope = 1 << 5,
242                         CompoundAssignmentScope = 1 << 6,
243                         FixedInitializerScope = 1 << 7,
244                         BaseInitializer = 1 << 8,
245
246                         //
247                         // Inside an enum definition, we do not resolve enumeration values
248                         // to their enumerations, but rather to the underlying type/value
249                         // This is so EnumVal + EnumValB can be evaluated.
250                         //
251                         // There is no "E operator + (E x, E y)", so during an enum evaluation
252                         // we relax the rules
253                         //
254                         EnumScope = 1 << 9,
255
256                         ConstantScope = 1 << 10,
257
258                         ConstructorScope = 1 << 11,
259
260                         UsingInitializerScope = 1 << 12,
261
262                         /// <summary>
263                         ///   Whether control flow analysis is enabled
264                         /// </summary>
265                         DoFlowAnalysis = 1 << 20,
266
267                         /// <summary>
268                         ///   Whether control flow analysis is disabled on structs
269                         ///   (only meaningful when DoFlowAnalysis is set)
270                         /// </summary>
271                         OmitStructFlowAnalysis = 1 << 21,
272
273                         ///
274                         /// Indicates the current context is in probing mode, no errors are reported. 
275                         ///
276                         ProbingMode = 1 << 22,
277
278                         //
279                         // Return and ContextualReturn statements will set the ReturnType
280                         // value based on the expression types of each return statement
281                         // instead of the method return type which is initially null.
282                         //
283                         InferReturnType = 1 << 23,
284
285                         OmitDebuggingInfo = 1 << 24,
286
287                         ExpressionTreeConversion = 1 << 25,
288
289                         InvokeSpecialName = 1 << 26
290                 }
291
292                 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
293                 // it's public so that we can use a struct at the callsite
294                 public struct FlagsHandle : IDisposable
295                 {
296                         ResolveContext ec;
297                         readonly Options invmask, oldval;
298
299                         public FlagsHandle (ResolveContext ec, Options flagsToSet)
300                                 : this (ec, flagsToSet, flagsToSet)
301                         {
302                         }
303
304                         internal FlagsHandle (ResolveContext ec, Options mask, Options val)
305                         {
306                                 this.ec = ec;
307                                 invmask = ~mask;
308                                 oldval = ec.flags & mask;
309                                 ec.flags = (ec.flags & invmask) | (val & mask);
310
311 //                              if ((mask & Options.ProbingMode) != 0)
312 //                                      ec.Report.DisableReporting ();
313                         }
314
315                         public void Dispose ()
316                         {
317 //                              if ((invmask & Options.ProbingMode) == 0)
318 //                                      ec.Report.EnableReporting ();
319
320                                 ec.flags = (ec.flags & invmask) | oldval;
321                         }
322                 }
323
324                 protected Options flags;
325
326                 //
327                 // Whether we are inside an anonymous method.
328                 //
329                 public AnonymousExpression CurrentAnonymousMethod;
330
331                 //
332                 // Holds a varible used during collection or object initialization.
333                 //
334                 public Expression CurrentInitializerVariable;
335
336                 public Block CurrentBlock;
337
338                 public readonly IMemberContext MemberContext;
339
340                 /// <summary>
341                 ///   If this is non-null, points to the current switch statement
342                 /// </summary>
343                 public Switch Switch;
344
345                 public ResolveContext (IMemberContext mc)
346                 {
347                         if (mc == null)
348                                 throw new ArgumentNullException ();
349
350                         MemberContext = mc;
351
352                         //
353                         // The default setting comes from the command line option
354                         //
355                         if (RootContext.Checked)
356                                 flags |= Options.CheckedScope;
357
358                         //
359                         // The constant check state is always set to true
360                         //
361                         flags |= Options.ConstantCheckState;
362                 }
363
364                 public ResolveContext (IMemberContext mc, Options options)
365                         : this (mc)
366                 {
367                         flags |= options;
368                 }
369
370                 public CompilerContext Compiler {
371                         get { return MemberContext.Compiler; }
372                 }
373
374                 public virtual ExplicitBlock ConstructorBlock {
375                         get {
376                                 return CurrentBlock.Explicit;
377                         }
378                 }
379
380                 public virtual FlowBranching CurrentBranching {
381                         get { return null; }
382                 }
383
384                 //
385                 // The current iterator
386                 //
387                 public Iterator CurrentIterator {
388                         get { return CurrentAnonymousMethod as Iterator; }
389                 }
390
391                 public TypeSpec CurrentType {
392                         get { return MemberContext.CurrentType; }
393                 }
394
395                 public TypeParameter[] CurrentTypeParameters {
396                         get { return MemberContext.CurrentTypeParameters; }
397                 }
398
399                 public MemberCore CurrentMemberDefinition {
400                         get { return MemberContext.CurrentMemberDefinition; }
401                 }
402
403                 public bool ConstantCheckState {
404                         get { return (flags & Options.ConstantCheckState) != 0; }
405                 }
406
407                 public bool DoFlowAnalysis {
408                         get { return (flags & Options.DoFlowAnalysis) != 0; }
409                 }
410
411                 public bool HasUnresolvedConstraints {
412                         get { return false; }
413                 }
414
415                 public bool IsInProbingMode {
416                         get { return (flags & Options.ProbingMode) != 0; }
417                 }
418
419                 public bool IsVariableCapturingRequired {
420                         get {
421                                 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
422                         }
423                 }
424
425                 public ModuleContainer Module {
426                         get {
427                                 return MemberContext.Module;
428                         }
429                 }
430
431                 public bool OmitStructFlowAnalysis {
432                         get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
433                 }
434
435                 public bool MustCaptureVariable (INamedBlockVariable local)
436                 {
437                         if (CurrentAnonymousMethod == null)
438                                 return false;
439
440                         // FIXME: IsIterator is too aggressive, we should capture only if child
441                         // block contains yield
442                         if (CurrentAnonymousMethod.IsIterator)
443                                 return true;
444
445                         return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
446                 }
447
448                 public bool HasSet (Options options)
449                 {
450                         return (this.flags & options) == options;
451                 }
452
453                 public bool HasAny (Options options)
454                 {
455                         return (this.flags & options) != 0;
456                 }
457
458                 public Report Report {
459                         get {
460                                 return Compiler.Report;
461                         }
462                 }
463
464                 // Temporarily set all the given flags to the given value.  Should be used in an 'using' statement
465                 public FlagsHandle Set (Options options)
466                 {
467                         return new FlagsHandle (this, options);
468                 }
469
470                 public FlagsHandle With (Options options, bool enable)
471                 {
472                         return new FlagsHandle (this, options, enable ? options : 0);
473                 }
474
475                 #region IMemberContext Members
476
477                 public string GetSignatureForError ()
478                 {
479                         return MemberContext.GetSignatureForError ();
480                 }
481
482                 public bool IsObsolete {
483                         get {
484                                 // Disables obsolete checks when probing is on
485                                 return MemberContext.IsObsolete;
486                         }
487                 }
488
489                 public bool IsStatic {
490                         get { return MemberContext.IsStatic; }
491                 }
492
493                 public bool IsUnsafe {
494                         get { return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe; }
495                 }
496
497                 public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
498                 {
499                         return MemberContext.LookupExtensionMethod (extensionType, name, arity, ref scope);
500                 }
501
502                 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
503                 {
504                         return MemberContext.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
505                 }
506
507                 public FullNamedExpression LookupNamespaceAlias (string name)
508                 {
509                         return MemberContext.LookupNamespaceAlias (name);
510                 }
511
512                 #endregion
513         }
514
515         //
516         // This class is used during the Statement.Clone operation
517         // to remap objects that have been cloned.
518         //
519         // Since blocks are cloned by Block.Clone, we need a way for
520         // expressions that must reference the block to be cloned
521         // pointing to the new cloned block.
522         //
523         public class CloneContext
524         {
525                 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
526
527                 public void AddBlockMap (Block from, Block to)
528                 {
529                         block_map.Add (from, to);
530                 }
531
532                 public Block LookupBlock (Block from)
533                 {
534                         Block result;
535                         if (!block_map.TryGetValue (from, out result)) {
536                                 result = (Block) from.Clone (this);
537                         }
538
539                         return result;
540                 }
541
542                 ///
543                 /// Remaps block to cloned copy if one exists.
544                 ///
545                 public Block RemapBlockCopy (Block from)
546                 {
547                         Block mapped_to;
548                         if (!block_map.TryGetValue (from, out mapped_to))
549                                 return from;
550
551                         return mapped_to;
552                 }
553         }
554
555         //
556         // Main compiler context
557         //
558         public class CompilerContext
559         {
560                 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
561
562                 readonly Report report;
563                 readonly BuildinTypes buildin_types;
564
565                 public CompilerContext (Report report)
566                 {
567                         this.report = report;
568                         this.buildin_types = new BuildinTypes ();
569                         this.TimeReporter = DisabledTimeReporter;
570                 }
571
572                 #region Properties
573
574                 public BuildinTypes BuildinTypes {
575                         get {
576                                 return buildin_types;
577                         }
578                 }
579
580                 public bool IsRuntimeBinder { get; set; }
581
582                 public Report Report {
583                         get {
584                                 return report;
585                         }
586                 }
587
588                 internal TimeReporter TimeReporter { get; set; }
589
590                 #endregion
591         }
592
593         //
594         // Generic code emitter context
595         //
596         public class BuilderContext
597         {
598                 [Flags]
599                 public enum Options
600                 {
601                         /// <summary>
602                         ///   This flag tracks the `checked' state of the compilation,
603                         ///   it controls whether we should generate code that does overflow
604                         ///   checking, or if we generate code that ignores overflows.
605                         ///
606                         ///   The default setting comes from the command line option to generate
607                         ///   checked or unchecked code plus any source code changes using the
608                         ///   checked/unchecked statements or expressions.   Contrast this with
609                         ///   the ConstantCheckState flag.
610                         /// </summary>
611                         CheckedScope = 1 << 0,
612
613                         /// <summary>
614                         ///   The constant check state is always set to `true' and cant be changed
615                         ///   from the command line.  The source code can change this setting with
616                         ///   the `checked' and `unchecked' statements and expressions. 
617                         /// </summary>
618                         ConstantCheckState = 1 << 1,
619
620                         AllCheckStateFlags = CheckedScope | ConstantCheckState,
621
622                         OmitDebugInfo = 1 << 2,
623
624                         ConstructorScope = 1 << 3
625                 }
626
627                 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
628                 // it's public so that we can use a struct at the callsite
629                 public struct FlagsHandle : IDisposable
630                 {
631                         BuilderContext ec;
632                         readonly Options invmask, oldval;
633
634                         public FlagsHandle (BuilderContext ec, Options flagsToSet)
635                                 : this (ec, flagsToSet, flagsToSet)
636                         {
637                         }
638
639                         internal FlagsHandle (BuilderContext ec, Options mask, Options val)
640                         {
641                                 this.ec = ec;
642                                 invmask = ~mask;
643                                 oldval = ec.flags & mask;
644                                 ec.flags = (ec.flags & invmask) | (val & mask);
645                         }
646
647                         public void Dispose ()
648                         {
649                                 ec.flags = (ec.flags & invmask) | oldval;
650                         }
651                 }
652
653                 Options flags;
654
655                 public bool HasSet (Options options)
656                 {
657                         return (this.flags & options) == options;
658                 }
659
660                 // Temporarily set all the given flags to the given value.  Should be used in an 'using' statement
661                 public FlagsHandle With (Options options, bool enable)
662                 {
663                         return new FlagsHandle (this, options, enable ? options : 0);
664                 }
665         }
666 }