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;
19 public enum LookupMode
23 IgnoreAccessibility = 2
27 // Implemented by elements which can act as independent contexts
28 // during resolve phase. Used mostly for lookups.
30 public interface IMemberContext : IModuleContext
33 // A scope type context, it can be inflated for generic types
35 TypeSpec CurrentType { get; }
38 // A scope type parameters either VAR or MVAR
40 TypeParameters CurrentTypeParameters { get; }
43 // A member definition of the context. For partial types definition use
44 // CurrentTypeDefinition.PartialContainer otherwise the context is local
46 // TODO: Obsolete it in this context, dynamic context cannot guarantee sensible value
48 MemberCore CurrentMemberDefinition { get; }
50 bool IsObsolete { get; }
51 bool IsUnsafe { get; }
52 bool IsStatic { get; }
54 string GetSignatureForError ();
56 ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity);
57 FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc);
58 FullNamedExpression LookupNamespaceAlias (string name);
61 public interface IModuleContext
63 ModuleContainer Module { get; }
67 // Block or statement resolving context
69 public class BlockContext : ResolveContext
71 FlowBranching current_flow_branching;
73 readonly TypeSpec return_type;
75 public int FlowOffset;
77 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
80 if (returnType == null)
81 throw new ArgumentNullException ("returnType");
83 this.return_type = returnType;
85 // TODO: check for null value
89 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
90 : this (rc.MemberContext, block, returnType)
93 flags |= ResolveContext.Options.UnsafeScope;
95 if (rc.HasSet (ResolveContext.Options.CheckedScope))
96 flags |= ResolveContext.Options.CheckedScope;
99 public override FlowBranching CurrentBranching {
100 get { return current_flow_branching; }
103 public TypeSpec ReturnType {
104 get { return return_type; }
108 // Starts a new code branching. This inherits the state of all local
109 // variables and parameters from the current branching.
111 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
113 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
114 return current_flow_branching;
118 // Starts a new code branching for block `block'.
120 public FlowBranching StartFlowBranching (Block block)
122 Set (Options.DoFlowAnalysis);
124 current_flow_branching = FlowBranching.CreateBranching (
125 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
126 return current_flow_branching;
129 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
131 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
132 current_flow_branching = branching;
136 public FlowBranchingTryFinally StartFlowBranching (TryFinallyBlock stmt)
138 FlowBranchingTryFinally branching = new FlowBranchingTryFinally (CurrentBranching, stmt);
139 current_flow_branching = branching;
143 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
145 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
146 current_flow_branching = branching;
150 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
152 FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
153 current_flow_branching = branching;
157 public FlowBranchingAsync StartFlowBranching (AsyncInitializer asyncBody, FlowBranching parent)
159 var branching = new FlowBranchingAsync (parent, asyncBody);
160 current_flow_branching = branching;
164 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
166 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
167 current_flow_branching = branching;
172 // Ends a code branching. Merges the state of locals and parameters
173 // from all the children of the ending branching.
175 public bool EndFlowBranching ()
177 FlowBranching old = current_flow_branching;
178 current_flow_branching = current_flow_branching.Parent;
180 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
181 return vector.IsUnreachable;
185 // Kills the current code branching. This throws away any changed state
186 // information and should only be used in case of an error.
188 // FIXME: this is evil
189 public void KillFlowBranching ()
191 current_flow_branching = current_flow_branching.Parent;
195 public void NeedReturnLabel ()
202 // Expression resolving context
204 public class ResolveContext : IMemberContext
210 /// This flag tracks the `checked' state of the compilation,
211 /// it controls whether we should generate code that does overflow
212 /// checking, or if we generate code that ignores overflows.
214 /// The default setting comes from the command line option to generate
215 /// checked or unchecked code plus any source code changes using the
216 /// checked/unchecked statements or expressions. Contrast this with
217 /// the ConstantCheckState flag.
219 CheckedScope = 1 << 0,
222 /// The constant check state is always set to `true' and cant be changed
223 /// from the command line. The source code can change this setting with
224 /// the `checked' and `unchecked' statements and expressions.
226 ConstantCheckState = 1 << 1,
228 AllCheckStateFlags = CheckedScope | ConstantCheckState,
231 // unsafe { ... } scope
233 UnsafeScope = 1 << 2,
235 FinallyScope = 1 << 4,
236 FieldInitializerScope = 1 << 5,
237 CompoundAssignmentScope = 1 << 6,
238 FixedInitializerScope = 1 << 7,
239 BaseInitializer = 1 << 8,
242 // Inside an enum definition, we do not resolve enumeration values
243 // to their enumerations, but rather to the underlying type/value
244 // This is so EnumVal + EnumValB can be evaluated.
246 // There is no "E operator + (E x, E y)", so during an enum evaluation
247 // we relax the rules
251 ConstantScope = 1 << 10,
253 ConstructorScope = 1 << 11,
255 UsingInitializerScope = 1 << 12,
260 /// Whether control flow analysis is enabled
262 DoFlowAnalysis = 1 << 20,
265 /// Whether control flow analysis is disabled on structs
266 /// (only meaningful when DoFlowAnalysis is set)
268 OmitStructFlowAnalysis = 1 << 21,
271 /// Indicates the current context is in probing mode, no errors are reported.
273 ProbingMode = 1 << 22,
276 // Return and ContextualReturn statements will set the ReturnType
277 // value based on the expression types of each return statement
278 // instead of the method return type which is initially null.
280 InferReturnType = 1 << 23,
282 OmitDebuggingInfo = 1 << 24,
284 ExpressionTreeConversion = 1 << 25,
286 InvokeSpecialName = 1 << 26
289 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
290 // it's public so that we can use a struct at the callsite
291 public struct FlagsHandle : IDisposable
294 readonly Options invmask, oldval;
296 public FlagsHandle (ResolveContext ec, Options flagsToSet)
297 : this (ec, flagsToSet, flagsToSet)
301 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
305 oldval = ec.flags & mask;
306 ec.flags = (ec.flags & invmask) | (val & mask);
308 // if ((mask & Options.ProbingMode) != 0)
309 // ec.Report.DisableReporting ();
312 public void Dispose ()
314 // if ((invmask & Options.ProbingMode) == 0)
315 // ec.Report.EnableReporting ();
317 ec.flags = (ec.flags & invmask) | oldval;
321 protected Options flags;
324 // Whether we are inside an anonymous method.
326 public AnonymousExpression CurrentAnonymousMethod;
329 // Holds a varible used during collection or object initialization.
331 public Expression CurrentInitializerVariable;
333 public Block CurrentBlock;
335 public readonly IMemberContext MemberContext;
338 /// If this is non-null, points to the current switch statement
340 public Switch Switch;
342 public ResolveContext (IMemberContext mc)
345 throw new ArgumentNullException ();
350 // The default setting comes from the command line option
352 if (mc.Module.Compiler.Settings.Checked)
353 flags |= Options.CheckedScope;
356 // The constant check state is always set to true
358 flags |= Options.ConstantCheckState;
361 public ResolveContext (IMemberContext mc, Options options)
369 public BuiltinTypes BuiltinTypes {
371 return MemberContext.Module.Compiler.BuiltinTypes;
375 public virtual ExplicitBlock ConstructorBlock {
377 return CurrentBlock.Explicit;
381 public virtual FlowBranching CurrentBranching {
386 // The current iterator
388 public Iterator CurrentIterator {
389 get { return CurrentAnonymousMethod as Iterator; }
392 public TypeSpec CurrentType {
393 get { return MemberContext.CurrentType; }
396 public TypeParameters CurrentTypeParameters {
397 get { return MemberContext.CurrentTypeParameters; }
400 public MemberCore CurrentMemberDefinition {
401 get { return MemberContext.CurrentMemberDefinition; }
404 public bool ConstantCheckState {
405 get { return (flags & Options.ConstantCheckState) != 0; }
408 public bool DoFlowAnalysis {
409 get { return (flags & Options.DoFlowAnalysis) != 0; }
412 public bool IsInProbingMode {
414 return (flags & Options.ProbingMode) != 0;
418 public bool IsObsolete {
420 // Disables obsolete checks when probing is on
421 return MemberContext.IsObsolete;
425 public bool IsStatic {
427 return MemberContext.IsStatic;
431 public bool IsUnsafe {
433 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
437 public bool IsRuntimeBinder {
439 return Module.Compiler.IsRuntimeBinder;
443 public bool IsVariableCapturingRequired {
445 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
449 public ModuleContainer Module {
451 return MemberContext.Module;
455 public bool OmitStructFlowAnalysis {
456 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
459 public Report Report {
461 return Module.Compiler.Report;
467 public bool MustCaptureVariable (INamedBlockVariable local)
469 if (CurrentAnonymousMethod == null)
473 // Capture only if this or any of child blocks contain yield
474 // or it's a parameter
476 if (CurrentAnonymousMethod.IsIterator)
477 return local.IsParameter || CurrentBlock.Explicit.HasYield;
480 // Capture only if this or any of child blocks contain await
481 // or it's a parameter
483 if (CurrentAnonymousMethod is AsyncInitializer)
484 return CurrentBlock.Explicit.HasAwait;
486 return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
489 public bool HasSet (Options options)
491 return (this.flags & options) == options;
494 public bool HasAny (Options options)
496 return (this.flags & options) != 0;
500 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
501 public FlagsHandle Set (Options options)
503 return new FlagsHandle (this, options);
506 public FlagsHandle With (Options options, bool enable)
508 return new FlagsHandle (this, options, enable ? options : 0);
511 #region IMemberContext Members
513 public string GetSignatureForError ()
515 return MemberContext.GetSignatureForError ();
518 public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
520 return MemberContext.LookupExtensionMethod (extensionType, name, arity);
523 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
525 return MemberContext.LookupNamespaceOrType (name, arity, mode, loc);
528 public FullNamedExpression LookupNamespaceAlias (string name)
530 return MemberContext.LookupNamespaceAlias (name);
537 // This class is used during the Statement.Clone operation
538 // to remap objects that have been cloned.
540 // Since blocks are cloned by Block.Clone, we need a way for
541 // expressions that must reference the block to be cloned
542 // pointing to the new cloned block.
544 public class CloneContext
546 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
548 public void AddBlockMap (Block from, Block to)
550 block_map.Add (from, to);
553 public Block LookupBlock (Block from)
556 if (!block_map.TryGetValue (from, out result)) {
557 result = (Block) from.Clone (this);
564 /// Remaps block to cloned copy if one exists.
566 public Block RemapBlockCopy (Block from)
569 if (!block_map.TryGetValue (from, out mapped_to))
577 // Main compiler context
579 public class CompilerContext
581 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
583 readonly Report report;
584 readonly BuiltinTypes builtin_types;
585 readonly CompilerSettings settings;
587 Dictionary<string, SourceFile> all_source_files;
589 public CompilerContext (CompilerSettings settings, ReportPrinter reportPrinter)
591 this.settings = settings;
592 this.report = new Report (this, reportPrinter);
593 this.builtin_types = new BuiltinTypes ();
594 this.TimeReporter = DisabledTimeReporter;
599 public BuiltinTypes BuiltinTypes {
601 return builtin_types;
605 // Used for special handling of runtime dynamic context mostly
606 // by error reporting but also by member accessibility checks
607 public bool IsRuntimeBinder {
611 public Report Report {
617 public CompilerSettings Settings {
623 public List<CompilationSourceFile> SourceFiles {
625 return settings.SourceFiles;
629 internal TimeReporter TimeReporter {
636 // This is used when we encounter a #line preprocessing directive during parsing
637 // to register additional source file names
639 public SourceFile LookupFile (CompilationSourceFile comp_unit, string name)
641 if (all_source_files == null) {
642 all_source_files = new Dictionary<string, SourceFile> ();
643 foreach (var source in SourceFiles)
644 all_source_files[source.FullPathName] = source;
648 if (!Path.IsPathRooted (name)) {
649 string root = Path.GetDirectoryName (comp_unit.FullPathName);
650 path = Path.Combine (root, name);
655 if (all_source_files.TryGetValue (path, out retval))
658 retval = Location.AddFile (name, path);
659 all_source_files.Add (path, retval);
665 // Generic code emitter context
667 public class BuilderContext
673 /// This flag tracks the `checked' state of the compilation,
674 /// it controls whether we should generate code that does overflow
675 /// checking, or if we generate code that ignores overflows.
677 /// The default setting comes from the command line option to generate
678 /// checked or unchecked code plus any source code changes using the
679 /// checked/unchecked statements or expressions. Contrast this with
680 /// the ConstantCheckState flag.
682 CheckedScope = 1 << 0,
684 OmitDebugInfo = 1 << 2,
686 ConstructorScope = 1 << 3,
691 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
692 // it's public so that we can use a struct at the callsite
693 public struct FlagsHandle : IDisposable
696 readonly Options invmask, oldval;
698 public FlagsHandle (BuilderContext ec, Options flagsToSet)
699 : this (ec, flagsToSet, flagsToSet)
703 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
707 oldval = ec.flags & mask;
708 ec.flags = (ec.flags & invmask) | (val & mask);
711 public void Dispose ()
713 ec.flags = (ec.flags & invmask) | oldval;
717 protected Options flags;
719 public bool HasSet (Options options)
721 return (this.flags & options) == options;
724 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
725 public FlagsHandle With (Options options, bool enable)
727 return new FlagsHandle (this, options, enable ? options : 0);