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