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