* Exec.cs: Write the commands, which can be multiline,
[mcs.git] / mcs / context.cs
blob71d19c7a3e83287bc0775ce27030e5a0d5fe263e
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
268 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
269 // it's public so that we can use a struct at the callsite
270 public struct FlagsHandle : IDisposable
272 ResolveContext ec;
273 readonly Options invmask, oldval;
275 public FlagsHandle (ResolveContext ec, Options flagsToSet)
276 : this (ec, flagsToSet, flagsToSet)
280 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
282 this.ec = ec;
283 invmask = ~mask;
284 oldval = ec.flags & mask;
285 ec.flags = (ec.flags & invmask) | (val & mask);
287 // if ((mask & Options.ProbingMode) != 0)
288 // ec.Report.DisableReporting ();
291 public void Dispose ()
293 // if ((invmask & Options.ProbingMode) == 0)
294 // ec.Report.EnableReporting ();
296 ec.flags = (ec.flags & invmask) | oldval;
300 Options flags;
303 // Whether we are inside an anonymous method.
305 public AnonymousExpression CurrentAnonymousMethod;
308 // Holds a varible used during collection or object initialization.
310 public Expression CurrentInitializerVariable;
312 public Block CurrentBlock;
314 public IMemberContext MemberContext;
316 /// <summary>
317 /// If this is non-null, points to the current switch statement
318 /// </summary>
319 public Switch Switch;
321 public ResolveContext (IMemberContext mc)
323 MemberContext = mc;
326 // The default setting comes from the command line option
328 if (RootContext.Checked)
329 flags |= Options.CheckedScope;
332 // The constant check state is always set to true
334 flags |= Options.ConstantCheckState;
337 public ResolveContext (IMemberContext mc, Options options)
338 : this (mc)
340 flags |= options;
343 public CompilerContext Compiler {
344 get { return MemberContext.Compiler; }
347 public virtual FlowBranching CurrentBranching {
348 get { return null; }
352 // The current iterator
354 public Iterator CurrentIterator {
355 get { return CurrentAnonymousMethod as Iterator; }
358 public Type CurrentType {
359 get { return MemberContext.CurrentType; }
362 public TypeParameter[] CurrentTypeParameters {
363 get { return MemberContext.CurrentTypeParameters; }
366 public TypeContainer CurrentTypeDefinition {
367 get { return MemberContext.CurrentTypeDefinition; }
370 public bool ConstantCheckState {
371 get { return (flags & Options.ConstantCheckState) != 0; }
374 public bool DoFlowAnalysis {
375 get { return (flags & Options.DoFlowAnalysis) != 0; }
378 public bool IsInProbingMode {
379 get { return (flags & Options.ProbingMode) != 0; }
382 public bool IsVariableCapturingRequired {
383 get {
384 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
388 public bool OmitStructFlowAnalysis {
389 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
392 // TODO: Merge with CompilerGeneratedThis
393 public Expression GetThis (Location loc)
395 This my_this;
396 if (CurrentBlock != null)
397 my_this = new This (CurrentBlock, loc);
398 else
399 my_this = new This (loc);
401 if (!my_this.ResolveBase (this))
402 my_this = null;
404 return my_this;
407 public bool MustCaptureVariable (LocalInfo local)
409 if (CurrentAnonymousMethod == null)
410 return false;
412 // FIXME: IsIterator is too aggressive, we should capture only if child
413 // block contains yield
414 if (CurrentAnonymousMethod.IsIterator)
415 return true;
417 return local.Block.Toplevel != CurrentBlock.Toplevel;
420 public bool HasSet (Options options)
422 return (this.flags & options) == options;
425 public bool HasAny (Options options)
427 return (this.flags & options) != 0;
430 public Report Report {
431 get {
432 return Compiler.Report;
436 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
437 public FlagsHandle Set (Options options)
439 return new FlagsHandle (this, options);
442 public FlagsHandle With (Options options, bool enable)
444 return new FlagsHandle (this, options, enable ? options : 0);
447 public FlagsHandle WithFlowAnalysis (bool do_flow_analysis, bool omit_struct_analysis)
449 Options newflags =
450 (do_flow_analysis ? Options.DoFlowAnalysis : 0) |
451 (omit_struct_analysis ? Options.OmitStructFlowAnalysis : 0);
452 return new FlagsHandle (this, Options.DoFlowAnalysis | Options.OmitStructFlowAnalysis, newflags);
455 #region IMemberContext Members
457 public string GetSignatureForError ()
459 return MemberContext.GetSignatureForError ();
462 public bool IsObsolete {
463 get {
464 // Disables obsolete checks when probing is on
465 return IsInProbingMode || MemberContext.IsObsolete;
469 public bool IsStatic {
470 get { return MemberContext.IsStatic; }
473 public bool IsUnsafe {
474 get { return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe; }
477 public ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name, Location loc)
479 return MemberContext.LookupExtensionMethod (extensionType, name, loc);
482 public FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104)
484 return MemberContext.LookupNamespaceOrType (name, loc, ignore_cs0104);
487 public FullNamedExpression LookupNamespaceAlias (string name)
489 return MemberContext.LookupNamespaceAlias (name);
492 #endregion
496 // This class is used during the Statement.Clone operation
497 // to remap objects that have been cloned.
499 // Since blocks are cloned by Block.Clone, we need a way for
500 // expressions that must reference the block to be cloned
501 // pointing to the new cloned block.
503 public class CloneContext
505 Hashtable block_map = new Hashtable ();
506 Hashtable variable_map;
508 public void AddBlockMap (Block from, Block to)
510 if (block_map.Contains (from))
511 return;
512 block_map[from] = to;
515 public Block LookupBlock (Block from)
517 Block result = (Block) block_map[from];
519 if (result == null) {
520 result = (Block) from.Clone (this);
521 block_map[from] = result;
524 return result;
528 /// Remaps block to cloned copy if one exists.
530 public Block RemapBlockCopy (Block from)
532 Block mapped_to = (Block) block_map[from];
533 if (mapped_to == null)
534 return from;
536 return mapped_to;
539 public void AddVariableMap (LocalInfo from, LocalInfo to)
541 if (variable_map == null)
542 variable_map = new Hashtable ();
544 if (variable_map.Contains (from))
545 return;
546 variable_map[from] = to;
549 public LocalInfo LookupVariable (LocalInfo from)
551 LocalInfo result = (LocalInfo) variable_map[from];
553 if (result == null)
554 throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");
556 return result;
561 // Main compiler context
563 public class CompilerContext
565 readonly Report report;
567 public CompilerContext (Report report)
569 this.report = report;
572 public Report Report {
573 get { return report; }
576 //public PredefinedAttributes PredefinedAttributes {
577 // get { throw new NotImplementedException (); }
582 // Generic code emitter context
584 public class BuilderContext
586 [Flags]
587 public enum Options
589 /// <summary>
590 /// This flag tracks the `checked' state of the compilation,
591 /// it controls whether we should generate code that does overflow
592 /// checking, or if we generate code that ignores overflows.
594 /// The default setting comes from the command line option to generate
595 /// checked or unchecked code plus any source code changes using the
596 /// checked/unchecked statements or expressions. Contrast this with
597 /// the ConstantCheckState flag.
598 /// </summary>
599 CheckedScope = 1 << 0,
601 /// <summary>
602 /// The constant check state is always set to `true' and cant be changed
603 /// from the command line. The source code can change this setting with
604 /// the `checked' and `unchecked' statements and expressions.
605 /// </summary>
606 ConstantCheckState = 1 << 1,
608 AllCheckStateFlags = CheckedScope | ConstantCheckState,
610 OmitDebugInfo = 1 << 2,
612 ConstructorScope = 1 << 3
615 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
616 // it's public so that we can use a struct at the callsite
617 public struct FlagsHandle : IDisposable
619 BuilderContext ec;
620 readonly Options invmask, oldval;
622 public FlagsHandle (BuilderContext ec, Options flagsToSet)
623 : this (ec, flagsToSet, flagsToSet)
627 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
629 this.ec = ec;
630 invmask = ~mask;
631 oldval = ec.flags & mask;
632 ec.flags = (ec.flags & invmask) | (val & mask);
635 public void Dispose ()
637 ec.flags = (ec.flags & invmask) | oldval;
641 Options flags;
643 public bool HasSet (Options options)
645 return (this.flags & options) == options;
648 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
649 public FlagsHandle With (Options options, bool enable)
651 return new FlagsHandle (this, options, enable ? options : 0);