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
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; }
51 ModuleContainer Module { get; }
53 string GetSignatureForError ();
55 IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope);
56 FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104);
57 FullNamedExpression LookupNamespaceAlias (string name);
61 // Block or statement resolving context
63 public class BlockContext : ResolveContext
65 FlowBranching current_flow_branching;
70 /// The location where return has to jump to return the
73 public Label ReturnLabel; // TODO: It's emit dependant
76 /// If we already defined the ReturnLabel
78 public bool HasReturnLabel;
80 public int FlowOffset;
82 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
85 if (returnType == null)
86 throw new ArgumentNullException ("returnType");
88 this.return_type = returnType;
90 // TODO: check for null value
94 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
95 : this (rc.MemberContext, block, returnType)
98 flags |= ResolveContext.Options.UnsafeScope;
100 if (rc.HasSet (ResolveContext.Options.CheckedScope))
101 flags |= ResolveContext.Options.CheckedScope;
104 public override FlowBranching CurrentBranching {
105 get { return current_flow_branching; }
109 // Starts a new code branching. This inherits the state of all local
110 // variables and parameters from the current branching.
112 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
114 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
115 return current_flow_branching;
119 // Starts a new code branching for block `block'.
121 public FlowBranching StartFlowBranching (Block block)
123 Set (Options.DoFlowAnalysis);
125 current_flow_branching = FlowBranching.CreateBranching (
126 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
127 return current_flow_branching;
130 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
132 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
133 current_flow_branching = branching;
137 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
139 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
140 current_flow_branching = branching;
144 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
146 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
147 current_flow_branching = branching;
151 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
153 FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
154 current_flow_branching = branching;
158 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
160 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
161 current_flow_branching = branching;
166 // Ends a code branching. Merges the state of locals and parameters
167 // from all the children of the ending branching.
169 public bool EndFlowBranching ()
171 FlowBranching old = current_flow_branching;
172 current_flow_branching = current_flow_branching.Parent;
174 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
175 return vector.IsUnreachable;
179 // Kills the current code branching. This throws away any changed state
180 // information and should only be used in case of an error.
182 // FIXME: this is evil
183 public void KillFlowBranching ()
185 current_flow_branching = current_flow_branching.Parent;
189 // This method is used during the Resolution phase to flag the
190 // need to define the ReturnLabel
192 public void NeedReturnLabel ()
195 HasReturnLabel = true;
198 public TypeSpec ReturnType {
199 get { return return_type; }
204 // Expression resolving context
206 public class ResolveContext : IMemberContext
212 /// This flag tracks the `checked' state of the compilation,
213 /// it controls whether we should generate code that does overflow
214 /// checking, or if we generate code that ignores overflows.
216 /// The default setting comes from the command line option to generate
217 /// checked or unchecked code plus any source code changes using the
218 /// checked/unchecked statements or expressions. Contrast this with
219 /// the ConstantCheckState flag.
221 CheckedScope = 1 << 0,
224 /// The constant check state is always set to `true' and cant be changed
225 /// from the command line. The source code can change this setting with
226 /// the `checked' and `unchecked' statements and expressions.
228 ConstantCheckState = 1 << 1,
230 AllCheckStateFlags = CheckedScope | ConstantCheckState,
233 // unsafe { ... } scope
235 UnsafeScope = 1 << 2,
237 FinallyScope = 1 << 4,
238 FieldInitializerScope = 1 << 5,
239 CompoundAssignmentScope = 1 << 6,
240 FixedInitializerScope = 1 << 7,
241 BaseInitializer = 1 << 8,
244 // Inside an enum definition, we do not resolve enumeration values
245 // to their enumerations, but rather to the underlying type/value
246 // This is so EnumVal + EnumValB can be evaluated.
248 // There is no "E operator + (E x, E y)", so during an enum evaluation
249 // we relax the rules
253 ConstantScope = 1 << 10,
255 ConstructorScope = 1 << 11,
257 UsingInitializerScope = 1 << 12,
260 /// Whether control flow analysis is enabled
262 DoFlowAnalysis = 1 << 20,
265 /// Whether control flow analysis is disabled on structs
266 /// (only meaningful when DoFlowAnalysis is set)
268 OmitStructFlowAnalysis = 1 << 21,
271 /// Indicates the current context is in probing mode, no errors are reported.
273 ProbingMode = 1 << 22,
276 // Return and ContextualReturn statements will set the ReturnType
277 // value based on the expression types of each return statement
278 // instead of the method return type which is initially null.
280 InferReturnType = 1 << 23,
282 OmitDebuggingInfo = 1 << 24,
284 ExpressionTreeConversion = 1 << 25,
286 InvokeSpecialName = 1 << 26
289 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
290 // it's public so that we can use a struct at the callsite
291 public struct FlagsHandle : IDisposable
294 readonly Options invmask, oldval;
296 public FlagsHandle (ResolveContext ec, Options flagsToSet)
297 : this (ec, flagsToSet, flagsToSet)
301 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
305 oldval = ec.flags & mask;
306 ec.flags = (ec.flags & invmask) | (val & mask);
308 // if ((mask & Options.ProbingMode) != 0)
309 // ec.Report.DisableReporting ();
312 public void Dispose ()
314 // if ((invmask & Options.ProbingMode) == 0)
315 // ec.Report.EnableReporting ();
317 ec.flags = (ec.flags & invmask) | oldval;
321 protected Options flags;
324 // Whether we are inside an anonymous method.
326 public AnonymousExpression CurrentAnonymousMethod;
329 // Holds a varible used during collection or object initialization.
331 public Expression CurrentInitializerVariable;
333 public Block CurrentBlock;
335 public readonly IMemberContext MemberContext;
338 /// If this is non-null, points to the current switch statement
340 public Switch Switch;
342 public ResolveContext (IMemberContext mc)
345 throw new ArgumentNullException ();
350 // The default setting comes from the command line option
352 if (RootContext.Checked)
353 flags |= Options.CheckedScope;
356 // The constant check state is always set to true
358 flags |= Options.ConstantCheckState;
361 public ResolveContext (IMemberContext mc, Options options)
369 public virtual ExplicitBlock ConstructorBlock {
371 return CurrentBlock.Explicit;
375 public virtual FlowBranching CurrentBranching {
380 // The current iterator
382 public Iterator CurrentIterator {
383 get { return CurrentAnonymousMethod as Iterator; }
386 public TypeSpec CurrentType {
387 get { return MemberContext.CurrentType; }
390 public TypeParameter[] CurrentTypeParameters {
391 get { return MemberContext.CurrentTypeParameters; }
394 public MemberCore CurrentMemberDefinition {
395 get { return MemberContext.CurrentMemberDefinition; }
398 public bool ConstantCheckState {
399 get { return (flags & Options.ConstantCheckState) != 0; }
402 public bool DoFlowAnalysis {
403 get { return (flags & Options.DoFlowAnalysis) != 0; }
406 public bool HasUnresolvedConstraints {
407 get { return false; }
410 public bool IsInProbingMode {
412 return (flags & Options.ProbingMode) != 0;
416 public bool IsObsolete {
418 // Disables obsolete checks when probing is on
419 return MemberContext.IsObsolete;
423 public bool IsStatic {
425 return MemberContext.IsStatic;
429 public bool IsUnsafe {
431 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
435 public bool IsRuntimeBinder {
437 return Module.Compiler.IsRuntimeBinder;
441 public bool IsVariableCapturingRequired {
443 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
447 public ModuleContainer Module {
449 return MemberContext.Module;
453 public bool OmitStructFlowAnalysis {
454 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
457 public Report Report {
459 return Module.Compiler.Report;
465 public bool MustCaptureVariable (INamedBlockVariable local)
467 if (CurrentAnonymousMethod == null)
470 // FIXME: IsIterator is too aggressive, we should capture only if child
471 // block contains yield
472 if (CurrentAnonymousMethod.IsIterator)
475 return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
478 public bool HasSet (Options options)
480 return (this.flags & options) == options;
483 public bool HasAny (Options options)
485 return (this.flags & options) != 0;
489 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
490 public FlagsHandle Set (Options options)
492 return new FlagsHandle (this, options);
495 public FlagsHandle With (Options options, bool enable)
497 return new FlagsHandle (this, options, enable ? options : 0);
500 #region IMemberContext Members
502 public string GetSignatureForError ()
504 return MemberContext.GetSignatureForError ();
507 public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
509 return MemberContext.LookupExtensionMethod (extensionType, name, arity, ref scope);
512 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
514 return MemberContext.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
517 public FullNamedExpression LookupNamespaceAlias (string name)
519 return MemberContext.LookupNamespaceAlias (name);
526 // This class is used during the Statement.Clone operation
527 // to remap objects that have been cloned.
529 // Since blocks are cloned by Block.Clone, we need a way for
530 // expressions that must reference the block to be cloned
531 // pointing to the new cloned block.
533 public class CloneContext
535 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
537 public void AddBlockMap (Block from, Block to)
539 block_map.Add (from, to);
542 public Block LookupBlock (Block from)
545 if (!block_map.TryGetValue (from, out result)) {
546 result = (Block) from.Clone (this);
553 /// Remaps block to cloned copy if one exists.
555 public Block RemapBlockCopy (Block from)
558 if (!block_map.TryGetValue (from, out mapped_to))
566 // Main compiler context
568 public class CompilerContext
570 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
572 readonly Report report;
573 readonly BuildinTypes buildin_types;
575 public CompilerContext (Report report)
577 this.report = report;
578 this.buildin_types = new BuildinTypes ();
579 this.TimeReporter = DisabledTimeReporter;
584 public BuildinTypes BuildinTypes {
586 return buildin_types;
590 // Used for special handling of runtime dynamic context mostly
591 // by error reporting but also by member accessibility checks
592 public bool IsRuntimeBinder { get; set; }
594 public Report Report {
600 internal TimeReporter TimeReporter { get; set; }
606 // Generic code emitter context
608 public class BuilderContext
614 /// This flag tracks the `checked' state of the compilation,
615 /// it controls whether we should generate code that does overflow
616 /// checking, or if we generate code that ignores overflows.
618 /// The default setting comes from the command line option to generate
619 /// checked or unchecked code plus any source code changes using the
620 /// checked/unchecked statements or expressions. Contrast this with
621 /// the ConstantCheckState flag.
623 CheckedScope = 1 << 0,
626 /// The constant check state is always set to `true' and cant be changed
627 /// from the command line. The source code can change this setting with
628 /// the `checked' and `unchecked' statements and expressions.
630 ConstantCheckState = 1 << 1,
632 AllCheckStateFlags = CheckedScope | ConstantCheckState,
634 OmitDebugInfo = 1 << 2,
636 ConstructorScope = 1 << 3
639 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
640 // it's public so that we can use a struct at the callsite
641 public struct FlagsHandle : IDisposable
644 readonly Options invmask, oldval;
646 public FlagsHandle (BuilderContext ec, Options flagsToSet)
647 : this (ec, flagsToSet, flagsToSet)
651 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
655 oldval = ec.flags & mask;
656 ec.flags = (ec.flags & invmask) | (val & mask);
659 public void Dispose ()
661 ec.flags = (ec.flags & invmask) | oldval;
667 public bool HasSet (Options options)
669 return (this.flags & options) == options;
672 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
673 public FlagsHandle With (Options options, bool enable)
675 return new FlagsHandle (this, options, enable ? options : 0);