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;
14 using System.Reflection.Emit;
19 // Implemented by elements which can act as independent contexts
20 // during resolve phase. Used mostly for lookups.
22 public interface IMemberContext
25 // A scope type context, it can be inflated for generic types
27 TypeSpec CurrentType { get; }
30 // A scope type parameters either VAR or MVAR
32 TypeParameter[] CurrentTypeParameters { get; }
35 // A member definition of the context. For partial types definition use
36 // CurrentTypeDefinition.PartialContainer otherwise the context is local
38 MemberCore CurrentMemberDefinition { get; }
40 bool IsObsolete { get; }
41 bool IsUnsafe { get; }
42 bool IsStatic { get; }
43 bool HasUnresolvedConstraints { get; }
45 string GetSignatureForError ();
47 IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope);
48 FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104);
49 FullNamedExpression LookupNamespaceAlias (string name);
51 CompilerContext Compiler { get; }
55 // Block or statement resolving context
57 public class BlockContext : ResolveContext
59 FlowBranching current_flow_branching;
64 /// The location where return has to jump to return the
67 public Label ReturnLabel; // TODO: It's emit dependant
70 /// If we already defined the ReturnLabel
72 public bool HasReturnLabel;
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; }
103 // Starts a new code branching. This inherits the state of all local
104 // variables and parameters from the current branching.
106 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
108 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
109 return current_flow_branching;
113 // Starts a new code branching for block `block'.
115 public FlowBranching StartFlowBranching (Block block)
117 Set (Options.DoFlowAnalysis);
119 current_flow_branching = FlowBranching.CreateBranching (
120 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
121 return current_flow_branching;
124 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
126 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
127 current_flow_branching = branching;
131 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
133 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
134 current_flow_branching = branching;
138 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
140 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
141 current_flow_branching = branching;
145 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
147 FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
148 current_flow_branching = branching;
152 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
154 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
155 current_flow_branching = branching;
160 // Ends a code branching. Merges the state of locals and parameters
161 // from all the children of the ending branching.
163 public bool EndFlowBranching ()
165 FlowBranching old = current_flow_branching;
166 current_flow_branching = current_flow_branching.Parent;
168 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
169 return vector.IsUnreachable;
173 // Kills the current code branching. This throws away any changed state
174 // information and should only be used in case of an error.
176 // FIXME: this is evil
177 public void KillFlowBranching ()
179 current_flow_branching = current_flow_branching.Parent;
183 // This method is used during the Resolution phase to flag the
184 // need to define the ReturnLabel
186 public void NeedReturnLabel ()
189 HasReturnLabel = true;
192 public TypeSpec ReturnType {
193 get { return return_type; }
198 // Expression resolving context
200 public class ResolveContext : IMemberContext
206 /// This flag tracks the `checked' state of the compilation,
207 /// it controls whether we should generate code that does overflow
208 /// checking, or if we generate code that ignores overflows.
210 /// The default setting comes from the command line option to generate
211 /// checked or unchecked code plus any source code changes using the
212 /// checked/unchecked statements or expressions. Contrast this with
213 /// the ConstantCheckState flag.
215 CheckedScope = 1 << 0,
218 /// The constant check state is always set to `true' and cant be changed
219 /// from the command line. The source code can change this setting with
220 /// the `checked' and `unchecked' statements and expressions.
222 ConstantCheckState = 1 << 1,
224 AllCheckStateFlags = CheckedScope | ConstantCheckState,
227 // unsafe { ... } scope
229 UnsafeScope = 1 << 2,
231 FinallyScope = 1 << 4,
232 FieldInitializerScope = 1 << 5,
233 CompoundAssignmentScope = 1 << 6,
234 FixedInitializerScope = 1 << 7,
235 BaseInitializer = 1 << 8,
238 // Inside an enum definition, we do not resolve enumeration values
239 // to their enumerations, but rather to the underlying type/value
240 // This is so EnumVal + EnumValB can be evaluated.
242 // There is no "E operator + (E x, E y)", so during an enum evaluation
243 // we relax the rules
247 ConstantScope = 1 << 10,
249 ConstructorScope = 1 << 11,
251 UsingInitializerScope = 1 << 12,
254 /// Whether control flow analysis is enabled
256 DoFlowAnalysis = 1 << 20,
259 /// Whether control flow analysis is disabled on structs
260 /// (only meaningful when DoFlowAnalysis is set)
262 OmitStructFlowAnalysis = 1 << 21,
265 /// Indicates the current context is in probing mode, no errors are reported.
267 ProbingMode = 1 << 22,
270 // Return and ContextualReturn statements will set the ReturnType
271 // value based on the expression types of each return statement
272 // instead of the method return type which is initially null.
274 InferReturnType = 1 << 23,
276 OmitDebuggingInfo = 1 << 24,
278 ExpressionTreeConversion = 1 << 25,
280 InvokeSpecialName = 1 << 26
283 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
284 // it's public so that we can use a struct at the callsite
285 public struct FlagsHandle : IDisposable
288 readonly Options invmask, oldval;
290 public FlagsHandle (ResolveContext ec, Options flagsToSet)
291 : this (ec, flagsToSet, flagsToSet)
295 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
299 oldval = ec.flags & mask;
300 ec.flags = (ec.flags & invmask) | (val & mask);
302 // if ((mask & Options.ProbingMode) != 0)
303 // ec.Report.DisableReporting ();
306 public void Dispose ()
308 // if ((invmask & Options.ProbingMode) == 0)
309 // ec.Report.EnableReporting ();
311 ec.flags = (ec.flags & invmask) | oldval;
315 protected Options flags;
318 // Whether we are inside an anonymous method.
320 public AnonymousExpression CurrentAnonymousMethod;
323 // Holds a varible used during collection or object initialization.
325 public Expression CurrentInitializerVariable;
327 public Block CurrentBlock;
329 public IMemberContext MemberContext;
332 /// If this is non-null, points to the current switch statement
334 public Switch Switch;
336 public ResolveContext (IMemberContext mc)
339 throw new ArgumentNullException ();
344 // The default setting comes from the command line option
346 if (RootContext.Checked)
347 flags |= Options.CheckedScope;
350 // The constant check state is always set to true
352 flags |= Options.ConstantCheckState;
355 public ResolveContext (IMemberContext mc, Options options)
361 public CompilerContext Compiler {
362 get { return MemberContext.Compiler; }
365 public virtual ExplicitBlock ConstructorBlock {
367 return CurrentBlock.Explicit;
371 public virtual FlowBranching CurrentBranching {
376 // The current iterator
378 public Iterator CurrentIterator {
379 get { return CurrentAnonymousMethod as Iterator; }
382 public TypeSpec CurrentType {
383 get { return MemberContext.CurrentType; }
386 public TypeParameter[] CurrentTypeParameters {
387 get { return MemberContext.CurrentTypeParameters; }
390 public MemberCore CurrentMemberDefinition {
391 get { return MemberContext.CurrentMemberDefinition; }
394 public bool ConstantCheckState {
395 get { return (flags & Options.ConstantCheckState) != 0; }
398 public bool DoFlowAnalysis {
399 get { return (flags & Options.DoFlowAnalysis) != 0; }
402 public bool HasUnresolvedConstraints {
403 get { return false; }
406 public bool IsInProbingMode {
407 get { return (flags & Options.ProbingMode) != 0; }
410 public bool IsVariableCapturingRequired {
412 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
416 public bool OmitStructFlowAnalysis {
417 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
420 // TODO: Merge with CompilerGeneratedThis
421 public Expression GetThis (Location loc)
423 This my_this = new This (loc);
424 my_this.ResolveBase (this);
428 public bool MustCaptureVariable (INamedBlockVariable local)
430 if (CurrentAnonymousMethod == null)
433 // FIXME: IsIterator is too aggressive, we should capture only if child
434 // block contains yield
435 if (CurrentAnonymousMethod.IsIterator)
438 return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
441 public bool HasSet (Options options)
443 return (this.flags & options) == options;
446 public bool HasAny (Options options)
448 return (this.flags & options) != 0;
451 public Report Report {
453 return Compiler.Report;
457 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
458 public FlagsHandle Set (Options options)
460 return new FlagsHandle (this, options);
463 public FlagsHandle With (Options options, bool enable)
465 return new FlagsHandle (this, options, enable ? options : 0);
468 #region IMemberContext Members
470 public string GetSignatureForError ()
472 return MemberContext.GetSignatureForError ();
475 public bool IsObsolete {
477 // Disables obsolete checks when probing is on
478 return MemberContext.IsObsolete;
482 public bool IsStatic {
483 get { return MemberContext.IsStatic; }
486 public bool IsUnsafe {
487 get { return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe; }
490 public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
492 return MemberContext.LookupExtensionMethod (extensionType, name, arity, ref scope);
495 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
497 return MemberContext.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
500 public FullNamedExpression LookupNamespaceAlias (string name)
502 return MemberContext.LookupNamespaceAlias (name);
509 // This class is used during the Statement.Clone operation
510 // to remap objects that have been cloned.
512 // Since blocks are cloned by Block.Clone, we need a way for
513 // expressions that must reference the block to be cloned
514 // pointing to the new cloned block.
516 public class CloneContext
518 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
520 public void AddBlockMap (Block from, Block to)
522 block_map.Add (from, to);
525 public Block LookupBlock (Block from)
528 if (!block_map.TryGetValue (from, out result)) {
529 result = (Block) from.Clone (this);
536 /// Remaps block to cloned copy if one exists.
538 public Block RemapBlockCopy (Block from)
541 if (!block_map.TryGetValue (from, out mapped_to))
549 // Main compiler context
551 public class CompilerContext
553 readonly Report report;
554 readonly ReflectionMetaImporter meta_importer;
555 readonly PredefinedAttributes attributes;
556 readonly GlobalRootNamespace root;
558 public CompilerContext (ReflectionMetaImporter metaImporter, Report report)
560 this.meta_importer = metaImporter;
561 this.report = report;
563 this.attributes = new PredefinedAttributes ();
564 this.root = new GlobalRootNamespace ();
567 public GlobalRootNamespace GlobalRootNamespace {
573 public bool IsRuntimeBinder { get; set; }
575 public ReflectionMetaImporter MetaImporter {
577 return meta_importer;
581 public PredefinedAttributes PredefinedAttributes {
587 public Report Report {
595 // Generic code emitter context
597 public class BuilderContext
603 /// This flag tracks the `checked' state of the compilation,
604 /// it controls whether we should generate code that does overflow
605 /// checking, or if we generate code that ignores overflows.
607 /// The default setting comes from the command line option to generate
608 /// checked or unchecked code plus any source code changes using the
609 /// checked/unchecked statements or expressions. Contrast this with
610 /// the ConstantCheckState flag.
612 CheckedScope = 1 << 0,
615 /// The constant check state is always set to `true' and cant be changed
616 /// from the command line. The source code can change this setting with
617 /// the `checked' and `unchecked' statements and expressions.
619 ConstantCheckState = 1 << 1,
621 AllCheckStateFlags = CheckedScope | ConstantCheckState,
623 OmitDebugInfo = 1 << 2,
625 ConstructorScope = 1 << 3
628 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
629 // it's public so that we can use a struct at the callsite
630 public struct FlagsHandle : IDisposable
633 readonly Options invmask, oldval;
635 public FlagsHandle (BuilderContext ec, Options flagsToSet)
636 : this (ec, flagsToSet, flagsToSet)
640 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
644 oldval = ec.flags & mask;
645 ec.flags = (ec.flags & invmask) | (val & mask);
648 public void Dispose ()
650 ec.flags = (ec.flags & invmask) | oldval;
656 public bool HasSet (Options options)
658 return (this.flags & options) == options;
661 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
662 public FlagsHandle With (Options options, bool enable)
664 return new FlagsHandle (this, options, enable ? options : 0);