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 ExtensionMethodGroupExpr LookupExtensionMethod (TypeSpec extensionType, string name, int arity, Location loc);
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;
61 public TypeInferenceContext ReturnTypeInference;
66 /// The location where return has to jump to return the
69 public Label ReturnLabel; // TODO: It's emit dependant
72 /// If we already defined the ReturnLabel
74 public bool HasReturnLabel;
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 override FlowBranching CurrentBranching {
89 get { return current_flow_branching; }
93 // Starts a new code branching. This inherits the state of all local
94 // variables and parameters from the current branching.
96 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
98 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
99 return current_flow_branching;
103 // Starts a new code branching for block `block'.
105 public FlowBranching StartFlowBranching (Block block)
107 Set (Options.DoFlowAnalysis);
109 current_flow_branching = FlowBranching.CreateBranching (
110 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
111 return current_flow_branching;
114 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
116 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
117 current_flow_branching = branching;
121 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
123 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
124 current_flow_branching = branching;
128 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
130 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
131 current_flow_branching = branching;
135 public FlowBranchingIterator StartFlowBranching (Iterator iterator)
137 FlowBranchingIterator branching = new FlowBranchingIterator (CurrentBranching, iterator);
138 current_flow_branching = branching;
142 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt, FlowBranching parent)
144 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
145 current_flow_branching = branching;
150 // Ends a code branching. Merges the state of locals and parameters
151 // from all the children of the ending branching.
153 public bool EndFlowBranching ()
155 FlowBranching old = current_flow_branching;
156 current_flow_branching = current_flow_branching.Parent;
158 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
159 return vector.IsUnreachable;
163 // Kills the current code branching. This throws away any changed state
164 // information and should only be used in case of an error.
166 // FIXME: this is evil
167 public void KillFlowBranching ()
169 current_flow_branching = current_flow_branching.Parent;
173 // This method is used during the Resolution phase to flag the
174 // need to define the ReturnLabel
176 public void NeedReturnLabel ()
179 HasReturnLabel = true;
182 public TypeSpec ReturnType {
183 get { return return_type; }
188 // Expression resolving context
190 public class ResolveContext : IMemberContext
196 /// This flag tracks the `checked' state of the compilation,
197 /// it controls whether we should generate code that does overflow
198 /// checking, or if we generate code that ignores overflows.
200 /// The default setting comes from the command line option to generate
201 /// checked or unchecked code plus any source code changes using the
202 /// checked/unchecked statements or expressions. Contrast this with
203 /// the ConstantCheckState flag.
205 CheckedScope = 1 << 0,
208 /// The constant check state is always set to `true' and cant be changed
209 /// from the command line. The source code can change this setting with
210 /// the `checked' and `unchecked' statements and expressions.
212 ConstantCheckState = 1 << 1,
214 AllCheckStateFlags = CheckedScope | ConstantCheckState,
217 // unsafe { ... } scope
219 UnsafeScope = 1 << 2,
221 FinallyScope = 1 << 4,
222 FieldInitializerScope = 1 << 5,
223 CompoundAssignmentScope = 1 << 6,
224 FixedInitializerScope = 1 << 7,
225 BaseInitializer = 1 << 8,
228 // Inside an enum definition, we do not resolve enumeration values
229 // to their enumerations, but rather to the underlying type/value
230 // This is so EnumVal + EnumValB can be evaluated.
232 // There is no "E operator + (E x, E y)", so during an enum evaluation
233 // we relax the rules
237 ConstantScope = 1 << 10,
239 ConstructorScope = 1 << 11,
242 /// Whether control flow analysis is enabled
244 DoFlowAnalysis = 1 << 20,
247 /// Whether control flow analysis is disabled on structs
248 /// (only meaningful when DoFlowAnalysis is set)
250 OmitStructFlowAnalysis = 1 << 21,
253 /// Indicates the current context is in probing mode, no errors are reported.
255 ProbingMode = 1 << 22,
258 // Return and ContextualReturn statements will set the ReturnType
259 // value based on the expression types of each return statement
260 // instead of the method return type which is initially null.
262 InferReturnType = 1 << 23,
264 OmitDebuggingInfo = 1 << 24,
266 ExpressionTreeConversion = 1 << 25,
268 InvokeSpecialName = 1 << 26
271 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
272 // it's public so that we can use a struct at the callsite
273 public struct FlagsHandle : IDisposable
276 readonly Options invmask, oldval;
278 public FlagsHandle (ResolveContext ec, Options flagsToSet)
279 : this (ec, flagsToSet, flagsToSet)
283 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
287 oldval = ec.flags & mask;
288 ec.flags = (ec.flags & invmask) | (val & mask);
290 // if ((mask & Options.ProbingMode) != 0)
291 // ec.Report.DisableReporting ();
294 public void Dispose ()
296 // if ((invmask & Options.ProbingMode) == 0)
297 // ec.Report.EnableReporting ();
299 ec.flags = (ec.flags & invmask) | oldval;
306 // Whether we are inside an anonymous method.
308 public AnonymousExpression CurrentAnonymousMethod;
311 // Holds a varible used during collection or object initialization.
313 public Expression CurrentInitializerVariable;
315 public Block CurrentBlock;
317 public IMemberContext MemberContext;
320 /// If this is non-null, points to the current switch statement
322 public Switch Switch;
324 public ResolveContext (IMemberContext mc)
327 throw new ArgumentNullException ();
332 // The default setting comes from the command line option
334 if (RootContext.Checked)
335 flags |= Options.CheckedScope;
338 // The constant check state is always set to true
340 flags |= Options.ConstantCheckState;
343 public ResolveContext (IMemberContext mc, Options options)
349 public CompilerContext Compiler {
350 get { return MemberContext.Compiler; }
353 public virtual FlowBranching CurrentBranching {
358 // The current iterator
360 public Iterator CurrentIterator {
361 get { return CurrentAnonymousMethod as Iterator; }
364 public TypeSpec CurrentType {
365 get { return MemberContext.CurrentType; }
368 public TypeParameter[] CurrentTypeParameters {
369 get { return MemberContext.CurrentTypeParameters; }
372 public MemberCore CurrentMemberDefinition {
373 get { return MemberContext.CurrentMemberDefinition; }
376 public bool ConstantCheckState {
377 get { return (flags & Options.ConstantCheckState) != 0; }
380 public bool DoFlowAnalysis {
381 get { return (flags & Options.DoFlowAnalysis) != 0; }
384 public bool HasUnresolvedConstraints {
385 get { return false; }
388 public bool IsInProbingMode {
389 get { return (flags & Options.ProbingMode) != 0; }
392 public bool IsVariableCapturingRequired {
394 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
398 public bool OmitStructFlowAnalysis {
399 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
402 // TODO: Merge with CompilerGeneratedThis
403 public Expression GetThis (Location loc)
406 if (CurrentBlock != null)
407 my_this = new This (CurrentBlock, loc);
409 my_this = new This (loc);
411 if (!my_this.ResolveBase (this))
417 public bool MustCaptureVariable (LocalInfo local)
419 if (CurrentAnonymousMethod == null)
422 // FIXME: IsIterator is too aggressive, we should capture only if child
423 // block contains yield
424 if (CurrentAnonymousMethod.IsIterator)
427 return local.Block.Toplevel != CurrentBlock.Toplevel;
430 public bool HasSet (Options options)
432 return (this.flags & options) == options;
435 public bool HasAny (Options options)
437 return (this.flags & options) != 0;
440 public Report Report {
442 return Compiler.Report;
446 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
447 public FlagsHandle Set (Options options)
449 return new FlagsHandle (this, options);
452 public FlagsHandle With (Options options, bool enable)
454 return new FlagsHandle (this, options, enable ? options : 0);
457 #region IMemberContext Members
459 public string GetSignatureForError ()
461 return MemberContext.GetSignatureForError ();
464 public bool IsObsolete {
466 // Disables obsolete checks when probing is on
467 return IsInProbingMode || MemberContext.IsObsolete;
471 public bool IsStatic {
472 get { return MemberContext.IsStatic; }
475 public bool IsUnsafe {
476 get { return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe; }
479 public ExtensionMethodGroupExpr LookupExtensionMethod (TypeSpec extensionType, string name, int arity, Location loc)
481 return MemberContext.LookupExtensionMethod (extensionType, name, arity, loc);
484 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
486 return MemberContext.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
489 public FullNamedExpression LookupNamespaceAlias (string name)
491 return MemberContext.LookupNamespaceAlias (name);
498 // This class is used during the Statement.Clone operation
499 // to remap objects that have been cloned.
501 // Since blocks are cloned by Block.Clone, we need a way for
502 // expressions that must reference the block to be cloned
503 // pointing to the new cloned block.
505 public class CloneContext
507 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
508 Dictionary<LocalInfo, LocalInfo> variable_map;
510 public void AddBlockMap (Block from, Block to)
512 if (block_map.ContainsKey (from))
514 block_map[from] = to;
517 public Block LookupBlock (Block from)
520 if (!block_map.TryGetValue (from, out result)) {
521 result = (Block) from.Clone (this);
522 block_map [from] = result;
529 /// Remaps block to cloned copy if one exists.
531 public Block RemapBlockCopy (Block from)
534 if (!block_map.TryGetValue (from, out mapped_to))
540 public void AddVariableMap (LocalInfo from, LocalInfo to)
542 if (variable_map == null)
543 variable_map = new Dictionary<LocalInfo, LocalInfo> ();
544 else if (variable_map.ContainsKey (from))
547 variable_map[from] = to;
550 public LocalInfo LookupVariable (LocalInfo from)
553 return variable_map[from];
554 } catch (KeyNotFoundException) {
555 throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");
561 // Main compiler context
563 public class CompilerContext
565 readonly Report report;
567 public CompilerContext (Report report)
569 this.report = report;
572 public bool IsRuntimeBinder { get; set; }
574 public Report Report {
575 get { return report; }
578 //public PredefinedAttributes PredefinedAttributes {
579 // get { throw new NotImplementedException (); }
584 // Generic code emitter context
586 public class BuilderContext
592 /// This flag tracks the `checked' state of the compilation,
593 /// it controls whether we should generate code that does overflow
594 /// checking, or if we generate code that ignores overflows.
596 /// The default setting comes from the command line option to generate
597 /// checked or unchecked code plus any source code changes using the
598 /// checked/unchecked statements or expressions. Contrast this with
599 /// the ConstantCheckState flag.
601 CheckedScope = 1 << 0,
604 /// The constant check state is always set to `true' and cant be changed
605 /// from the command line. The source code can change this setting with
606 /// the `checked' and `unchecked' statements and expressions.
608 ConstantCheckState = 1 << 1,
610 AllCheckStateFlags = CheckedScope | ConstantCheckState,
612 OmitDebugInfo = 1 << 2,
614 ConstructorScope = 1 << 3
617 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
618 // it's public so that we can use a struct at the callsite
619 public struct FlagsHandle : IDisposable
622 readonly Options invmask, oldval;
624 public FlagsHandle (BuilderContext ec, Options flagsToSet)
625 : this (ec, flagsToSet, flagsToSet)
629 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
633 oldval = ec.flags & mask;
634 ec.flags = (ec.flags & invmask) | (val & mask);
637 public void Dispose ()
639 ec.flags = (ec.flags & invmask) | oldval;
645 public bool HasSet (Options options)
647 return (this.flags & options) == options;
650 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
651 public FlagsHandle With (Options options, bool enable)
653 return new FlagsHandle (this, options, enable ? options : 0);