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;
16 using IKVM.Reflection.Emit;
18 using System.Reflection.Emit;
24 // Implemented by elements which can act as independent contexts
25 // during resolve phase. Used mostly for lookups.
27 public interface IMemberContext : IModuleContext
30 // A scope type context, it can be inflated for generic types
32 TypeSpec CurrentType { get; }
35 // A scope type parameters either VAR or MVAR
37 TypeParameter[] CurrentTypeParameters { get; }
40 // A member definition of the context. For partial types definition use
41 // CurrentTypeDefinition.PartialContainer otherwise the context is local
43 // TODO: Obsolete it in this context, dynamic context cannot guarantee sensible value
45 MemberCore CurrentMemberDefinition { get; }
47 bool IsObsolete { get; }
48 bool IsUnsafe { get; }
49 bool IsStatic { get; }
50 bool HasUnresolvedConstraints { get; }
52 string GetSignatureForError ();
54 IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope);
55 FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104);
56 FullNamedExpression LookupNamespaceAlias (string name);
59 public interface IModuleContext
61 ModuleContainer Module { get; }
65 // Block or statement resolving context
67 public class BlockContext : ResolveContext
69 FlowBranching current_flow_branching;
74 /// The location where return has to jump to return the
77 public Label ReturnLabel; // TODO: It's emit dependant
80 /// If we already defined the ReturnLabel
82 public bool HasReturnLabel;
84 public int FlowOffset;
86 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
89 if (returnType == null)
90 throw new ArgumentNullException ("returnType");
92 this.return_type = returnType;
94 // TODO: check for null value
98 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
99 : this (rc.MemberContext, block, returnType)
102 flags |= ResolveContext.Options.UnsafeScope;
104 if (rc.HasSet (ResolveContext.Options.CheckedScope))
105 flags |= ResolveContext.Options.CheckedScope;
108 public override FlowBranching CurrentBranching {
109 get { return current_flow_branching; }
113 // Starts a new code branching. This inherits the state of all local
114 // variables and parameters from the current branching.
116 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
118 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
119 return current_flow_branching;
123 // Starts a new code branching for block `block'.
125 public FlowBranching StartFlowBranching (Block block)
127 Set (Options.DoFlowAnalysis);
129 current_flow_branching = FlowBranching.CreateBranching (
130 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
131 return current_flow_branching;
134 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
136 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
137 current_flow_branching = branching;
141 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
143 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
144 current_flow_branching = branching;
148 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
150 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
151 current_flow_branching = branching;
155 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
157 FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
158 current_flow_branching = branching;
162 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
164 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
165 current_flow_branching = branching;
170 // Ends a code branching. Merges the state of locals and parameters
171 // from all the children of the ending branching.
173 public bool EndFlowBranching ()
175 FlowBranching old = current_flow_branching;
176 current_flow_branching = current_flow_branching.Parent;
178 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
179 return vector.IsUnreachable;
183 // Kills the current code branching. This throws away any changed state
184 // information and should only be used in case of an error.
186 // FIXME: this is evil
187 public void KillFlowBranching ()
189 current_flow_branching = current_flow_branching.Parent;
193 // This method is used during the Resolution phase to flag the
194 // need to define the ReturnLabel
196 public void NeedReturnLabel ()
199 HasReturnLabel = true;
202 public TypeSpec ReturnType {
203 get { return return_type; }
208 // Expression resolving context
210 public class ResolveContext : IMemberContext
216 /// This flag tracks the `checked' state of the compilation,
217 /// it controls whether we should generate code that does overflow
218 /// checking, or if we generate code that ignores overflows.
220 /// The default setting comes from the command line option to generate
221 /// checked or unchecked code plus any source code changes using the
222 /// checked/unchecked statements or expressions. Contrast this with
223 /// the ConstantCheckState flag.
225 CheckedScope = 1 << 0,
228 /// The constant check state is always set to `true' and cant be changed
229 /// from the command line. The source code can change this setting with
230 /// the `checked' and `unchecked' statements and expressions.
232 ConstantCheckState = 1 << 1,
234 AllCheckStateFlags = CheckedScope | ConstantCheckState,
237 // unsafe { ... } scope
239 UnsafeScope = 1 << 2,
241 FinallyScope = 1 << 4,
242 FieldInitializerScope = 1 << 5,
243 CompoundAssignmentScope = 1 << 6,
244 FixedInitializerScope = 1 << 7,
245 BaseInitializer = 1 << 8,
248 // Inside an enum definition, we do not resolve enumeration values
249 // to their enumerations, but rather to the underlying type/value
250 // This is so EnumVal + EnumValB can be evaluated.
252 // There is no "E operator + (E x, E y)", so during an enum evaluation
253 // we relax the rules
257 ConstantScope = 1 << 10,
259 ConstructorScope = 1 << 11,
261 UsingInitializerScope = 1 << 12,
264 /// Whether control flow analysis is enabled
266 DoFlowAnalysis = 1 << 20,
269 /// Whether control flow analysis is disabled on structs
270 /// (only meaningful when DoFlowAnalysis is set)
272 OmitStructFlowAnalysis = 1 << 21,
275 /// Indicates the current context is in probing mode, no errors are reported.
277 ProbingMode = 1 << 22,
280 // Return and ContextualReturn statements will set the ReturnType
281 // value based on the expression types of each return statement
282 // instead of the method return type which is initially null.
284 InferReturnType = 1 << 23,
286 OmitDebuggingInfo = 1 << 24,
288 ExpressionTreeConversion = 1 << 25,
290 InvokeSpecialName = 1 << 26
293 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
294 // it's public so that we can use a struct at the callsite
295 public struct FlagsHandle : IDisposable
298 readonly Options invmask, oldval;
300 public FlagsHandle (ResolveContext ec, Options flagsToSet)
301 : this (ec, flagsToSet, flagsToSet)
305 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
309 oldval = ec.flags & mask;
310 ec.flags = (ec.flags & invmask) | (val & mask);
312 // if ((mask & Options.ProbingMode) != 0)
313 // ec.Report.DisableReporting ();
316 public void Dispose ()
318 // if ((invmask & Options.ProbingMode) == 0)
319 // ec.Report.EnableReporting ();
321 ec.flags = (ec.flags & invmask) | oldval;
325 protected Options flags;
328 // Whether we are inside an anonymous method.
330 public AnonymousExpression CurrentAnonymousMethod;
333 // Holds a varible used during collection or object initialization.
335 public Expression CurrentInitializerVariable;
337 public Block CurrentBlock;
339 public readonly IMemberContext MemberContext;
342 /// If this is non-null, points to the current switch statement
344 public Switch Switch;
346 public ResolveContext (IMemberContext mc)
349 throw new ArgumentNullException ();
354 // The default setting comes from the command line option
356 if (mc.Module.Compiler.Settings.Checked)
357 flags |= Options.CheckedScope;
360 // The constant check state is always set to true
362 flags |= Options.ConstantCheckState;
365 public ResolveContext (IMemberContext mc, Options options)
373 public BuildinTypes BuildinTypes {
375 return MemberContext.Module.Compiler.BuildinTypes;
379 public virtual ExplicitBlock ConstructorBlock {
381 return CurrentBlock.Explicit;
385 public virtual FlowBranching CurrentBranching {
390 // The current iterator
392 public Iterator CurrentIterator {
393 get { return CurrentAnonymousMethod as Iterator; }
396 public TypeSpec CurrentType {
397 get { return MemberContext.CurrentType; }
400 public TypeParameter[] CurrentTypeParameters {
401 get { return MemberContext.CurrentTypeParameters; }
404 public MemberCore CurrentMemberDefinition {
405 get { return MemberContext.CurrentMemberDefinition; }
408 public bool ConstantCheckState {
409 get { return (flags & Options.ConstantCheckState) != 0; }
412 public bool DoFlowAnalysis {
413 get { return (flags & Options.DoFlowAnalysis) != 0; }
416 public bool HasUnresolvedConstraints {
417 get { return false; }
420 public bool IsInProbingMode {
422 return (flags & Options.ProbingMode) != 0;
426 public bool IsObsolete {
428 // Disables obsolete checks when probing is on
429 return MemberContext.IsObsolete;
433 public bool IsStatic {
435 return MemberContext.IsStatic;
439 public bool IsUnsafe {
441 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
445 public bool IsRuntimeBinder {
447 return Module.Compiler.IsRuntimeBinder;
451 public bool IsVariableCapturingRequired {
453 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
457 public ModuleContainer Module {
459 return MemberContext.Module;
463 public bool OmitStructFlowAnalysis {
464 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
467 public Report Report {
469 return Module.Compiler.Report;
475 public bool MustCaptureVariable (INamedBlockVariable local)
477 if (CurrentAnonymousMethod == null)
480 // FIXME: IsIterator is too aggressive, we should capture only if child
481 // block contains yield
482 if (CurrentAnonymousMethod.IsIterator)
485 return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
488 public bool HasSet (Options options)
490 return (this.flags & options) == options;
493 public bool HasAny (Options options)
495 return (this.flags & options) != 0;
499 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
500 public FlagsHandle Set (Options options)
502 return new FlagsHandle (this, options);
505 public FlagsHandle With (Options options, bool enable)
507 return new FlagsHandle (this, options, enable ? options : 0);
510 #region IMemberContext Members
512 public string GetSignatureForError ()
514 return MemberContext.GetSignatureForError ();
517 public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
519 return MemberContext.LookupExtensionMethod (extensionType, name, arity, ref scope);
522 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
524 return MemberContext.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
527 public FullNamedExpression LookupNamespaceAlias (string name)
529 return MemberContext.LookupNamespaceAlias (name);
536 // This class is used during the Statement.Clone operation
537 // to remap objects that have been cloned.
539 // Since blocks are cloned by Block.Clone, we need a way for
540 // expressions that must reference the block to be cloned
541 // pointing to the new cloned block.
543 public class CloneContext
545 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
547 public void AddBlockMap (Block from, Block to)
549 block_map.Add (from, to);
552 public Block LookupBlock (Block from)
555 if (!block_map.TryGetValue (from, out result)) {
556 result = (Block) from.Clone (this);
563 /// Remaps block to cloned copy if one exists.
565 public Block RemapBlockCopy (Block from)
568 if (!block_map.TryGetValue (from, out mapped_to))
576 // Main compiler context
578 public class CompilerContext
580 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
582 readonly Report report;
583 readonly BuildinTypes buildin_types;
584 readonly CompilerSettings settings;
586 public CompilerContext (CompilerSettings settings, Report report)
588 this.settings = settings;
589 this.report = report;
590 this.buildin_types = new BuildinTypes ();
591 this.TimeReporter = DisabledTimeReporter;
596 public BuildinTypes BuildinTypes {
598 return buildin_types;
602 // Used for special handling of runtime dynamic context mostly
603 // by error reporting but also by member accessibility checks
604 public bool IsRuntimeBinder {
608 public Report Report {
614 public CompilerSettings Settings {
620 internal TimeReporter TimeReporter {
628 // Generic code emitter context
630 public class BuilderContext
636 /// This flag tracks the `checked' state of the compilation,
637 /// it controls whether we should generate code that does overflow
638 /// checking, or if we generate code that ignores overflows.
640 /// The default setting comes from the command line option to generate
641 /// checked or unchecked code plus any source code changes using the
642 /// checked/unchecked statements or expressions. Contrast this with
643 /// the ConstantCheckState flag.
645 CheckedScope = 1 << 0,
648 /// The constant check state is always set to `true' and cant be changed
649 /// from the command line. The source code can change this setting with
650 /// the `checked' and `unchecked' statements and expressions.
652 ConstantCheckState = 1 << 1,
654 AllCheckStateFlags = CheckedScope | ConstantCheckState,
656 OmitDebugInfo = 1 << 2,
658 ConstructorScope = 1 << 3
661 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
662 // it's public so that we can use a struct at the callsite
663 public struct FlagsHandle : IDisposable
666 readonly Options invmask, oldval;
668 public FlagsHandle (BuilderContext ec, Options flagsToSet)
669 : this (ec, flagsToSet, flagsToSet)
673 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
677 oldval = ec.flags & mask;
678 ec.flags = (ec.flags & invmask) | (val & mask);
681 public void Dispose ()
683 ec.flags = (ec.flags & invmask) | oldval;
689 public bool HasSet (Options options)
691 return (this.flags & options) == options;
694 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
695 public FlagsHandle With (Options options, bool enable)
697 return new FlagsHandle (this, options, enable ? options : 0);