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 BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
77 if (returnType == null)
78 throw new ArgumentNullException ("returnType");
80 this.return_type = returnType;
82 // TODO: check for null value
86 public override FlowBranching CurrentBranching {
87 get { return current_flow_branching; }
91 // Starts a new code branching. This inherits the state of all local
92 // variables and parameters from the current branching.
94 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
96 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
97 return current_flow_branching;
101 // Starts a new code branching for block `block'.
103 public FlowBranching StartFlowBranching (Block block)
105 Set (Options.DoFlowAnalysis);
107 current_flow_branching = FlowBranching.CreateBranching (
108 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
109 return current_flow_branching;
112 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
114 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
115 current_flow_branching = branching;
119 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
121 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
122 current_flow_branching = branching;
126 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
128 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
129 current_flow_branching = branching;
133 public FlowBranchingIterator StartFlowBranching (Iterator iterator)
135 FlowBranchingIterator branching = new FlowBranchingIterator (CurrentBranching, iterator);
136 current_flow_branching = branching;
140 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt, FlowBranching parent)
142 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
143 current_flow_branching = branching;
148 // Ends a code branching. Merges the state of locals and parameters
149 // from all the children of the ending branching.
151 public bool EndFlowBranching ()
153 FlowBranching old = current_flow_branching;
154 current_flow_branching = current_flow_branching.Parent;
156 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
157 return vector.IsUnreachable;
161 // Kills the current code branching. This throws away any changed state
162 // information and should only be used in case of an error.
164 // FIXME: this is evil
165 public void KillFlowBranching ()
167 current_flow_branching = current_flow_branching.Parent;
171 // This method is used during the Resolution phase to flag the
172 // need to define the ReturnLabel
174 public void NeedReturnLabel ()
177 HasReturnLabel = true;
180 public TypeSpec ReturnType {
181 get { return return_type; }
186 // Expression resolving context
188 public class ResolveContext : IMemberContext
194 /// This flag tracks the `checked' state of the compilation,
195 /// it controls whether we should generate code that does overflow
196 /// checking, or if we generate code that ignores overflows.
198 /// The default setting comes from the command line option to generate
199 /// checked or unchecked code plus any source code changes using the
200 /// checked/unchecked statements or expressions. Contrast this with
201 /// the ConstantCheckState flag.
203 CheckedScope = 1 << 0,
206 /// The constant check state is always set to `true' and cant be changed
207 /// from the command line. The source code can change this setting with
208 /// the `checked' and `unchecked' statements and expressions.
210 ConstantCheckState = 1 << 1,
212 AllCheckStateFlags = CheckedScope | ConstantCheckState,
215 // unsafe { ... } scope
217 UnsafeScope = 1 << 2,
219 FinallyScope = 1 << 4,
220 FieldInitializerScope = 1 << 5,
221 CompoundAssignmentScope = 1 << 6,
222 FixedInitializerScope = 1 << 7,
223 BaseInitializer = 1 << 8,
226 // Inside an enum definition, we do not resolve enumeration values
227 // to their enumerations, but rather to the underlying type/value
228 // This is so EnumVal + EnumValB can be evaluated.
230 // There is no "E operator + (E x, E y)", so during an enum evaluation
231 // we relax the rules
235 ConstantScope = 1 << 10,
237 ConstructorScope = 1 << 11,
240 /// Whether control flow analysis is enabled
242 DoFlowAnalysis = 1 << 20,
245 /// Whether control flow analysis is disabled on structs
246 /// (only meaningful when DoFlowAnalysis is set)
248 OmitStructFlowAnalysis = 1 << 21,
251 /// Indicates the current context is in probing mode, no errors are reported.
253 ProbingMode = 1 << 22,
256 // Return and ContextualReturn statements will set the ReturnType
257 // value based on the expression types of each return statement
258 // instead of the method return type which is initially null.
260 InferReturnType = 1 << 23,
262 OmitDebuggingInfo = 1 << 24,
264 ExpressionTreeConversion = 1 << 25,
266 InvokeSpecialName = 1 << 26
269 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
270 // it's public so that we can use a struct at the callsite
271 public struct FlagsHandle : IDisposable
274 readonly Options invmask, oldval;
276 public FlagsHandle (ResolveContext ec, Options flagsToSet)
277 : this (ec, flagsToSet, flagsToSet)
281 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
285 oldval = ec.flags & mask;
286 ec.flags = (ec.flags & invmask) | (val & mask);
288 // if ((mask & Options.ProbingMode) != 0)
289 // ec.Report.DisableReporting ();
292 public void Dispose ()
294 // if ((invmask & Options.ProbingMode) == 0)
295 // ec.Report.EnableReporting ();
297 ec.flags = (ec.flags & invmask) | oldval;
304 // Whether we are inside an anonymous method.
306 public AnonymousExpression CurrentAnonymousMethod;
309 // Holds a varible used during collection or object initialization.
311 public Expression CurrentInitializerVariable;
313 public Block CurrentBlock;
315 public IMemberContext MemberContext;
318 /// If this is non-null, points to the current switch statement
320 public Switch Switch;
322 public ResolveContext (IMemberContext mc)
325 throw new ArgumentNullException ();
330 // The default setting comes from the command line option
332 if (RootContext.Checked)
333 flags |= Options.CheckedScope;
336 // The constant check state is always set to true
338 flags |= Options.ConstantCheckState;
341 public ResolveContext (IMemberContext mc, Options options)
347 public CompilerContext Compiler {
348 get { return MemberContext.Compiler; }
351 public virtual ExplicitBlock ConstructorBlock {
353 return CurrentBlock.Explicit;
357 public virtual FlowBranching CurrentBranching {
362 // The current iterator
364 public Iterator CurrentIterator {
365 get { return CurrentAnonymousMethod as Iterator; }
368 public TypeSpec CurrentType {
369 get { return MemberContext.CurrentType; }
372 public TypeParameter[] CurrentTypeParameters {
373 get { return MemberContext.CurrentTypeParameters; }
376 public MemberCore CurrentMemberDefinition {
377 get { return MemberContext.CurrentMemberDefinition; }
380 public bool ConstantCheckState {
381 get { return (flags & Options.ConstantCheckState) != 0; }
384 public bool DoFlowAnalysis {
385 get { return (flags & Options.DoFlowAnalysis) != 0; }
388 public bool HasUnresolvedConstraints {
389 get { return false; }
392 public bool IsInProbingMode {
393 get { return (flags & Options.ProbingMode) != 0; }
396 public bool IsVariableCapturingRequired {
398 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
402 public bool OmitStructFlowAnalysis {
403 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
406 // TODO: Merge with CompilerGeneratedThis
407 public Expression GetThis (Location loc)
409 This my_this = new This (loc);
410 my_this.ResolveBase (this);
414 public bool MustCaptureVariable (LocalInfo local)
416 if (CurrentAnonymousMethod == null)
419 // FIXME: IsIterator is too aggressive, we should capture only if child
420 // block contains yield
421 if (CurrentAnonymousMethod.IsIterator)
424 return local.Block.Toplevel != CurrentBlock.Toplevel;
427 public bool HasSet (Options options)
429 return (this.flags & options) == options;
432 public bool HasAny (Options options)
434 return (this.flags & options) != 0;
437 public Report Report {
439 return Compiler.Report;
443 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
444 public FlagsHandle Set (Options options)
446 return new FlagsHandle (this, options);
449 public FlagsHandle With (Options options, bool enable)
451 return new FlagsHandle (this, options, enable ? options : 0);
454 #region IMemberContext Members
456 public string GetSignatureForError ()
458 return MemberContext.GetSignatureForError ();
461 public bool IsObsolete {
463 // Disables obsolete checks when probing is on
464 return MemberContext.IsObsolete;
468 public bool IsStatic {
469 get { return MemberContext.IsStatic; }
472 public bool IsUnsafe {
473 get { return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe; }
476 public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
478 return MemberContext.LookupExtensionMethod (extensionType, name, arity, ref scope);
481 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
483 return MemberContext.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
486 public FullNamedExpression LookupNamespaceAlias (string name)
488 return MemberContext.LookupNamespaceAlias (name);
495 // This class is used during the Statement.Clone operation
496 // to remap objects that have been cloned.
498 // Since blocks are cloned by Block.Clone, we need a way for
499 // expressions that must reference the block to be cloned
500 // pointing to the new cloned block.
502 public class CloneContext
504 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
505 Dictionary<LocalInfo, LocalInfo> variable_map;
507 public void AddBlockMap (Block from, Block to)
509 block_map.Add (from, to);
512 public Block LookupBlock (Block from)
515 if (!block_map.TryGetValue (from, out result)) {
516 result = (Block) from.Clone (this);
523 /// Remaps block to cloned copy if one exists.
525 public Block RemapBlockCopy (Block from)
528 if (!block_map.TryGetValue (from, out mapped_to))
534 public void AddVariableMap (LocalInfo from, LocalInfo to)
536 if (variable_map == null)
537 variable_map = new Dictionary<LocalInfo, LocalInfo> ();
538 else if (variable_map.ContainsKey (from))
541 variable_map[from] = to;
544 public LocalInfo LookupVariable (LocalInfo from)
547 return variable_map[from];
548 } catch (KeyNotFoundException) {
549 throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");
555 // Main compiler context
557 public class CompilerContext
559 readonly Report report;
560 readonly ReflectionMetaImporter meta_importer;
562 public CompilerContext (ReflectionMetaImporter metaImporter, Report report)
564 this.meta_importer = metaImporter;
565 this.report = report;
568 public bool IsRuntimeBinder { get; set; }
570 public ReflectionMetaImporter MetaImporter {
572 return meta_importer;
576 public Report Report {
582 //public PredefinedAttributes PredefinedAttributes {
583 // get { throw new NotImplementedException (); }
588 // Generic code emitter context
590 public class BuilderContext
596 /// This flag tracks the `checked' state of the compilation,
597 /// it controls whether we should generate code that does overflow
598 /// checking, or if we generate code that ignores overflows.
600 /// The default setting comes from the command line option to generate
601 /// checked or unchecked code plus any source code changes using the
602 /// checked/unchecked statements or expressions. Contrast this with
603 /// the ConstantCheckState flag.
605 CheckedScope = 1 << 0,
608 /// The constant check state is always set to `true' and cant be changed
609 /// from the command line. The source code can change this setting with
610 /// the `checked' and `unchecked' statements and expressions.
612 ConstantCheckState = 1 << 1,
614 AllCheckStateFlags = CheckedScope | ConstantCheckState,
616 OmitDebugInfo = 1 << 2,
618 ConstructorScope = 1 << 3
621 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
622 // it's public so that we can use a struct at the callsite
623 public struct FlagsHandle : IDisposable
626 readonly Options invmask, oldval;
628 public FlagsHandle (BuilderContext ec, Options flagsToSet)
629 : this (ec, flagsToSet, flagsToSet)
633 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
637 oldval = ec.flags & mask;
638 ec.flags = (ec.flags & invmask) | (val & mask);
641 public void Dispose ()
643 ec.flags = (ec.flags & invmask) | oldval;
649 public bool HasSet (Options options)
651 return (this.flags & options) == options;
654 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
655 public FlagsHandle With (Options options, bool enable)
657 return new FlagsHandle (this, options, enable ? options : 0);