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;
99 if (rc.IsInProbingMode)
100 flags |= ResolveContext.Options.ProbingMode;
102 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
103 flags |= ResolveContext.Options.FieldInitializerScope;
105 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
106 flags |= ResolveContext.Options.ExpressionTreeConversion;
108 if (rc.HasSet (ResolveContext.Options.BaseInitializer))
109 flags |= ResolveContext.Options.BaseInitializer;
112 public override FlowBranching CurrentBranching {
113 get { return current_flow_branching; }
116 public TypeSpec ReturnType {
117 get { return return_type; }
120 public bool IsUnreachable {
122 return HasSet (Options.UnreachableScope);
125 flags = value ? flags | Options.UnreachableScope : flags & ~Options.UnreachableScope;
129 public bool UnreachableReported {
131 return HasSet (Options.UnreachableReported);
134 flags = value ? flags | Options.UnreachableReported : flags & ~Options.UnreachableScope;
139 // Starts a new code branching. This inherits the state of all local
140 // variables and parameters from the current branching.
142 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
144 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
145 return current_flow_branching;
149 // Starts a new code branching for block `block'.
151 public FlowBranching StartFlowBranching (Block block)
153 Set (Options.DoFlowAnalysis);
155 current_flow_branching = FlowBranching.CreateBranching (
156 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
157 return current_flow_branching;
160 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
162 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
163 current_flow_branching = branching;
167 public FlowBranchingTryFinally StartFlowBranching (TryFinallyBlock stmt)
169 FlowBranchingTryFinally branching = new FlowBranchingTryFinally (CurrentBranching, stmt);
170 current_flow_branching = branching;
174 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
176 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
177 current_flow_branching = branching;
181 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
183 FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
184 current_flow_branching = branching;
188 public FlowBranchingAsync StartFlowBranching (AsyncInitializer asyncBody, FlowBranching parent)
190 var branching = new FlowBranchingAsync (parent, asyncBody);
191 current_flow_branching = branching;
195 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
197 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
198 current_flow_branching = branching;
203 // Ends a code branching. Merges the state of locals and parameters
204 // from all the children of the ending branching.
206 public bool EndFlowBranching ()
208 FlowBranching old = current_flow_branching;
209 current_flow_branching = current_flow_branching.Parent;
211 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
212 return vector.IsUnreachable;
216 // Kills the current code branching. This throws away any changed state
217 // information and should only be used in case of an error.
219 // FIXME: this is evil
220 public void KillFlowBranching ()
222 current_flow_branching = current_flow_branching.Parent;
226 public void NeedReturnLabel ()
233 // Expression resolving context
235 public class ResolveContext : IMemberContext
241 /// This flag tracks the `checked' state of the compilation,
242 /// it controls whether we should generate code that does overflow
243 /// checking, or if we generate code that ignores overflows.
245 /// The default setting comes from the command line option to generate
246 /// checked or unchecked code plus any source code changes using the
247 /// checked/unchecked statements or expressions. Contrast this with
248 /// the ConstantCheckState flag.
250 CheckedScope = 1 << 0,
253 /// The constant check state is always set to `true' and cant be changed
254 /// from the command line. The source code can change this setting with
255 /// the `checked' and `unchecked' statements and expressions.
257 ConstantCheckState = 1 << 1,
259 AllCheckStateFlags = CheckedScope | ConstantCheckState,
262 // unsafe { ... } scope
264 UnsafeScope = 1 << 2,
266 FinallyScope = 1 << 4,
267 FieldInitializerScope = 1 << 5,
268 CompoundAssignmentScope = 1 << 6,
269 FixedInitializerScope = 1 << 7,
270 BaseInitializer = 1 << 8,
273 // Inside an enum definition, we do not resolve enumeration values
274 // to their enumerations, but rather to the underlying type/value
275 // This is so EnumVal + EnumValB can be evaluated.
277 // There is no "E operator + (E x, E y)", so during an enum evaluation
278 // we relax the rules
282 ConstantScope = 1 << 10,
284 ConstructorScope = 1 << 11,
286 UsingInitializerScope = 1 << 12,
290 UnreachableScope = 1 << 14,
292 UnreachableReported = 1 << 15,
295 /// Whether control flow analysis is enabled
297 DoFlowAnalysis = 1 << 20,
300 /// Whether control flow analysis is disabled on structs
301 /// (only meaningful when DoFlowAnalysis is set)
303 OmitStructFlowAnalysis = 1 << 21,
306 /// Indicates the current context is in probing mode, no errors are reported.
308 ProbingMode = 1 << 22,
311 // Return and ContextualReturn statements will set the ReturnType
312 // value based on the expression types of each return statement
313 // instead of the method return type which is initially null.
315 InferReturnType = 1 << 23,
317 OmitDebuggingInfo = 1 << 24,
319 ExpressionTreeConversion = 1 << 25,
321 InvokeSpecialName = 1 << 26
324 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
325 // it's public so that we can use a struct at the callsite
326 public struct FlagsHandle : IDisposable
329 readonly Options invmask, oldval;
331 public FlagsHandle (ResolveContext ec, Options flagsToSet)
332 : this (ec, flagsToSet, flagsToSet)
336 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
340 oldval = ec.flags & mask;
341 ec.flags = (ec.flags & invmask) | (val & mask);
343 // if ((mask & Options.ProbingMode) != 0)
344 // ec.Report.DisableReporting ();
347 public void Dispose ()
349 // if ((invmask & Options.ProbingMode) == 0)
350 // ec.Report.EnableReporting ();
352 ec.flags = (ec.flags & invmask) | oldval;
356 protected Options flags;
359 // Whether we are inside an anonymous method.
361 public AnonymousExpression CurrentAnonymousMethod;
364 // Holds a varible used during collection or object initialization.
366 public Expression CurrentInitializerVariable;
368 public Block CurrentBlock;
370 public readonly IMemberContext MemberContext;
373 /// If this is non-null, points to the current switch statement
375 public Switch Switch;
377 public ResolveContext (IMemberContext mc)
380 throw new ArgumentNullException ();
385 // The default setting comes from the command line option
387 if (mc.Module.Compiler.Settings.Checked)
388 flags |= Options.CheckedScope;
391 // The constant check state is always set to true
393 flags |= Options.ConstantCheckState;
396 public ResolveContext (IMemberContext mc, Options options)
404 public BuiltinTypes BuiltinTypes {
406 return MemberContext.Module.Compiler.BuiltinTypes;
410 public virtual ExplicitBlock ConstructorBlock {
412 return CurrentBlock.Explicit;
416 public virtual FlowBranching CurrentBranching {
421 // The current iterator
423 public Iterator CurrentIterator {
424 get { return CurrentAnonymousMethod as Iterator; }
427 public TypeSpec CurrentType {
428 get { return MemberContext.CurrentType; }
431 public TypeParameters CurrentTypeParameters {
432 get { return MemberContext.CurrentTypeParameters; }
435 public MemberCore CurrentMemberDefinition {
436 get { return MemberContext.CurrentMemberDefinition; }
439 public bool ConstantCheckState {
440 get { return (flags & Options.ConstantCheckState) != 0; }
443 public bool DoFlowAnalysis {
444 get { return (flags & Options.DoFlowAnalysis) != 0; }
447 public bool IsInProbingMode {
449 return (flags & Options.ProbingMode) != 0;
453 public bool IsObsolete {
455 // Disables obsolete checks when probing is on
456 return MemberContext.IsObsolete;
460 public bool IsStatic {
462 return MemberContext.IsStatic;
466 public bool IsUnsafe {
468 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
472 public bool IsRuntimeBinder {
474 return Module.Compiler.IsRuntimeBinder;
478 public bool IsVariableCapturingRequired {
480 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
484 public ModuleContainer Module {
486 return MemberContext.Module;
490 public bool OmitStructFlowAnalysis {
491 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
494 public Report Report {
496 return Module.Compiler.Report;
502 public bool MustCaptureVariable (INamedBlockVariable local)
504 if (CurrentAnonymousMethod == null)
508 // Capture only if this or any of child blocks contain yield
509 // or it's a parameter
511 if (CurrentAnonymousMethod.IsIterator)
512 return local.IsParameter || local.Block.Explicit.HasYield;
515 // Capture only if this or any of child blocks contain await
516 // or it's a parameter
518 if (CurrentAnonymousMethod is AsyncInitializer)
519 return local.IsParameter || local.Block.Explicit.HasAwait || CurrentBlock.Explicit.HasAwait;
521 return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
524 public bool HasSet (Options options)
526 return (this.flags & options) == options;
529 public bool HasAny (Options options)
531 return (this.flags & options) != 0;
535 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
536 public FlagsHandle Set (Options options)
538 return new FlagsHandle (this, options);
541 public FlagsHandle With (Options options, bool enable)
543 return new FlagsHandle (this, options, enable ? options : 0);
546 #region IMemberContext Members
548 public string GetSignatureForError ()
550 return MemberContext.GetSignatureForError ();
553 public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
555 return MemberContext.LookupExtensionMethod (extensionType, name, arity);
558 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
560 return MemberContext.LookupNamespaceOrType (name, arity, mode, loc);
563 public FullNamedExpression LookupNamespaceAlias (string name)
565 return MemberContext.LookupNamespaceAlias (name);
572 // This class is used during the Statement.Clone operation
573 // to remap objects that have been cloned.
575 // Since blocks are cloned by Block.Clone, we need a way for
576 // expressions that must reference the block to be cloned
577 // pointing to the new cloned block.
579 public class CloneContext
581 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
583 public void AddBlockMap (Block from, Block to)
585 block_map.Add (from, to);
588 public Block LookupBlock (Block from)
591 if (!block_map.TryGetValue (from, out result)) {
592 result = (Block) from.Clone (this);
599 /// Remaps block to cloned copy if one exists.
601 public Block RemapBlockCopy (Block from)
604 if (!block_map.TryGetValue (from, out mapped_to))
612 // Main compiler context
614 public class CompilerContext
616 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
618 readonly Report report;
619 readonly BuiltinTypes builtin_types;
620 readonly CompilerSettings settings;
622 Dictionary<string, SourceFile> all_source_files;
624 public CompilerContext (CompilerSettings settings, ReportPrinter reportPrinter)
626 this.settings = settings;
627 this.report = new Report (this, reportPrinter);
628 this.builtin_types = new BuiltinTypes ();
629 this.TimeReporter = DisabledTimeReporter;
634 public BuiltinTypes BuiltinTypes {
636 return builtin_types;
640 // Used for special handling of runtime dynamic context mostly
641 // by error reporting but also by member accessibility checks
642 public bool IsRuntimeBinder {
646 public Report Report {
652 public CompilerSettings Settings {
658 public List<SourceFile> SourceFiles {
660 return settings.SourceFiles;
664 internal TimeReporter TimeReporter {
671 // This is used when we encounter a #line preprocessing directive during parsing
672 // to register additional source file names
674 public SourceFile LookupFile (CompilationSourceFile comp_unit, string name)
676 if (all_source_files == null) {
677 all_source_files = new Dictionary<string, SourceFile> ();
678 foreach (var source in SourceFiles)
679 all_source_files[source.FullPathName] = source;
683 if (!Path.IsPathRooted (name)) {
684 string root = Path.GetDirectoryName (comp_unit.SourceFile.FullPathName);
685 path = Path.Combine (root, name);
690 if (all_source_files.TryGetValue (path, out retval))
693 retval = new SourceFile (name, path, all_source_files.Count + 1);
694 Location.AddFile (retval);
695 all_source_files.Add (path, retval);
701 // Generic code emitter context
703 public class BuilderContext
709 /// This flag tracks the `checked' state of the compilation,
710 /// it controls whether we should generate code that does overflow
711 /// checking, or if we generate code that ignores overflows.
713 /// The default setting comes from the command line option to generate
714 /// checked or unchecked code plus any source code changes using the
715 /// checked/unchecked statements or expressions. Contrast this with
716 /// the ConstantCheckState flag.
718 CheckedScope = 1 << 0,
720 AccurateDebugInfo = 1 << 1,
722 OmitDebugInfo = 1 << 2,
724 ConstructorScope = 1 << 3,
729 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
730 // it's public so that we can use a struct at the callsite
731 public struct FlagsHandle : IDisposable
734 readonly Options invmask, oldval;
736 public FlagsHandle (BuilderContext ec, Options flagsToSet)
737 : this (ec, flagsToSet, flagsToSet)
741 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
745 oldval = ec.flags & mask;
746 ec.flags = (ec.flags & invmask) | (val & mask);
749 public void Dispose ()
751 ec.flags = (ec.flags & invmask) | oldval;
755 protected Options flags;
757 public bool HasSet (Options options)
759 return (this.flags & options) == options;
762 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
763 public FlagsHandle With (Options options, bool enable)
765 return new FlagsHandle (this, options, enable ? options : 0);
770 // Parser session objects. We could recreate all these objects for each parser
771 // instance but the best parser performance the session object can be reused
773 public class ParserSession
777 public readonly char[] StreamReaderBuffer = new char[SeekableStreamReader.DefaultReadAheadSize * 2];
778 public readonly Dictionary<char[], string>[] Identifiers = new Dictionary<char[], string>[Tokenizer.MaxIdentifierLength + 1];
779 public readonly List<Parameter> ParametersStack = new List<Parameter> (4);
780 public readonly char[] IDBuilder = new char[Tokenizer.MaxIdentifierLength];
781 public readonly char[] NumberBuilder = new char[Tokenizer.MaxNumberLength];
783 public LocationsBag LocationsBag { get; set; }
784 public bool UseJayGlobalArrays { get; set; }
785 public LocatedToken[] LocatedTokens { get; set; }
787 public MD5 GetChecksumAlgorithm ()
789 return md5 ?? (md5 = MD5.Create ());