Update mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng/RelaxngPattern.cs
[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 // Copyright 2011 Xamarin Inc.
11 //
12
13 using System;
14 using System.Collections.Generic;
15 using System.IO;
16 using System.Security.Cryptography;
17
18 namespace Mono.CSharp
19 {
20         public enum LookupMode
21         {
22                 Normal = 0,
23                 Probing = 1,
24                 IgnoreAccessibility = 2
25         }
26
27         //
28         // Implemented by elements which can act as independent contexts
29         // during resolve phase. Used mostly for lookups.
30         //
31         public interface IMemberContext : IModuleContext
32         {
33                 //
34                 // A scope type context, it can be inflated for generic types
35                 //
36                 TypeSpec CurrentType { get; }
37
38                 //
39                 // A scope type parameters either VAR or MVAR
40                 //
41                 TypeParameters CurrentTypeParameters { get; }
42
43                 //
44                 // A member definition of the context. For partial types definition use
45                 // CurrentTypeDefinition.PartialContainer otherwise the context is local
46                 //
47                 // TODO: Obsolete it in this context, dynamic context cannot guarantee sensible value
48                 //
49                 MemberCore CurrentMemberDefinition { get; }
50
51                 bool IsObsolete { get; }
52                 bool IsUnsafe { get; }
53                 bool IsStatic { get; }
54
55                 string GetSignatureForError ();
56
57                 ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity);
58                 FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc);
59                 FullNamedExpression LookupNamespaceAlias (string name);
60         }
61
62         public interface IModuleContext
63         {
64                 ModuleContainer Module { get; }
65         }
66
67         //
68         // Block or statement resolving context
69         //
70         public class BlockContext : ResolveContext
71         {
72                 FlowBranching current_flow_branching;
73
74                 readonly TypeSpec return_type;
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                 public TypeSpec ReturnType {
105                         get { return return_type; }
106                 }
107
108                 // <summary>
109                 //   Starts a new code branching.  This inherits the state of all local
110                 //   variables and parameters from the current branching.
111                 // </summary>
112                 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
113                 {
114                         current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
115                         return current_flow_branching;
116                 }
117
118                 // <summary>
119                 //   Starts a new code branching for block `block'.
120                 // </summary>
121                 public FlowBranching StartFlowBranching (Block block)
122                 {
123                         Set (Options.DoFlowAnalysis);
124
125                         current_flow_branching = FlowBranching.CreateBranching (
126                                 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
127                         return current_flow_branching;
128                 }
129
130                 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
131                 {
132                         FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
133                         current_flow_branching = branching;
134                         return branching;
135                 }
136
137                 public FlowBranchingTryFinally StartFlowBranching (TryFinallyBlock stmt)
138                 {
139                         FlowBranchingTryFinally branching = new FlowBranchingTryFinally (CurrentBranching, stmt);
140                         current_flow_branching = branching;
141                         return branching;
142                 }
143
144                 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
145                 {
146                         FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
147                         current_flow_branching = branching;
148                         return branching;
149                 }
150
151                 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
152                 {
153                         FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
154                         current_flow_branching = branching;
155                         return branching;
156                 }
157
158                 public FlowBranchingAsync StartFlowBranching (AsyncInitializer asyncBody, FlowBranching parent)
159                 {
160                         var branching = new FlowBranchingAsync (parent, asyncBody);
161                         current_flow_branching = branching;
162                         return branching;
163                 }
164
165                 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
166                 {
167                         FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
168                         current_flow_branching = branching;
169                         return branching;
170                 }
171
172                 // <summary>
173                 //   Ends a code branching.  Merges the state of locals and parameters
174                 //   from all the children of the ending branching.
175                 // </summary>
176                 public bool EndFlowBranching ()
177                 {
178                         FlowBranching old = current_flow_branching;
179                         current_flow_branching = current_flow_branching.Parent;
180
181                         FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
182                         return vector.IsUnreachable;
183                 }
184
185                 // <summary>
186                 //   Kills the current code branching.  This throws away any changed state
187                 //   information and should only be used in case of an error.
188                 // </summary>
189                 // FIXME: this is evil
190                 public void KillFlowBranching ()
191                 {
192                         current_flow_branching = current_flow_branching.Parent;
193                 }
194
195 #if !STATIC
196                 public void NeedReturnLabel ()
197                 {
198                 }
199 #endif
200         }
201
202         //
203         // Expression resolving context
204         //
205         public class ResolveContext : IMemberContext
206         {
207                 [Flags]
208                 public enum Options
209                 {
210                         /// <summary>
211                         ///   This flag tracks the `checked' state of the compilation,
212                         ///   it controls whether we should generate code that does overflow
213                         ///   checking, or if we generate code that ignores overflows.
214                         ///
215                         ///   The default setting comes from the command line option to generate
216                         ///   checked or unchecked code plus any source code changes using the
217                         ///   checked/unchecked statements or expressions.   Contrast this with
218                         ///   the ConstantCheckState flag.
219                         /// </summary>
220                         CheckedScope = 1 << 0,
221
222                         /// <summary>
223                         ///   The constant check state is always set to `true' and cant be changed
224                         ///   from the command line.  The source code can change this setting with
225                         ///   the `checked' and `unchecked' statements and expressions. 
226                         /// </summary>
227                         ConstantCheckState = 1 << 1,
228
229                         AllCheckStateFlags = CheckedScope | ConstantCheckState,
230
231                         //
232                         // unsafe { ... } scope
233                         //
234                         UnsafeScope = 1 << 2,
235                         CatchScope = 1 << 3,
236                         FinallyScope = 1 << 4,
237                         FieldInitializerScope = 1 << 5,
238                         CompoundAssignmentScope = 1 << 6,
239                         FixedInitializerScope = 1 << 7,
240                         BaseInitializer = 1 << 8,
241
242                         //
243                         // Inside an enum definition, we do not resolve enumeration values
244                         // to their enumerations, but rather to the underlying type/value
245                         // This is so EnumVal + EnumValB can be evaluated.
246                         //
247                         // There is no "E operator + (E x, E y)", so during an enum evaluation
248                         // we relax the rules
249                         //
250                         EnumScope = 1 << 9,
251
252                         ConstantScope = 1 << 10,
253
254                         ConstructorScope = 1 << 11,
255
256                         UsingInitializerScope = 1 << 12,
257
258                         LockScope = 1 << 13,
259
260                         /// <summary>
261                         ///   Whether control flow analysis is enabled
262                         /// </summary>
263                         DoFlowAnalysis = 1 << 20,
264
265                         /// <summary>
266                         ///   Whether control flow analysis is disabled on structs
267                         ///   (only meaningful when DoFlowAnalysis is set)
268                         /// </summary>
269                         OmitStructFlowAnalysis = 1 << 21,
270
271                         ///
272                         /// Indicates the current context is in probing mode, no errors are reported. 
273                         ///
274                         ProbingMode = 1 << 22,
275
276                         //
277                         // Return and ContextualReturn statements will set the ReturnType
278                         // value based on the expression types of each return statement
279                         // instead of the method return type which is initially null.
280                         //
281                         InferReturnType = 1 << 23,
282
283                         OmitDebuggingInfo = 1 << 24,
284
285                         ExpressionTreeConversion = 1 << 25,
286
287                         InvokeSpecialName = 1 << 26
288                 }
289
290                 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
291                 // it's public so that we can use a struct at the callsite
292                 public struct FlagsHandle : IDisposable
293                 {
294                         ResolveContext ec;
295                         readonly Options invmask, oldval;
296
297                         public FlagsHandle (ResolveContext ec, Options flagsToSet)
298                                 : this (ec, flagsToSet, flagsToSet)
299                         {
300                         }
301
302                         internal FlagsHandle (ResolveContext ec, Options mask, Options val)
303                         {
304                                 this.ec = ec;
305                                 invmask = ~mask;
306                                 oldval = ec.flags & mask;
307                                 ec.flags = (ec.flags & invmask) | (val & mask);
308
309 //                              if ((mask & Options.ProbingMode) != 0)
310 //                                      ec.Report.DisableReporting ();
311                         }
312
313                         public void Dispose ()
314                         {
315 //                              if ((invmask & Options.ProbingMode) == 0)
316 //                                      ec.Report.EnableReporting ();
317
318                                 ec.flags = (ec.flags & invmask) | oldval;
319                         }
320                 }
321
322                 protected Options flags;
323
324                 //
325                 // Whether we are inside an anonymous method.
326                 //
327                 public AnonymousExpression CurrentAnonymousMethod;
328
329                 //
330                 // Holds a varible used during collection or object initialization.
331                 //
332                 public Expression CurrentInitializerVariable;
333
334                 public Block CurrentBlock;
335
336                 public readonly IMemberContext MemberContext;
337
338                 /// <summary>
339                 ///   If this is non-null, points to the current switch statement
340                 /// </summary>
341                 public Switch Switch;
342
343                 public ResolveContext (IMemberContext mc)
344                 {
345                         if (mc == null)
346                                 throw new ArgumentNullException ();
347
348                         MemberContext = mc;
349
350                         //
351                         // The default setting comes from the command line option
352                         //
353                         if (mc.Module.Compiler.Settings.Checked)
354                                 flags |= Options.CheckedScope;
355
356                         //
357                         // The constant check state is always set to true
358                         //
359                         flags |= Options.ConstantCheckState;
360                 }
361
362                 public ResolveContext (IMemberContext mc, Options options)
363                         : this (mc)
364                 {
365                         flags |= options;
366                 }
367
368                 #region Properties
369
370                 public BuiltinTypes BuiltinTypes {
371                         get {
372                                 return MemberContext.Module.Compiler.BuiltinTypes;
373                         }
374                 }
375
376                 public virtual ExplicitBlock ConstructorBlock {
377                         get {
378                                 return CurrentBlock.Explicit;
379                         }
380                 }
381
382                 public virtual FlowBranching CurrentBranching {
383                         get { return null; }
384                 }
385
386                 //
387                 // The current iterator
388                 //
389                 public Iterator CurrentIterator {
390                         get { return CurrentAnonymousMethod as Iterator; }
391                 }
392
393                 public TypeSpec CurrentType {
394                         get { return MemberContext.CurrentType; }
395                 }
396
397                 public TypeParameters CurrentTypeParameters {
398                         get { return MemberContext.CurrentTypeParameters; }
399                 }
400
401                 public MemberCore CurrentMemberDefinition {
402                         get { return MemberContext.CurrentMemberDefinition; }
403                 }
404
405                 public bool ConstantCheckState {
406                         get { return (flags & Options.ConstantCheckState) != 0; }
407                 }
408
409                 public bool DoFlowAnalysis {
410                         get { return (flags & Options.DoFlowAnalysis) != 0; }
411                 }
412
413                 public bool IsInProbingMode {
414                         get {
415                                 return (flags & Options.ProbingMode) != 0;
416                         }
417                 }
418
419                 public bool IsObsolete {
420                         get {
421                                 // Disables obsolete checks when probing is on
422                                 return MemberContext.IsObsolete;
423                         }
424                 }
425
426                 public bool IsStatic {
427                         get {
428                                 return MemberContext.IsStatic;
429                         }
430                 }
431
432                 public bool IsUnsafe {
433                         get {
434                                 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
435                         }
436                 }
437
438                 public bool IsRuntimeBinder {
439                         get {
440                                 return Module.Compiler.IsRuntimeBinder;
441                         }
442                 }
443
444                 public bool IsVariableCapturingRequired {
445                         get {
446                                 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
447                         }
448                 }
449
450                 public ModuleContainer Module {
451                         get {
452                                 return MemberContext.Module;
453                         }
454                 }
455
456                 public bool OmitStructFlowAnalysis {
457                         get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
458                 }
459
460                 public Report Report {
461                         get {
462                                 return Module.Compiler.Report;
463                         }
464                 }
465
466                 #endregion
467
468                 public bool MustCaptureVariable (INamedBlockVariable local)
469                 {
470                         if (CurrentAnonymousMethod == null)
471                                 return false;
472
473                         //
474                         // Capture only if this or any of child blocks contain yield
475                         // or it's a parameter
476                         //
477                         if (CurrentAnonymousMethod.IsIterator)
478                                 return local.IsParameter || CurrentBlock.Explicit.HasYield;
479
480                         //
481                         // Capture only if this or any of child blocks contain await
482                         // or it's a parameter
483                         //
484                         if (CurrentAnonymousMethod is AsyncInitializer)
485                                 return local.IsParameter || CurrentBlock.Explicit.HasAwait;
486
487                         return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
488                 }
489
490                 public bool HasSet (Options options)
491                 {
492                         return (this.flags & options) == options;
493                 }
494
495                 public bool HasAny (Options options)
496                 {
497                         return (this.flags & options) != 0;
498                 }
499
500
501                 // Temporarily set all the given flags to the given value.  Should be used in an 'using' statement
502                 public FlagsHandle Set (Options options)
503                 {
504                         return new FlagsHandle (this, options);
505                 }
506
507                 public FlagsHandle With (Options options, bool enable)
508                 {
509                         return new FlagsHandle (this, options, enable ? options : 0);
510                 }
511
512                 #region IMemberContext Members
513
514                 public string GetSignatureForError ()
515                 {
516                         return MemberContext.GetSignatureForError ();
517                 }
518
519                 public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
520                 {
521                         return MemberContext.LookupExtensionMethod (extensionType, name, arity);
522                 }
523
524                 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
525                 {
526                         return MemberContext.LookupNamespaceOrType (name, arity, mode, loc);
527                 }
528
529                 public FullNamedExpression LookupNamespaceAlias (string name)
530                 {
531                         return MemberContext.LookupNamespaceAlias (name);
532                 }
533
534                 #endregion
535         }
536
537         //
538         // This class is used during the Statement.Clone operation
539         // to remap objects that have been cloned.
540         //
541         // Since blocks are cloned by Block.Clone, we need a way for
542         // expressions that must reference the block to be cloned
543         // pointing to the new cloned block.
544         //
545         public class CloneContext
546         {
547                 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
548
549                 public void AddBlockMap (Block from, Block to)
550                 {
551                         block_map.Add (from, to);
552                 }
553
554                 public Block LookupBlock (Block from)
555                 {
556                         Block result;
557                         if (!block_map.TryGetValue (from, out result)) {
558                                 result = (Block) from.Clone (this);
559                         }
560
561                         return result;
562                 }
563
564                 ///
565                 /// Remaps block to cloned copy if one exists.
566                 ///
567                 public Block RemapBlockCopy (Block from)
568                 {
569                         Block mapped_to;
570                         if (!block_map.TryGetValue (from, out mapped_to))
571                                 return from;
572
573                         return mapped_to;
574                 }
575         }
576
577         //
578         // Main compiler context
579         //
580         public class CompilerContext
581         {
582                 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
583
584                 readonly Report report;
585                 readonly BuiltinTypes builtin_types;
586                 readonly CompilerSettings settings;
587
588                 Dictionary<string, SourceFile> all_source_files;
589
590                 public CompilerContext (CompilerSettings settings, ReportPrinter reportPrinter)
591                 {
592                         this.settings = settings;
593                         this.report = new Report (this, reportPrinter);
594                         this.builtin_types = new BuiltinTypes ();
595                         this.TimeReporter = DisabledTimeReporter;
596                 }
597
598                 #region Properties
599
600                 public BuiltinTypes BuiltinTypes {
601                         get {
602                                 return builtin_types;
603                         }
604                 }
605
606                 // Used for special handling of runtime dynamic context mostly
607                 // by error reporting but also by member accessibility checks
608                 public bool IsRuntimeBinder {
609                         get; set;
610                 }
611
612                 public Report Report {
613                         get {
614                                 return report;
615                         }
616                 }
617
618                 public CompilerSettings Settings {
619                         get {
620                                 return settings;
621                         }
622                 }
623
624                 public List<SourceFile> SourceFiles {
625                         get {
626                                 return settings.SourceFiles;
627                         }
628                 }
629
630                 internal TimeReporter TimeReporter {
631                         get; set;
632                 }
633
634                 #endregion
635
636                 //
637                 // This is used when we encounter a #line preprocessing directive during parsing
638                 // to register additional source file names
639                 //
640                 public SourceFile LookupFile (CompilationSourceFile comp_unit, string name)
641                 {
642                         if (all_source_files == null) {
643                                 all_source_files = new Dictionary<string, SourceFile> ();
644                                 foreach (var source in SourceFiles)
645                                         all_source_files[source.FullPathName] = source;
646                         }
647
648                         string path;
649                         if (!Path.IsPathRooted (name)) {
650                                 string root = Path.GetDirectoryName (comp_unit.SourceFile.FullPathName);
651                                 path = Path.Combine (root, name);
652                         } else
653                                 path = name;
654
655                         SourceFile retval;
656                         if (all_source_files.TryGetValue (path, out retval))
657                                 return retval;
658
659                         retval = new SourceFile (name, path, all_source_files.Count + 1);
660                         Location.AddFile (retval);
661                         all_source_files.Add (path, retval);
662                         return retval;
663                 }
664         }
665
666         //
667         // Generic code emitter context
668         //
669         public class BuilderContext
670         {
671                 [Flags]
672                 public enum Options
673                 {
674                         /// <summary>
675                         ///   This flag tracks the `checked' state of the compilation,
676                         ///   it controls whether we should generate code that does overflow
677                         ///   checking, or if we generate code that ignores overflows.
678                         ///
679                         ///   The default setting comes from the command line option to generate
680                         ///   checked or unchecked code plus any source code changes using the
681                         ///   checked/unchecked statements or expressions.   Contrast this with
682                         ///   the ConstantCheckState flag.
683                         /// </summary>
684                         CheckedScope = 1 << 0,
685
686                         AccurateDebugInfo = 1 << 1,
687
688                         OmitDebugInfo = 1 << 2,
689
690                         ConstructorScope = 1 << 3,
691
692                         AsyncBody = 1 << 4
693                 }
694
695                 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
696                 // it's public so that we can use a struct at the callsite
697                 public struct FlagsHandle : IDisposable
698                 {
699                         BuilderContext ec;
700                         readonly Options invmask, oldval;
701
702                         public FlagsHandle (BuilderContext ec, Options flagsToSet)
703                                 : this (ec, flagsToSet, flagsToSet)
704                         {
705                         }
706
707                         internal FlagsHandle (BuilderContext ec, Options mask, Options val)
708                         {
709                                 this.ec = ec;
710                                 invmask = ~mask;
711                                 oldval = ec.flags & mask;
712                                 ec.flags = (ec.flags & invmask) | (val & mask);
713                         }
714
715                         public void Dispose ()
716                         {
717                                 ec.flags = (ec.flags & invmask) | oldval;
718                         }
719                 }
720
721                 protected Options flags;
722
723                 public bool HasSet (Options options)
724                 {
725                         return (this.flags & options) == options;
726                 }
727
728                 // Temporarily set all the given flags to the given value.  Should be used in an 'using' statement
729                 public FlagsHandle With (Options options, bool enable)
730                 {
731                         return new FlagsHandle (this, options, enable ? options : 0);
732                 }
733         }
734
735         //
736         // Parser session objects. We could recreate all these objects for each parser
737         // instance but the best parser performance the session object can be reused
738         //
739         public class ParserSession
740         {
741                 MD5 md5;
742
743                 public readonly char[] StreamReaderBuffer = new char[SeekableStreamReader.DefaultReadAheadSize * 2];
744                 public readonly Dictionary<char[], string>[] Identifiers = new Dictionary<char[], string>[Tokenizer.MaxIdentifierLength + 1];
745                 public readonly List<Parameter> ParametersStack = new List<Parameter> (4);
746                 public readonly char[] IDBuilder = new char[Tokenizer.MaxIdentifierLength];
747                 public readonly char[] NumberBuilder = new char[Tokenizer.MaxNumberLength];
748
749                 public LocationsBag LocationsBag { get; set; }
750                 public bool UseJayGlobalArrays { get; set; }
751                 public Tokenizer.LocatedToken[] LocatedTokens { get; set; }
752
753                 public MD5 GetChecksumAlgorithm ()
754                 {
755                         return md5 ?? (md5 = MD5.Create ());
756                 }
757         }
758 }