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.
13 using System.Collections.Generic;
18 public enum LookupMode
22 IgnoreAccessibility = 2
26 // Implemented by elements which can act as independent contexts
27 // during resolve phase. Used mostly for lookups.
29 public interface IMemberContext : IModuleContext
32 // A scope type context, it can be inflated for generic types
34 TypeSpec CurrentType { get; }
37 // A scope type parameters either VAR or MVAR
39 TypeParameter[] CurrentTypeParameters { get; }
42 // A member definition of the context. For partial types definition use
43 // CurrentTypeDefinition.PartialContainer otherwise the context is local
45 // TODO: Obsolete it in this context, dynamic context cannot guarantee sensible value
47 MemberCore CurrentMemberDefinition { get; }
49 bool IsObsolete { get; }
50 bool IsUnsafe { get; }
51 bool IsStatic { get; }
53 string GetSignatureForError ();
55 ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity);
56 FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc);
57 FullNamedExpression LookupNamespaceAlias (string name);
60 public interface IModuleContext
62 ModuleContainer Module { get; }
66 // Block or statement resolving context
68 public class BlockContext : ResolveContext
70 FlowBranching current_flow_branching;
72 readonly TypeSpec return_type;
74 public int FlowOffset;
76 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
79 if (returnType == null)
80 throw new ArgumentNullException ("returnType");
82 this.return_type = returnType;
84 // TODO: check for null value
88 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
89 : this (rc.MemberContext, block, returnType)
92 flags |= ResolveContext.Options.UnsafeScope;
94 if (rc.HasSet (ResolveContext.Options.CheckedScope))
95 flags |= ResolveContext.Options.CheckedScope;
98 public override FlowBranching CurrentBranching {
99 get { return current_flow_branching; }
102 public TypeSpec ReturnType {
103 get { return return_type; }
107 // Starts a new code branching. This inherits the state of all local
108 // variables and parameters from the current branching.
110 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
112 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
113 return current_flow_branching;
117 // Starts a new code branching for block `block'.
119 public FlowBranching StartFlowBranching (Block block)
121 Set (Options.DoFlowAnalysis);
123 current_flow_branching = FlowBranching.CreateBranching (
124 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
125 return current_flow_branching;
128 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
130 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
131 current_flow_branching = branching;
135 public FlowBranchingTryFinally StartFlowBranching (TryFinallyBlock stmt)
137 FlowBranchingTryFinally branching = new FlowBranchingTryFinally (CurrentBranching, stmt);
138 current_flow_branching = branching;
142 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
144 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
145 current_flow_branching = branching;
149 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
151 FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
152 current_flow_branching = branching;
156 public FlowBranchingAsync StartFlowBranching (AsyncInitializer asyncBody, FlowBranching parent)
158 var branching = new FlowBranchingAsync (parent, asyncBody);
159 current_flow_branching = branching;
163 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
165 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
166 current_flow_branching = branching;
171 // Ends a code branching. Merges the state of locals and parameters
172 // from all the children of the ending branching.
174 public bool EndFlowBranching ()
176 FlowBranching old = current_flow_branching;
177 current_flow_branching = current_flow_branching.Parent;
179 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
180 return vector.IsUnreachable;
184 // Kills the current code branching. This throws away any changed state
185 // information and should only be used in case of an error.
187 // FIXME: this is evil
188 public void KillFlowBranching ()
190 current_flow_branching = current_flow_branching.Parent;
194 public void NeedReturnLabel ()
201 // Expression resolving context
203 public class ResolveContext : IMemberContext
209 /// This flag tracks the `checked' state of the compilation,
210 /// it controls whether we should generate code that does overflow
211 /// checking, or if we generate code that ignores overflows.
213 /// The default setting comes from the command line option to generate
214 /// checked or unchecked code plus any source code changes using the
215 /// checked/unchecked statements or expressions. Contrast this with
216 /// the ConstantCheckState flag.
218 CheckedScope = 1 << 0,
221 /// The constant check state is always set to `true' and cant be changed
222 /// from the command line. The source code can change this setting with
223 /// the `checked' and `unchecked' statements and expressions.
225 ConstantCheckState = 1 << 1,
227 AllCheckStateFlags = CheckedScope | ConstantCheckState,
230 // unsafe { ... } scope
232 UnsafeScope = 1 << 2,
234 FinallyScope = 1 << 4,
235 FieldInitializerScope = 1 << 5,
236 CompoundAssignmentScope = 1 << 6,
237 FixedInitializerScope = 1 << 7,
238 BaseInitializer = 1 << 8,
241 // Inside an enum definition, we do not resolve enumeration values
242 // to their enumerations, but rather to the underlying type/value
243 // This is so EnumVal + EnumValB can be evaluated.
245 // There is no "E operator + (E x, E y)", so during an enum evaluation
246 // we relax the rules
250 ConstantScope = 1 << 10,
252 ConstructorScope = 1 << 11,
254 UsingInitializerScope = 1 << 12,
259 /// Whether control flow analysis is enabled
261 DoFlowAnalysis = 1 << 20,
264 /// Whether control flow analysis is disabled on structs
265 /// (only meaningful when DoFlowAnalysis is set)
267 OmitStructFlowAnalysis = 1 << 21,
270 /// Indicates the current context is in probing mode, no errors are reported.
272 ProbingMode = 1 << 22,
275 // Return and ContextualReturn statements will set the ReturnType
276 // value based on the expression types of each return statement
277 // instead of the method return type which is initially null.
279 InferReturnType = 1 << 23,
281 OmitDebuggingInfo = 1 << 24,
283 ExpressionTreeConversion = 1 << 25,
285 InvokeSpecialName = 1 << 26
288 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
289 // it's public so that we can use a struct at the callsite
290 public struct FlagsHandle : IDisposable
293 readonly Options invmask, oldval;
295 public FlagsHandle (ResolveContext ec, Options flagsToSet)
296 : this (ec, flagsToSet, flagsToSet)
300 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
304 oldval = ec.flags & mask;
305 ec.flags = (ec.flags & invmask) | (val & mask);
307 // if ((mask & Options.ProbingMode) != 0)
308 // ec.Report.DisableReporting ();
311 public void Dispose ()
313 // if ((invmask & Options.ProbingMode) == 0)
314 // ec.Report.EnableReporting ();
316 ec.flags = (ec.flags & invmask) | oldval;
320 protected Options flags;
323 // Whether we are inside an anonymous method.
325 public AnonymousExpression CurrentAnonymousMethod;
328 // Holds a varible used during collection or object initialization.
330 public Expression CurrentInitializerVariable;
332 public Block CurrentBlock;
334 public readonly IMemberContext MemberContext;
337 /// If this is non-null, points to the current switch statement
339 public Switch Switch;
341 public ResolveContext (IMemberContext mc)
344 throw new ArgumentNullException ();
349 // The default setting comes from the command line option
351 if (mc.Module.Compiler.Settings.Checked)
352 flags |= Options.CheckedScope;
355 // The constant check state is always set to true
357 flags |= Options.ConstantCheckState;
360 public ResolveContext (IMemberContext mc, Options options)
368 public BuiltinTypes BuiltinTypes {
370 return MemberContext.Module.Compiler.BuiltinTypes;
374 public virtual ExplicitBlock ConstructorBlock {
376 return CurrentBlock.Explicit;
380 public virtual FlowBranching CurrentBranching {
385 // The current iterator
387 public Iterator CurrentIterator {
388 get { return CurrentAnonymousMethod as Iterator; }
391 public TypeSpec CurrentType {
392 get { return MemberContext.CurrentType; }
395 public TypeParameter[] CurrentTypeParameters {
396 get { return MemberContext.CurrentTypeParameters; }
399 public MemberCore CurrentMemberDefinition {
400 get { return MemberContext.CurrentMemberDefinition; }
403 public bool ConstantCheckState {
404 get { return (flags & Options.ConstantCheckState) != 0; }
407 public bool DoFlowAnalysis {
408 get { return (flags & Options.DoFlowAnalysis) != 0; }
411 public bool IsInProbingMode {
413 return (flags & Options.ProbingMode) != 0;
417 public bool IsObsolete {
419 // Disables obsolete checks when probing is on
420 return MemberContext.IsObsolete;
424 public bool IsStatic {
426 return MemberContext.IsStatic;
430 public bool IsUnsafe {
432 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
436 public bool IsRuntimeBinder {
438 return Module.Compiler.IsRuntimeBinder;
442 public bool IsVariableCapturingRequired {
444 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
448 public ModuleContainer Module {
450 return MemberContext.Module;
454 public bool OmitStructFlowAnalysis {
455 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
458 public Report Report {
460 return Module.Compiler.Report;
466 public bool MustCaptureVariable (INamedBlockVariable local)
468 if (CurrentAnonymousMethod == null)
471 // FIXME: IsIterator is too aggressive, we should capture only if child
472 // block contains yield
473 if (CurrentAnonymousMethod.IsIterator || CurrentAnonymousMethod is AsyncInitializer)
476 return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
479 public bool HasSet (Options options)
481 return (this.flags & options) == options;
484 public bool HasAny (Options options)
486 return (this.flags & options) != 0;
490 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
491 public FlagsHandle Set (Options options)
493 return new FlagsHandle (this, options);
496 public FlagsHandle With (Options options, bool enable)
498 return new FlagsHandle (this, options, enable ? options : 0);
501 #region IMemberContext Members
503 public string GetSignatureForError ()
505 return MemberContext.GetSignatureForError ();
508 public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
510 return MemberContext.LookupExtensionMethod (extensionType, name, arity);
513 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
515 return MemberContext.LookupNamespaceOrType (name, arity, mode, loc);
518 public FullNamedExpression LookupNamespaceAlias (string name)
520 return MemberContext.LookupNamespaceAlias (name);
527 // This class is used during the Statement.Clone operation
528 // to remap objects that have been cloned.
530 // Since blocks are cloned by Block.Clone, we need a way for
531 // expressions that must reference the block to be cloned
532 // pointing to the new cloned block.
534 public class CloneContext
536 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
538 public void AddBlockMap (Block from, Block to)
540 block_map.Add (from, to);
543 public Block LookupBlock (Block from)
546 if (!block_map.TryGetValue (from, out result)) {
547 result = (Block) from.Clone (this);
554 /// Remaps block to cloned copy if one exists.
556 public Block RemapBlockCopy (Block from)
559 if (!block_map.TryGetValue (from, out mapped_to))
567 // Main compiler context
569 public class CompilerContext
571 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
573 readonly Report report;
574 readonly BuiltinTypes builtin_types;
575 readonly CompilerSettings settings;
577 Dictionary<string, SourceFile> all_source_files;
579 public CompilerContext (CompilerSettings settings, Report report)
581 this.settings = settings;
582 this.report = report;
583 this.builtin_types = new BuiltinTypes ();
584 this.TimeReporter = DisabledTimeReporter;
589 public BuiltinTypes BuiltinTypes {
591 return builtin_types;
595 // Used for special handling of runtime dynamic context mostly
596 // by error reporting but also by member accessibility checks
597 public bool IsRuntimeBinder {
601 public Report Report {
607 public CompilerSettings Settings {
613 public List<CompilationSourceFile> SourceFiles {
615 return settings.SourceFiles;
619 internal TimeReporter TimeReporter {
626 // This is used when we encounter a #line preprocessing directive during parsing
627 // to register additional source file names
629 public SourceFile LookupFile (CompilationSourceFile comp_unit, string name)
631 if (all_source_files == null) {
632 all_source_files = new Dictionary<string, SourceFile> ();
633 foreach (var source in SourceFiles)
634 all_source_files[source.FullPathName] = source;
638 if (!Path.IsPathRooted (name)) {
639 string root = Path.GetDirectoryName (comp_unit.FullPathName);
640 path = Path.Combine (root, name);
645 if (all_source_files.TryGetValue (path, out retval))
648 retval = Location.AddFile (name, path);
649 all_source_files.Add (path, retval);
655 // Generic code emitter context
657 public class BuilderContext
663 /// This flag tracks the `checked' state of the compilation,
664 /// it controls whether we should generate code that does overflow
665 /// checking, or if we generate code that ignores overflows.
667 /// The default setting comes from the command line option to generate
668 /// checked or unchecked code plus any source code changes using the
669 /// checked/unchecked statements or expressions. Contrast this with
670 /// the ConstantCheckState flag.
672 CheckedScope = 1 << 0,
674 OmitDebugInfo = 1 << 2,
676 ConstructorScope = 1 << 3,
681 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
682 // it's public so that we can use a struct at the callsite
683 public struct FlagsHandle : IDisposable
686 readonly Options invmask, oldval;
688 public FlagsHandle (BuilderContext ec, Options flagsToSet)
689 : this (ec, flagsToSet, flagsToSet)
693 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
697 oldval = ec.flags & mask;
698 ec.flags = (ec.flags & invmask) | (val & mask);
701 public void Dispose ()
703 ec.flags = (ec.flags & invmask) | oldval;
707 protected Options flags;
709 public bool HasSet (Options options)
711 return (this.flags & options) == options;
714 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
715 public FlagsHandle With (Options options, bool enable)
717 return new FlagsHandle (this, options, enable ? options : 0);