2009-11-24 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / context.cs
blob4e02e315b4623166238974104027e8bc9b05b631
1 //
2 // context.cs: Various compiler contexts.
3 //
4 // Author:
5 // Marek Safar (marek.safar@gmail.com)
6 // Miguel de Icaza (miguel@ximian.com)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2004-2009 Novell, Inc.
12 using System;
13 using System.Collections;
14 using System.Reflection.Emit;
16 namespace Mono.CSharp
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);
52 CompilerContext Compiler { get; }
56 // Block or statement resolving context
58 public class BlockContext : ResolveContext
60 FlowBranching current_flow_branching;
62 public TypeInferenceContext ReturnTypeInference;
64 Type return_type;
66 /// <summary>
67 /// The location where return has to jump to return the
68 /// value
69 /// </summary>
70 public Label ReturnLabel; // TODO: It's emit dependant
72 /// <summary>
73 /// If we already defined the ReturnLabel
74 /// </summary>
75 public bool HasReturnLabel;
77 public BlockContext (IMemberContext mc, ExplicitBlock block, Type returnType)
78 : base (mc)
80 if (returnType == null)
81 throw new ArgumentNullException ("returnType");
83 this.return_type = returnType;
85 // TODO: check for null value
86 CurrentBlock = block;
89 public override FlowBranching CurrentBranching {
90 get { return current_flow_branching; }
93 // <summary>
94 // Starts a new code branching. This inherits the state of all local
95 // variables and parameters from the current branching.
96 // </summary>
97 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
99 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
100 return current_flow_branching;
103 // <summary>
104 // Starts a new code branching for block `block'.
105 // </summary>
106 public FlowBranching StartFlowBranching (Block block)
108 Set (Options.DoFlowAnalysis);
110 current_flow_branching = FlowBranching.CreateBranching (
111 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
112 return current_flow_branching;
115 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
117 FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
118 current_flow_branching = branching;
119 return branching;
122 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
124 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
125 current_flow_branching = branching;
126 return branching;
129 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
131 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
132 current_flow_branching = branching;
133 return branching;
136 public FlowBranchingIterator StartFlowBranching (Iterator iterator)
138 FlowBranchingIterator branching = new FlowBranchingIterator (CurrentBranching, iterator);
139 current_flow_branching = branching;
140 return branching;
143 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt, FlowBranching parent)
145 FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
146 current_flow_branching = branching;
147 return branching;
150 // <summary>
151 // Ends a code branching. Merges the state of locals and parameters
152 // from all the children of the ending branching.
153 // </summary>
154 public bool EndFlowBranching ()
156 FlowBranching old = current_flow_branching;
157 current_flow_branching = current_flow_branching.Parent;
159 FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
160 return vector.IsUnreachable;
163 // <summary>
164 // Kills the current code branching. This throws away any changed state
165 // information and should only be used in case of an error.
166 // </summary>
167 // FIXME: this is evil
168 public void KillFlowBranching ()
170 current_flow_branching = current_flow_branching.Parent;
174 // This method is used during the Resolution phase to flag the
175 // need to define the ReturnLabel
177 public void NeedReturnLabel ()
179 if (!HasReturnLabel)
180 HasReturnLabel = true;
183 public Type ReturnType {
184 get { return return_type; }
189 // Expression resolving context
191 public class ResolveContext : IMemberContext
193 [Flags]
194 public enum Options
196 /// <summary>
197 /// This flag tracks the `checked' state of the compilation,
198 /// it controls whether we should generate code that does overflow
199 /// checking, or if we generate code that ignores overflows.
201 /// The default setting comes from the command line option to generate
202 /// checked or unchecked code plus any source code changes using the
203 /// checked/unchecked statements or expressions. Contrast this with
204 /// the ConstantCheckState flag.
205 /// </summary>
206 CheckedScope = 1 << 0,
208 /// <summary>
209 /// The constant check state is always set to `true' and cant be changed
210 /// from the command line. The source code can change this setting with
211 /// the `checked' and `unchecked' statements and expressions.
212 /// </summary>
213 ConstantCheckState = 1 << 1,
215 AllCheckStateFlags = CheckedScope | ConstantCheckState,
218 // unsafe { ... } scope
220 UnsafeScope = 1 << 2,
221 CatchScope = 1 << 3,
222 FinallyScope = 1 << 4,
223 FieldInitializerScope = 1 << 5,
224 CompoundAssignmentScope = 1 << 6,
225 FixedInitializerScope = 1 << 7,
226 BaseInitializer = 1 << 8,
229 // Inside an enum definition, we do not resolve enumeration values
230 // to their enumerations, but rather to the underlying type/value
231 // This is so EnumVal + EnumValB can be evaluated.
233 // There is no "E operator + (E x, E y)", so during an enum evaluation
234 // we relax the rules
236 EnumScope = 1 << 9,
238 ConstantScope = 1 << 10,
240 ConstructorScope = 1 << 11,
242 /// <summary>
243 /// Whether control flow analysis is enabled
244 /// </summary>
245 DoFlowAnalysis = 1 << 20,
247 /// <summary>
248 /// Whether control flow analysis is disabled on structs
249 /// (only meaningful when DoFlowAnalysis is set)
250 /// </summary>
251 OmitStructFlowAnalysis = 1 << 21,
254 /// Indicates the current context is in probing mode, no errors are reported.
256 ProbingMode = 1 << 22,
259 // Return and ContextualReturn statements will set the ReturnType
260 // value based on the expression types of each return statement
261 // instead of the method return type which is initially null.
263 InferReturnType = 1 << 23,
265 OmitDebuggingInfo = 1 << 24,
267 ExpressionTreeConversion = 1 << 25,
269 InvokeSpecialName = 1 << 26
272 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
273 // it's public so that we can use a struct at the callsite
274 public struct FlagsHandle : IDisposable
276 ResolveContext ec;
277 readonly Options invmask, oldval;
279 public FlagsHandle (ResolveContext ec, Options flagsToSet)
280 : this (ec, flagsToSet, flagsToSet)
284 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
286 this.ec = ec;
287 invmask = ~mask;
288 oldval = ec.flags & mask;
289 ec.flags = (ec.flags & invmask) | (val & mask);
291 // if ((mask & Options.ProbingMode) != 0)
292 // ec.Report.DisableReporting ();
295 public void Dispose ()
297 // if ((invmask & Options.ProbingMode) == 0)
298 // ec.Report.EnableReporting ();
300 ec.flags = (ec.flags & invmask) | oldval;
304 Options flags;
307 // Whether we are inside an anonymous method.
309 public AnonymousExpression CurrentAnonymousMethod;
312 // Holds a varible used during collection or object initialization.
314 public Expression CurrentInitializerVariable;
316 public Block CurrentBlock;
318 public IMemberContext MemberContext;
320 /// <summary>
321 /// If this is non-null, points to the current switch statement
322 /// </summary>
323 public Switch Switch;
325 public ResolveContext (IMemberContext mc)
327 if (mc == null)
328 throw new ArgumentNullException ();
330 MemberContext = mc;
333 // The default setting comes from the command line option
335 if (RootContext.Checked)
336 flags |= Options.CheckedScope;
339 // The constant check state is always set to true
341 flags |= Options.ConstantCheckState;
344 public ResolveContext (IMemberContext mc, Options options)
345 : this (mc)
347 flags |= options;
350 public CompilerContext Compiler {
351 get { return MemberContext.Compiler; }
354 public virtual FlowBranching CurrentBranching {
355 get { return null; }
359 // The current iterator
361 public Iterator CurrentIterator {
362 get { return CurrentAnonymousMethod as Iterator; }
365 public Type CurrentType {
366 get { return MemberContext.CurrentType; }
369 public TypeParameter[] CurrentTypeParameters {
370 get { return MemberContext.CurrentTypeParameters; }
373 public TypeContainer CurrentTypeDefinition {
374 get { return MemberContext.CurrentTypeDefinition; }
377 public bool ConstantCheckState {
378 get { return (flags & Options.ConstantCheckState) != 0; }
381 public bool DoFlowAnalysis {
382 get { return (flags & Options.DoFlowAnalysis) != 0; }
385 public bool IsInProbingMode {
386 get { return (flags & Options.ProbingMode) != 0; }
389 public bool IsVariableCapturingRequired {
390 get {
391 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
395 public bool OmitStructFlowAnalysis {
396 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
399 // TODO: Merge with CompilerGeneratedThis
400 public Expression GetThis (Location loc)
402 This my_this;
403 if (CurrentBlock != null)
404 my_this = new This (CurrentBlock, loc);
405 else
406 my_this = new This (loc);
408 if (!my_this.ResolveBase (this))
409 my_this = null;
411 return my_this;
414 public bool MustCaptureVariable (LocalInfo local)
416 if (CurrentAnonymousMethod == null)
417 return false;
419 // FIXME: IsIterator is too aggressive, we should capture only if child
420 // block contains yield
421 if (CurrentAnonymousMethod.IsIterator)
422 return true;
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 {
438 get {
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 {
462 get {
463 // Disables obsolete checks when probing is on
464 return IsInProbingMode || 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 ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name, Location loc)
478 return MemberContext.LookupExtensionMethod (extensionType, name, loc);
481 public FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104)
483 return MemberContext.LookupNamespaceOrType (name, loc, ignore_cs0104);
486 public FullNamedExpression LookupNamespaceAlias (string name)
488 return MemberContext.LookupNamespaceAlias (name);
491 #endregion
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 Hashtable block_map = new Hashtable ();
505 Hashtable variable_map;
507 public void AddBlockMap (Block from, Block to)
509 if (block_map.Contains (from))
510 return;
511 block_map[from] = to;
514 public Block LookupBlock (Block from)
516 Block result = (Block) block_map[from];
518 if (result == null) {
519 result = (Block) from.Clone (this);
520 block_map[from] = result;
523 return result;
527 /// Remaps block to cloned copy if one exists.
529 public Block RemapBlockCopy (Block from)
531 Block mapped_to = (Block) block_map[from];
532 if (mapped_to == null)
533 return from;
535 return mapped_to;
538 public void AddVariableMap (LocalInfo from, LocalInfo to)
540 if (variable_map == null)
541 variable_map = new Hashtable ();
543 if (variable_map.Contains (from))
544 return;
545 variable_map[from] = to;
548 public LocalInfo LookupVariable (LocalInfo from)
550 LocalInfo result = (LocalInfo) variable_map[from];
552 if (result == null)
553 throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");
555 return result;
560 // Main compiler context
562 public class CompilerContext
564 readonly Report report;
566 public CompilerContext (Report report)
568 this.report = report;
571 public bool IsRuntimeBinder { get; set; }
573 public Report Report {
574 get { return report; }
577 //public PredefinedAttributes PredefinedAttributes {
578 // get { throw new NotImplementedException (); }
583 // Generic code emitter context
585 public class BuilderContext
587 [Flags]
588 public enum Options
590 /// <summary>
591 /// This flag tracks the `checked' state of the compilation,
592 /// it controls whether we should generate code that does overflow
593 /// checking, or if we generate code that ignores overflows.
595 /// The default setting comes from the command line option to generate
596 /// checked or unchecked code plus any source code changes using the
597 /// checked/unchecked statements or expressions. Contrast this with
598 /// the ConstantCheckState flag.
599 /// </summary>
600 CheckedScope = 1 << 0,
602 /// <summary>
603 /// The constant check state is always set to `true' and cant be changed
604 /// from the command line. The source code can change this setting with
605 /// the `checked' and `unchecked' statements and expressions.
606 /// </summary>
607 ConstantCheckState = 1 << 1,
609 AllCheckStateFlags = CheckedScope | ConstantCheckState,
611 OmitDebugInfo = 1 << 2,
613 ConstructorScope = 1 << 3
616 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
617 // it's public so that we can use a struct at the callsite
618 public struct FlagsHandle : IDisposable
620 BuilderContext ec;
621 readonly Options invmask, oldval;
623 public FlagsHandle (BuilderContext ec, Options flagsToSet)
624 : this (ec, flagsToSet, flagsToSet)
628 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
630 this.ec = ec;
631 invmask = ~mask;
632 oldval = ec.flags & mask;
633 ec.flags = (ec.flags & invmask) | (val & mask);
636 public void Dispose ()
638 ec.flags = (ec.flags & invmask) | oldval;
642 Options flags;
644 public bool HasSet (Options options)
646 return (this.flags & options) == options;
649 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
650 public FlagsHandle With (Options options, bool enable)
652 return new FlagsHandle (this, options, enable ? options : 0);