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;
76 public int FlowOffset;
78 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
81 if (returnType == null)
82 throw new ArgumentNullException ("returnType");
84 this.return_type = returnType;
86 // TODO: check for null value
90 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
91 : this (rc.MemberContext, block, returnType)
94 flags |= ResolveContext.Options.UnsafeScope;
96 if (rc.HasSet (ResolveContext.Options.CheckedScope))
97 flags |= ResolveContext.Options.CheckedScope;
100 public override FlowBranching CurrentBranching {
101 get { return current_flow_branching; }
104 public TypeSpec ReturnType {
105 get { return return_type; }
109 // Starts a new code branching. This inherits the state of all local
110 // variables and parameters from the current branching.
112 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
114 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
115 return current_flow_branching;
119 // Starts a new code branching for block `block'.
121 public FlowBranching StartFlowBranching (Block block)
123 Set (Options.DoFlowAnalysis);
125 current_flow_branching = FlowBranching.CreateBranching (
126 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
127 return current_flow_branching;
130 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
132 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
133 current_flow_branching = branching;
137 public FlowBranchingTryFinally StartFlowBranching (TryFinallyBlock stmt)
139 FlowBranchingTryFinally branching = new FlowBranchingTryFinally (CurrentBranching, stmt);
140 current_flow_branching = branching;
144 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
146 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
147 current_flow_branching = branching;
151 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
153 FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
154 current_flow_branching = branching;
158 public FlowBranchingAsync StartFlowBranching (AsyncInitializer asyncBody, FlowBranching parent)
160 var branching = new FlowBranchingAsync (parent, asyncBody);
161 current_flow_branching = branching;
165 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
167 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
168 current_flow_branching = branching;
173 // Ends a code branching. Merges the state of locals and parameters
174 // from all the children of the ending branching.
176 public bool EndFlowBranching ()
178 FlowBranching old = current_flow_branching;
179 current_flow_branching = current_flow_branching.Parent;
181 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
182 return vector.IsUnreachable;
186 // Kills the current code branching. This throws away any changed state
187 // information and should only be used in case of an error.
189 // FIXME: this is evil
190 public void KillFlowBranching ()
192 current_flow_branching = current_flow_branching.Parent;
196 public void NeedReturnLabel ()
203 // Expression resolving context
205 public class ResolveContext : IMemberContext
211 /// This flag tracks the `checked' state of the compilation,
212 /// it controls whether we should generate code that does overflow
213 /// checking, or if we generate code that ignores overflows.
215 /// The default setting comes from the command line option to generate
216 /// checked or unchecked code plus any source code changes using the
217 /// checked/unchecked statements or expressions. Contrast this with
218 /// the ConstantCheckState flag.
220 CheckedScope = 1 << 0,
223 /// The constant check state is always set to `true' and cant be changed
224 /// from the command line. The source code can change this setting with
225 /// the `checked' and `unchecked' statements and expressions.
227 ConstantCheckState = 1 << 1,
229 AllCheckStateFlags = CheckedScope | ConstantCheckState,
232 // unsafe { ... } scope
234 UnsafeScope = 1 << 2,
236 FinallyScope = 1 << 4,
237 FieldInitializerScope = 1 << 5,
238 CompoundAssignmentScope = 1 << 6,
239 FixedInitializerScope = 1 << 7,
240 BaseInitializer = 1 << 8,
243 // Inside an enum definition, we do not resolve enumeration values
244 // to their enumerations, but rather to the underlying type/value
245 // This is so EnumVal + EnumValB can be evaluated.
247 // There is no "E operator + (E x, E y)", so during an enum evaluation
248 // we relax the rules
252 ConstantScope = 1 << 10,
254 ConstructorScope = 1 << 11,
256 UsingInitializerScope = 1 << 12,
261 /// Whether control flow analysis is enabled
263 DoFlowAnalysis = 1 << 20,
266 /// Whether control flow analysis is disabled on structs
267 /// (only meaningful when DoFlowAnalysis is set)
269 OmitStructFlowAnalysis = 1 << 21,
272 /// Indicates the current context is in probing mode, no errors are reported.
274 ProbingMode = 1 << 22,
277 // Return and ContextualReturn statements will set the ReturnType
278 // value based on the expression types of each return statement
279 // instead of the method return type which is initially null.
281 InferReturnType = 1 << 23,
283 OmitDebuggingInfo = 1 << 24,
285 ExpressionTreeConversion = 1 << 25,
287 InvokeSpecialName = 1 << 26
290 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
291 // it's public so that we can use a struct at the callsite
292 public struct FlagsHandle : IDisposable
295 readonly Options invmask, oldval;
297 public FlagsHandle (ResolveContext ec, Options flagsToSet)
298 : this (ec, flagsToSet, flagsToSet)
302 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
306 oldval = ec.flags & mask;
307 ec.flags = (ec.flags & invmask) | (val & mask);
309 // if ((mask & Options.ProbingMode) != 0)
310 // ec.Report.DisableReporting ();
313 public void Dispose ()
315 // if ((invmask & Options.ProbingMode) == 0)
316 // ec.Report.EnableReporting ();
318 ec.flags = (ec.flags & invmask) | oldval;
322 protected Options flags;
325 // Whether we are inside an anonymous method.
327 public AnonymousExpression CurrentAnonymousMethod;
330 // Holds a varible used during collection or object initialization.
332 public Expression CurrentInitializerVariable;
334 public Block CurrentBlock;
336 public readonly IMemberContext MemberContext;
339 /// If this is non-null, points to the current switch statement
341 public Switch Switch;
343 public ResolveContext (IMemberContext mc)
346 throw new ArgumentNullException ();
351 // The default setting comes from the command line option
353 if (mc.Module.Compiler.Settings.Checked)
354 flags |= Options.CheckedScope;
357 // The constant check state is always set to true
359 flags |= Options.ConstantCheckState;
362 public ResolveContext (IMemberContext mc, Options options)
370 public BuiltinTypes BuiltinTypes {
372 return MemberContext.Module.Compiler.BuiltinTypes;
376 public virtual ExplicitBlock ConstructorBlock {
378 return CurrentBlock.Explicit;
382 public virtual FlowBranching CurrentBranching {
387 // The current iterator
389 public Iterator CurrentIterator {
390 get { return CurrentAnonymousMethod as Iterator; }
393 public TypeSpec CurrentType {
394 get { return MemberContext.CurrentType; }
397 public TypeParameters CurrentTypeParameters {
398 get { return MemberContext.CurrentTypeParameters; }
401 public MemberCore CurrentMemberDefinition {
402 get { return MemberContext.CurrentMemberDefinition; }
405 public bool ConstantCheckState {
406 get { return (flags & Options.ConstantCheckState) != 0; }
409 public bool DoFlowAnalysis {
410 get { return (flags & Options.DoFlowAnalysis) != 0; }
413 public bool IsInProbingMode {
415 return (flags & Options.ProbingMode) != 0;
419 public bool IsObsolete {
421 // Disables obsolete checks when probing is on
422 return MemberContext.IsObsolete;
426 public bool IsStatic {
428 return MemberContext.IsStatic;
432 public bool IsUnsafe {
434 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
438 public bool IsRuntimeBinder {
440 return Module.Compiler.IsRuntimeBinder;
444 public bool IsVariableCapturingRequired {
446 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
450 public ModuleContainer Module {
452 return MemberContext.Module;
456 public bool OmitStructFlowAnalysis {
457 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
460 public Report Report {
462 return Module.Compiler.Report;
468 public bool MustCaptureVariable (INamedBlockVariable local)
470 if (CurrentAnonymousMethod == null)
474 // Capture only if this or any of child blocks contain yield
475 // or it's a parameter
477 if (CurrentAnonymousMethod.IsIterator)
478 return local.IsParameter || CurrentBlock.Explicit.HasYield;
481 // Capture only if this or any of child blocks contain await
482 // or it's a parameter
484 if (CurrentAnonymousMethod is AsyncInitializer)
485 return local.IsParameter || CurrentBlock.Explicit.HasAwait;
487 return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
490 public bool HasSet (Options options)
492 return (this.flags & options) == options;
495 public bool HasAny (Options options)
497 return (this.flags & options) != 0;
501 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
502 public FlagsHandle Set (Options options)
504 return new FlagsHandle (this, options);
507 public FlagsHandle With (Options options, bool enable)
509 return new FlagsHandle (this, options, enable ? options : 0);
512 #region IMemberContext Members
514 public string GetSignatureForError ()
516 return MemberContext.GetSignatureForError ();
519 public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
521 return MemberContext.LookupExtensionMethod (extensionType, name, arity);
524 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
526 return MemberContext.LookupNamespaceOrType (name, arity, mode, loc);
529 public FullNamedExpression LookupNamespaceAlias (string name)
531 return MemberContext.LookupNamespaceAlias (name);
538 // This class is used during the Statement.Clone operation
539 // to remap objects that have been cloned.
541 // Since blocks are cloned by Block.Clone, we need a way for
542 // expressions that must reference the block to be cloned
543 // pointing to the new cloned block.
545 public class CloneContext
547 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
549 public void AddBlockMap (Block from, Block to)
551 block_map.Add (from, to);
554 public Block LookupBlock (Block from)
557 if (!block_map.TryGetValue (from, out result)) {
558 result = (Block) from.Clone (this);
565 /// Remaps block to cloned copy if one exists.
567 public Block RemapBlockCopy (Block from)
570 if (!block_map.TryGetValue (from, out mapped_to))
578 // Main compiler context
580 public class CompilerContext
582 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
584 readonly Report report;
585 readonly BuiltinTypes builtin_types;
586 readonly CompilerSettings settings;
588 Dictionary<string, SourceFile> all_source_files;
590 public CompilerContext (CompilerSettings settings, ReportPrinter reportPrinter)
592 this.settings = settings;
593 this.report = new Report (this, reportPrinter);
594 this.builtin_types = new BuiltinTypes ();
595 this.TimeReporter = DisabledTimeReporter;
600 public BuiltinTypes BuiltinTypes {
602 return builtin_types;
606 // Used for special handling of runtime dynamic context mostly
607 // by error reporting but also by member accessibility checks
608 public bool IsRuntimeBinder {
612 public Report Report {
618 public CompilerSettings Settings {
624 public List<SourceFile> SourceFiles {
626 return settings.SourceFiles;
630 internal TimeReporter TimeReporter {
637 // This is used when we encounter a #line preprocessing directive during parsing
638 // to register additional source file names
640 public SourceFile LookupFile (CompilationSourceFile comp_unit, string name)
642 if (all_source_files == null) {
643 all_source_files = new Dictionary<string, SourceFile> ();
644 foreach (var source in SourceFiles)
645 all_source_files[source.FullPathName] = source;
649 if (!Path.IsPathRooted (name)) {
650 string root = Path.GetDirectoryName (comp_unit.SourceFile.FullPathName);
651 path = Path.Combine (root, name);
656 if (all_source_files.TryGetValue (path, out retval))
659 retval = new SourceFile (name, path, all_source_files.Count + 1);
660 Location.AddFile (retval);
661 all_source_files.Add (path, retval);
667 // Generic code emitter context
669 public class BuilderContext
675 /// This flag tracks the `checked' state of the compilation,
676 /// it controls whether we should generate code that does overflow
677 /// checking, or if we generate code that ignores overflows.
679 /// The default setting comes from the command line option to generate
680 /// checked or unchecked code plus any source code changes using the
681 /// checked/unchecked statements or expressions. Contrast this with
682 /// the ConstantCheckState flag.
684 CheckedScope = 1 << 0,
686 AccurateDebugInfo = 1 << 1,
688 OmitDebugInfo = 1 << 2,
690 ConstructorScope = 1 << 3,
695 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
696 // it's public so that we can use a struct at the callsite
697 public struct FlagsHandle : IDisposable
700 readonly Options invmask, oldval;
702 public FlagsHandle (BuilderContext ec, Options flagsToSet)
703 : this (ec, flagsToSet, flagsToSet)
707 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
711 oldval = ec.flags & mask;
712 ec.flags = (ec.flags & invmask) | (val & mask);
715 public void Dispose ()
717 ec.flags = (ec.flags & invmask) | oldval;
721 protected Options flags;
723 public bool HasSet (Options options)
725 return (this.flags & options) == options;
728 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
729 public FlagsHandle With (Options options, bool enable)
731 return new FlagsHandle (this, options, enable ? options : 0);
736 // Parser session objects. We could recreate all these objects for each parser
737 // instance but the best parser performance the session object can be reused
739 public class ParserSession
743 public readonly char[] StreamReaderBuffer = new char[SeekableStreamReader.DefaultReadAheadSize * 2];
744 public readonly Dictionary<char[], string>[] Identifiers = new Dictionary<char[], string>[Tokenizer.MaxIdentifierLength + 1];
745 public readonly List<Parameter> ParametersStack = new List<Parameter> (4);
746 public readonly char[] IDBuilder = new char[Tokenizer.MaxIdentifierLength];
747 public readonly char[] NumberBuilder = new char[Tokenizer.MaxNumberLength];
749 public LocationsBag LocationsBag { get; set; }
750 public bool UseJayGlobalArrays { get; set; }
751 public Tokenizer.LocatedToken[] LocatedTokens { get; set; }
753 public MD5 GetChecksumAlgorithm ()
755 return md5 ?? (md5 = MD5.Create ());