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