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
;
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 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
;
67 /// The location where return has to jump to return the
70 public Label ReturnLabel
; // TODO: It's emit dependant
73 /// If we already defined the ReturnLabel
75 public bool HasReturnLabel
;
77 public BlockContext (IMemberContext mc
, ExplicitBlock block
, Type returnType
)
80 if (returnType
== null)
81 throw new ArgumentNullException ("returnType");
83 this.return_type
= returnType
;
85 // TODO: check for null value
89 public override FlowBranching CurrentBranching
{
90 get { return current_flow_branching; }
94 // Starts a new code branching. This inherits the state of all local
95 // variables and parameters from the current branching.
97 public FlowBranching
StartFlowBranching (FlowBranching
.BranchingType type
, Location loc
)
99 current_flow_branching
= FlowBranching
.CreateBranching (CurrentBranching
, type
, null, loc
);
100 return current_flow_branching
;
104 // Starts a new code branching for block `block'.
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
;
122 public FlowBranchingException
StartFlowBranching (ExceptionStatement stmt
)
124 FlowBranchingException branching
= new FlowBranchingException (CurrentBranching
, stmt
);
125 current_flow_branching
= branching
;
129 public FlowBranchingLabeled
StartFlowBranching (LabeledStatement stmt
)
131 FlowBranchingLabeled branching
= new FlowBranchingLabeled (CurrentBranching
, stmt
);
132 current_flow_branching
= branching
;
136 public FlowBranchingIterator
StartFlowBranching (Iterator iterator
)
138 FlowBranchingIterator branching
= new FlowBranchingIterator (CurrentBranching
, iterator
);
139 current_flow_branching
= branching
;
143 public FlowBranchingToplevel
StartFlowBranching (ToplevelBlock stmt
, FlowBranching parent
)
145 FlowBranchingToplevel branching
= new FlowBranchingToplevel (parent
, stmt
);
146 current_flow_branching
= branching
;
151 // Ends a code branching. Merges the state of locals and parameters
152 // from all the children of the ending branching.
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
;
164 // Kills the current code branching. This throws away any changed state
165 // information and should only be used in case of an error.
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 ()
180 HasReturnLabel
= true;
183 public Type ReturnType
{
184 get { return return_type; }
189 // Expression resolving context
191 public class ResolveContext
: IMemberContext
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.
206 CheckedScope
= 1 << 0,
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.
213 ConstantCheckState
= 1 << 1,
215 AllCheckStateFlags
= CheckedScope
| ConstantCheckState
,
218 // unsafe { ... } scope
220 UnsafeScope
= 1 << 2,
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
238 ConstantScope
= 1 << 10,
240 ConstructorScope
= 1 << 11,
243 /// Whether control flow analysis is enabled
245 DoFlowAnalysis
= 1 << 20,
248 /// Whether control flow analysis is disabled on structs
249 /// (only meaningful when DoFlowAnalysis is set)
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
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
)
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
;
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
;
317 /// If this is non-null, points to the current switch statement
319 public Switch Switch
;
321 public ResolveContext (IMemberContext 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
)
343 public CompilerContext Compiler
{
344 get { return MemberContext.Compiler; }
347 public virtual FlowBranching CurrentBranching
{
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
{
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
)
396 if (CurrentBlock
!= null)
397 my_this
= new This (CurrentBlock
, loc
);
399 my_this
= new This (loc
);
401 if (!my_this
.ResolveBase (this))
407 public bool MustCaptureVariable (LocalInfo local
)
409 if (CurrentAnonymousMethod
== null)
412 // FIXME: IsIterator is too aggressive, we should capture only if child
413 // block contains yield
414 if (CurrentAnonymousMethod
.IsIterator
)
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
{
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
)
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
{
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
);
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))
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
;
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)
539 public void AddVariableMap (LocalInfo
from, LocalInfo to
)
541 if (variable_map
== null)
542 variable_map
= new Hashtable ();
544 if (variable_map
.Contains (from))
546 variable_map
[from] = to
;
549 public LocalInfo
LookupVariable (LocalInfo
from)
551 LocalInfo result
= (LocalInfo
) variable_map
[from];
554 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 Report Report
{
573 get { return report; }
576 //public PredefinedAttributes PredefinedAttributes {
577 // get { throw new NotImplementedException (); }
582 // Generic code emitter context
584 public class BuilderContext
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.
599 CheckedScope
= 1 << 0,
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.
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
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
)
631 oldval
= ec
.flags
& mask
;
632 ec
.flags
= (ec
.flags
& invmask
) | (val
& mask
);
635 public void Dispose ()
637 ec
.flags
= (ec
.flags
& invmask
) | oldval
;
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);