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