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