2 // context.cs: Various compiler contexts.
5 // Marek Safar (marek.safar@gmail.com)
6 // Miguel de Icaza (miguel@ximian.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2004-2009 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using System.Security.Cryptography;
20 public enum LookupMode
24 IgnoreAccessibility = 2
28 // Implemented by elements which can act as independent contexts
29 // during resolve phase. Used mostly for lookups.
31 public interface IMemberContext : IModuleContext
34 // A scope type context, it can be inflated for generic types
36 TypeSpec CurrentType { get; }
39 // A scope type parameters either VAR or MVAR
41 TypeParameters CurrentTypeParameters { get; }
44 // A member definition of the context. For partial types definition use
45 // CurrentTypeDefinition.PartialContainer otherwise the context is local
47 // TODO: Obsolete it in this context, dynamic context cannot guarantee sensible value
49 MemberCore CurrentMemberDefinition { get; }
51 bool IsObsolete { get; }
52 bool IsUnsafe { get; }
53 bool IsStatic { get; }
55 string GetSignatureForError ();
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);
62 public interface IModuleContext
64 ModuleContainer Module { get; }
68 // Block or statement resolving context
70 public class BlockContext : ResolveContext
72 FlowBranching current_flow_branching;
74 readonly TypeSpec return_type;
77 // Tracks the last offset used by VariableInfo
79 public int AssignmentInfoOffset;
81 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
84 if (returnType == null)
85 throw new ArgumentNullException ("returnType");
87 this.return_type = returnType;
89 // TODO: check for null value
93 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
94 : this (rc.MemberContext, block, returnType)
97 flags |= ResolveContext.Options.UnsafeScope;
99 if (rc.HasSet (ResolveContext.Options.CheckedScope))
100 flags |= ResolveContext.Options.CheckedScope;
102 if (rc.IsInProbingMode)
103 flags |= ResolveContext.Options.ProbingMode;
105 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
106 flags |= ResolveContext.Options.FieldInitializerScope;
108 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
109 flags |= ResolveContext.Options.ExpressionTreeConversion;
111 if (rc.HasSet (ResolveContext.Options.BaseInitializer))
112 flags |= ResolveContext.Options.BaseInitializer;
115 public override FlowBranching CurrentBranching {
116 get { return current_flow_branching; }
119 public TypeSpec ReturnType {
120 get { return return_type; }
123 public bool IsUnreachable {
125 return HasSet (Options.UnreachableScope);
128 flags = value ? flags | Options.UnreachableScope : flags & ~Options.UnreachableScope;
132 public bool UnreachableReported {
134 return HasSet (Options.UnreachableReported);
137 flags = value ? flags | Options.UnreachableReported : flags & ~Options.UnreachableScope;
142 // Starts a new code branching. This inherits the state of all local
143 // variables and parameters from the current branching.
145 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
147 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
148 return current_flow_branching;
152 // Starts a new code branching for block `block'.
154 public FlowBranching StartFlowBranching (Block block)
156 Set (Options.DoFlowAnalysis);
158 current_flow_branching = FlowBranching.CreateBranching (
159 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
160 return current_flow_branching;
163 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
165 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
166 current_flow_branching = branching;
170 public FlowBranchingTryFinally StartFlowBranching (TryFinallyBlock stmt)
172 FlowBranchingTryFinally branching = new FlowBranchingTryFinally (CurrentBranching, stmt);
173 current_flow_branching = branching;
177 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
179 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
180 current_flow_branching = branching;
184 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
186 FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
187 current_flow_branching = branching;
191 public FlowBranchingAsync StartFlowBranching (AsyncInitializer asyncBody, FlowBranching parent)
193 var branching = new FlowBranchingAsync (parent, asyncBody);
194 current_flow_branching = branching;
198 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
200 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
201 current_flow_branching = branching;
206 // Ends a code branching. Merges the state of locals and parameters
207 // from all the children of the ending branching.
209 public bool EndFlowBranching ()
211 FlowBranching old = current_flow_branching;
212 current_flow_branching = current_flow_branching.Parent;
214 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
215 return vector.IsUnreachable;
219 // Kills the current code branching. This throws away any changed state
220 // information and should only be used in case of an error.
222 // FIXME: this is evil
223 public void KillFlowBranching ()
225 current_flow_branching = current_flow_branching.Parent;
229 public void NeedReturnLabel ()
236 // Expression resolving context
238 public class ResolveContext : IMemberContext
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.
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.
253 CheckedScope = 1 << 0,
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.
260 ConstantCheckState = 1 << 1,
262 AllCheckStateFlags = CheckedScope | ConstantCheckState,
265 // unsafe { ... } scope
267 UnsafeScope = 1 << 2,
269 FinallyScope = 1 << 4,
270 FieldInitializerScope = 1 << 5,
271 CompoundAssignmentScope = 1 << 6,
272 FixedInitializerScope = 1 << 7,
273 BaseInitializer = 1 << 8,
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.
280 // There is no "E operator + (E x, E y)", so during an enum evaluation
281 // we relax the rules
285 ConstantScope = 1 << 10,
287 ConstructorScope = 1 << 11,
289 UsingInitializerScope = 1 << 12,
293 UnreachableScope = 1 << 14,
295 UnreachableReported = 1 << 15,
298 /// Whether control flow analysis is enabled
300 DoFlowAnalysis = 1 << 20,
303 /// Whether control flow analysis is disabled on structs
304 /// (only meaningful when DoFlowAnalysis is set)
306 OmitStructFlowAnalysis = 1 << 21,
309 /// Indicates the current context is in probing mode, no errors are reported.
311 ProbingMode = 1 << 22,
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.
318 InferReturnType = 1 << 23,
320 OmitDebuggingInfo = 1 << 24,
322 ExpressionTreeConversion = 1 << 25,
324 InvokeSpecialName = 1 << 26
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
331 readonly ResolveContext ec;
332 readonly Options invmask, oldval;
334 public FlagsHandle (ResolveContext ec, Options flagsToSet)
335 : this (ec, flagsToSet, flagsToSet)
339 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
343 oldval = ec.flags & mask;
344 ec.flags = (ec.flags & invmask) | (val & mask);
346 // if ((mask & Options.ProbingMode) != 0)
347 // ec.Report.DisableReporting ();
350 public void Dispose ()
352 // if ((invmask & Options.ProbingMode) == 0)
353 // ec.Report.EnableReporting ();
355 ec.flags = (ec.flags & invmask) | oldval;
359 protected Options flags;
362 // Whether we are inside an anonymous method.
364 public AnonymousExpression CurrentAnonymousMethod;
367 // Holds a varible used during collection or object initialization.
369 public Expression CurrentInitializerVariable;
371 public Block CurrentBlock;
373 public readonly IMemberContext MemberContext;
376 /// If this is non-null, points to the current switch statement
378 public Switch Switch;
380 public ResolveContext (IMemberContext mc)
383 throw new ArgumentNullException ();
388 // The default setting comes from the command line option
390 if (mc.Module.Compiler.Settings.Checked)
391 flags |= Options.CheckedScope;
394 // The constant check state is always set to true
396 flags |= Options.ConstantCheckState;
399 public ResolveContext (IMemberContext mc, Options options)
407 public BuiltinTypes BuiltinTypes {
409 return MemberContext.Module.Compiler.BuiltinTypes;
413 public virtual ExplicitBlock ConstructorBlock {
415 return CurrentBlock.Explicit;
419 public virtual FlowBranching CurrentBranching {
424 // The current iterator
426 public Iterator CurrentIterator {
427 get { return CurrentAnonymousMethod as Iterator; }
430 public TypeSpec CurrentType {
431 get { return MemberContext.CurrentType; }
434 public TypeParameters CurrentTypeParameters {
435 get { return MemberContext.CurrentTypeParameters; }
438 public MemberCore CurrentMemberDefinition {
439 get { return MemberContext.CurrentMemberDefinition; }
442 public bool ConstantCheckState {
443 get { return (flags & Options.ConstantCheckState) != 0; }
446 public bool DoFlowAnalysis {
447 get { return (flags & Options.DoFlowAnalysis) != 0; }
450 public bool IsInProbingMode {
452 return (flags & Options.ProbingMode) != 0;
456 public bool IsObsolete {
458 // Disables obsolete checks when probing is on
459 return MemberContext.IsObsolete;
463 public bool IsStatic {
465 return MemberContext.IsStatic;
469 public bool IsUnsafe {
471 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
475 public bool IsRuntimeBinder {
477 return Module.Compiler.IsRuntimeBinder;
481 public bool IsVariableCapturingRequired {
483 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
487 public ModuleContainer Module {
489 return MemberContext.Module;
493 public bool OmitStructFlowAnalysis {
494 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
497 public Report Report {
499 return Module.Compiler.Report;
505 public bool MustCaptureVariable (INamedBlockVariable local)
507 if (CurrentAnonymousMethod == null)
511 // Capture only if this or any of child blocks contain yield
512 // or it's a parameter
514 if (CurrentAnonymousMethod.IsIterator)
515 return local.IsParameter || local.Block.Explicit.HasYield;
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
522 if (CurrentAnonymousMethod is AsyncInitializer)
523 return local.IsParameter || local.Block.Explicit.HasAwait || CurrentBlock.Explicit.HasAwait ||
524 local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
526 return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
529 public bool HasSet (Options options)
531 return (this.flags & options) == options;
534 public bool HasAny (Options options)
536 return (this.flags & options) != 0;
540 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
541 public FlagsHandle Set (Options options)
543 return new FlagsHandle (this, options);
546 public FlagsHandle With (Options options, bool enable)
548 return new FlagsHandle (this, options, enable ? options : 0);
551 #region IMemberContext Members
553 public string GetSignatureForError ()
555 return MemberContext.GetSignatureForError ();
558 public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
560 return MemberContext.LookupExtensionMethod (extensionType, name, arity);
563 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
565 return MemberContext.LookupNamespaceOrType (name, arity, mode, loc);
568 public FullNamedExpression LookupNamespaceAlias (string name)
570 return MemberContext.LookupNamespaceAlias (name);
577 // This class is used during the Statement.Clone operation
578 // to remap objects that have been cloned.
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.
584 public class CloneContext
586 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
588 public void AddBlockMap (Block from, Block to)
590 block_map.Add (from, to);
593 public Block LookupBlock (Block from)
596 if (!block_map.TryGetValue (from, out result)) {
597 result = (Block) from.Clone (this);
604 /// Remaps block to cloned copy if one exists.
606 public Block RemapBlockCopy (Block from)
609 if (!block_map.TryGetValue (from, out mapped_to))
617 // Main compiler context
619 public class CompilerContext
621 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
623 readonly Report report;
624 readonly BuiltinTypes builtin_types;
625 readonly CompilerSettings settings;
627 Dictionary<string, SourceFile> all_source_files;
629 public CompilerContext (CompilerSettings settings, ReportPrinter reportPrinter)
631 this.settings = settings;
632 this.report = new Report (this, reportPrinter);
633 this.builtin_types = new BuiltinTypes ();
634 this.TimeReporter = DisabledTimeReporter;
639 public BuiltinTypes BuiltinTypes {
641 return builtin_types;
645 // Used for special handling of runtime dynamic context mostly
646 // by error reporting but also by member accessibility checks
647 public bool IsRuntimeBinder {
651 public Report Report {
657 public CompilerSettings Settings {
663 public List<SourceFile> SourceFiles {
665 return settings.SourceFiles;
669 internal TimeReporter TimeReporter {
676 // This is used when we encounter a #line preprocessing directive during parsing
677 // to register additional source file names
679 public SourceFile LookupFile (CompilationSourceFile comp_unit, string name)
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;
688 if (!Path.IsPathRooted (name)) {
689 string root = Path.GetDirectoryName (comp_unit.SourceFile.FullPathName);
690 path = Path.Combine (root, name);
695 if (all_source_files.TryGetValue (path, out retval))
698 retval = new SourceFile (name, path, all_source_files.Count + 1);
699 Location.AddFile (retval);
700 all_source_files.Add (path, retval);
706 // Generic code emitter context
708 public class BuilderContext
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.
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.
723 CheckedScope = 1 << 0,
725 AccurateDebugInfo = 1 << 1,
727 OmitDebugInfo = 1 << 2,
729 ConstructorScope = 1 << 3,
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
738 readonly BuilderContext ec;
739 readonly Options invmask, oldval;
741 public FlagsHandle (BuilderContext ec, Options flagsToSet)
742 : this (ec, flagsToSet, flagsToSet)
746 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
750 oldval = ec.flags & mask;
751 ec.flags = (ec.flags & invmask) | (val & mask);
754 public void Dispose ()
756 ec.flags = (ec.flags & invmask) | oldval;
760 protected Options flags;
762 public bool HasSet (Options options)
764 return (this.flags & options) == options;
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)
770 return new FlagsHandle (this, options, enable ? options : 0);
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
778 public class ParserSession
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];
788 public LocationsBag LocationsBag { get; set; }
789 public bool UseJayGlobalArrays { get; set; }
790 public LocatedToken[] LocatedTokens { get; set; }
792 public MD5 GetChecksumAlgorithm ()
794 return md5 ?? (md5 = MD5.Create ());