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;
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 Type CurrentType { get; }
30 // A scope type parameters either VAR or MVAR
32 TypeParameter[] CurrentTypeParameters { get; }
35 // A type definition of the type context. For partial types definition use
36 // CurrentTypeDefinition.PartialContainer otherwise the context is local
38 // TODO: CurrentType.Definition
40 TypeContainer CurrentTypeDefinition { get; }
42 bool IsObsolete { get; }
43 bool IsUnsafe { get; }
44 bool IsStatic { get; }
46 string GetSignatureForError ();
48 ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name, Location loc);
49 FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104);
50 FullNamedExpression LookupNamespaceAlias (string name);
54 // Block or statement resolving context
56 public class BlockContext : ResolveContext
58 FlowBranching current_flow_branching;
60 public TypeInferenceContext ReturnTypeInference;
65 /// The location where return has to jump to return the
68 public Label ReturnLabel; // TODO: It's emit dependant
71 /// If we already defined the ReturnLabel
73 public bool HasReturnLabel;
75 public BlockContext (IMemberContext mc, ExplicitBlock block, Type returnType)
78 if (returnType == null)
79 throw new ArgumentNullException ("returnType");
81 this.return_type = returnType;
83 // TODO: check for null value
87 public override FlowBranching CurrentBranching {
88 get { return current_flow_branching; }
92 // Starts a new code branching. This inherits the state of all local
93 // variables and parameters from the current branching.
95 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
97 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
98 return current_flow_branching;
102 // Starts a new code branching for block `block'.
104 public FlowBranching StartFlowBranching (Block block)
106 Set (Options.DoFlowAnalysis);
108 current_flow_branching = FlowBranching.CreateBranching (
109 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
110 return current_flow_branching;
113 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
115 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
116 current_flow_branching = branching;
120 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
122 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
123 current_flow_branching = branching;
127 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
129 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
130 current_flow_branching = branching;
134 public FlowBranchingIterator StartFlowBranching (Iterator iterator)
136 FlowBranchingIterator branching = new FlowBranchingIterator (CurrentBranching, iterator);
137 current_flow_branching = branching;
141 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt, FlowBranching parent)
143 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
144 current_flow_branching = branching;
149 // Ends a code branching. Merges the state of locals and parameters
150 // from all the children of the ending branching.
152 public bool EndFlowBranching ()
154 FlowBranching old = current_flow_branching;
155 current_flow_branching = current_flow_branching.Parent;
157 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
158 return vector.IsUnreachable;
162 // Kills the current code branching. This throws away any changed state
163 // information and should only be used in case of an error.
165 // FIXME: this is evil
166 public void KillFlowBranching ()
168 current_flow_branching = current_flow_branching.Parent;
172 // This method is used during the Resolution phase to flag the
173 // need to define the ReturnLabel
175 public void NeedReturnLabel ()
178 HasReturnLabel = true;
181 public Type ReturnType {
182 get { return return_type; }
187 // Expression resolving context
189 public class ResolveContext : IMemberContext
195 /// This flag tracks the `checked' state of the compilation,
196 /// it controls whether we should generate code that does overflow
197 /// checking, or if we generate code that ignores overflows.
199 /// The default setting comes from the command line option to generate
200 /// checked or unchecked code plus any source code changes using the
201 /// checked/unchecked statements or expressions. Contrast this with
202 /// the ConstantCheckState flag.
204 CheckedScope = 1 << 0,
207 /// The constant check state is always set to `true' and cant be changed
208 /// from the command line. The source code can change this setting with
209 /// the `checked' and `unchecked' statements and expressions.
211 ConstantCheckState = 1 << 1,
213 AllCheckStateFlags = CheckedScope | ConstantCheckState,
216 // unsafe { ... } scope
218 UnsafeScope = 1 << 2,
220 FinallyScope = 1 << 4,
221 FieldInitializerScope = 1 << 5,
222 CompoundAssignmentScope = 1 << 6,
223 FixedInitializerScope = 1 << 7,
224 BaseInitializer = 1 << 8,
227 // Inside an enum definition, we do not resolve enumeration values
228 // to their enumerations, but rather to the underlying type/value
229 // This is so EnumVal + EnumValB can be evaluated.
231 // There is no "E operator + (E x, E y)", so during an enum evaluation
232 // we relax the rules
236 ConstantScope = 1 << 10,
238 ConstructorScope = 1 << 11,
241 /// Whether control flow analysis is enabled
243 DoFlowAnalysis = 1 << 20,
246 /// Whether control flow analysis is disabled on structs
247 /// (only meaningful when DoFlowAnalysis is set)
249 OmitStructFlowAnalysis = 1 << 21,
252 /// Indicates the current context is in probing mode, no errors are reported.
254 ProbingMode = 1 << 22,
257 // Return and ContextualReturn statements will set the ReturnType
258 // value based on the expression types of each return statement
259 // instead of the method return type which is initially null.
261 InferReturnType = 1 << 23,
263 OmitDebuggingInfo = 1 << 24
266 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
267 // it's public so that we can use a struct at the callsite
268 public struct FlagsHandle : IDisposable
271 readonly Options invmask, oldval;
273 public FlagsHandle (ResolveContext ec, Options flagsToSet)
274 : this (ec, flagsToSet, flagsToSet)
278 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
282 oldval = ec.flags & mask;
283 ec.flags = (ec.flags & invmask) | (val & mask);
285 if ((mask & Options.ProbingMode) != 0)
286 Report.DisableReporting ();
289 public void Dispose ()
291 if ((invmask & Options.ProbingMode) == 0)
292 Report.EnableReporting ();
294 ec.flags = (ec.flags & invmask) | oldval;
301 // Whether we are inside an anonymous method.
303 public AnonymousExpression CurrentAnonymousMethod;
306 // Holds a varible used during collection or object initialization.
308 public Expression CurrentInitializerVariable;
310 public Block CurrentBlock;
312 public IMemberContext MemberContext;
315 /// If this is non-null, points to the current switch statement
317 public Switch Switch;
319 public ResolveContext (IMemberContext mc)
324 // The default setting comes from the command line option
326 if (RootContext.Checked)
327 flags |= Options.CheckedScope;
330 // The constant check state is always set to true
332 flags |= Options.ConstantCheckState;
335 public ResolveContext (IMemberContext mc, Options options)
341 public virtual FlowBranching CurrentBranching {
346 // The current iterator
348 public Iterator CurrentIterator {
349 get { return CurrentAnonymousMethod as Iterator; }
352 public Type CurrentType {
353 get { return MemberContext.CurrentType; }
356 public TypeParameter[] CurrentTypeParameters {
357 get { return MemberContext.CurrentTypeParameters; }
360 public TypeContainer CurrentTypeDefinition {
361 get { return MemberContext.CurrentTypeDefinition; }
364 public bool ConstantCheckState {
365 get { return (flags & Options.ConstantCheckState) != 0; }
368 public bool DoFlowAnalysis {
369 get { return (flags & Options.DoFlowAnalysis) != 0; }
372 public bool IsInProbingMode {
373 get { return (flags & Options.ProbingMode) != 0; }
376 public bool IsVariableCapturingRequired {
378 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
382 public bool OmitStructFlowAnalysis {
383 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
386 // TODO: Merge with CompilerGeneratedThis
387 public Expression GetThis (Location loc)
390 if (CurrentBlock != null)
391 my_this = new This (CurrentBlock, loc);
393 my_this = new This (loc);
395 if (!my_this.ResolveBase (this))
401 public bool MustCaptureVariable (LocalInfo local)
403 if (CurrentAnonymousMethod == null)
406 // FIXME: IsIterator is too aggressive, we should capture only if child
407 // block contains yield
408 if (CurrentAnonymousMethod.IsIterator)
411 return local.Block.Toplevel != CurrentBlock.Toplevel;
414 public bool HasSet (Options options)
416 return (this.flags & options) == options;
419 public bool HasAny (Options options)
421 return (this.flags & options) != 0;
424 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
425 public FlagsHandle Set (Options options)
427 return new FlagsHandle (this, options);
430 public FlagsHandle With (Options options, bool enable)
432 return new FlagsHandle (this, options, enable ? options : 0);
435 public FlagsHandle WithFlowAnalysis (bool do_flow_analysis, bool omit_struct_analysis)
438 (do_flow_analysis ? Options.DoFlowAnalysis : 0) |
439 (omit_struct_analysis ? Options.OmitStructFlowAnalysis : 0);
440 return new FlagsHandle (this, Options.DoFlowAnalysis | Options.OmitStructFlowAnalysis, newflags);
443 #region IMemberContext Members
445 public string GetSignatureForError ()
447 return MemberContext.GetSignatureForError ();
450 public bool IsObsolete {
452 // Disables obsolete checks when probing is on
453 return IsInProbingMode || MemberContext.IsObsolete;
457 public bool IsStatic {
458 get { return MemberContext.IsStatic; }
461 public bool IsUnsafe {
462 get { return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe; }
465 public ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name, Location loc)
467 return MemberContext.LookupExtensionMethod (extensionType, name, loc);
470 public FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104)
472 return MemberContext.LookupNamespaceOrType (name, loc, ignore_cs0104);
475 public FullNamedExpression LookupNamespaceAlias (string name)
477 return MemberContext.LookupNamespaceAlias (name);
484 // This class is used during the Statement.Clone operation
485 // to remap objects that have been cloned.
487 // Since blocks are cloned by Block.Clone, we need a way for
488 // expressions that must reference the block to be cloned
489 // pointing to the new cloned block.
491 public class CloneContext
493 Hashtable block_map = new Hashtable ();
494 Hashtable variable_map;
496 public void AddBlockMap (Block from, Block to)
498 if (block_map.Contains (from))
500 block_map[from] = to;
503 public Block LookupBlock (Block from)
505 Block result = (Block) block_map[from];
507 if (result == null) {
508 result = (Block) from.Clone (this);
509 block_map[from] = result;
516 /// Remaps block to cloned copy if one exists.
518 public Block RemapBlockCopy (Block from)
520 Block mapped_to = (Block) block_map[from];
521 if (mapped_to == null)
527 public void AddVariableMap (LocalInfo from, LocalInfo to)
529 if (variable_map == null)
530 variable_map = new Hashtable ();
532 if (variable_map.Contains (from))
534 variable_map[from] = to;
537 public LocalInfo LookupVariable (LocalInfo from)
539 LocalInfo result = (LocalInfo) variable_map[from];
542 throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");