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 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,
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
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
)
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
;
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
;
321 /// If this is non-null, points to the current switch statement
323 public Switch Switch
;
325 public ResolveContext (IMemberContext mc
)
328 throw new ArgumentNullException ();
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
)
350 public CompilerContext Compiler
{
351 get { return MemberContext.Compiler; }
354 public virtual FlowBranching CurrentBranching
{
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
{
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
)
403 if (CurrentBlock
!= null)
404 my_this
= new This (CurrentBlock
, loc
);
406 my_this
= new This (loc
);
408 if (!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 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
);
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 if (block_map
.ContainsKey (from))
511 block_map
[from] = to
;
514 public Block
LookupBlock (Block
from)
517 if (!block_map
.TryGetValue (from, out result
)) {
518 result
= (Block
) from.Clone (this);
519 block_map
[from] = result
;
526 /// Remaps block to cloned copy if one exists.
528 public Block
RemapBlockCopy (Block
from)
531 if (!block_map
.TryGetValue (from, out mapped_to
))
537 public void AddVariableMap (LocalInfo
from, LocalInfo to
)
539 if (variable_map
== null)
540 variable_map
= new Dictionary
<LocalInfo
, LocalInfo
> ();
541 else if (variable_map
.ContainsKey (from))
544 variable_map
[from] = to
;
547 public LocalInfo
LookupVariable (LocalInfo
from)
550 return variable_map
[from];
551 } catch (KeyNotFoundException
) {
552 throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");
558 // Main compiler context
560 public class CompilerContext
562 readonly Report report
;
564 public CompilerContext (Report report
)
566 this.report
= report
;
569 public bool IsRuntimeBinder { get; set; }
571 public Report Report
{
572 get { return report; }
575 //public PredefinedAttributes PredefinedAttributes {
576 // get { throw new NotImplementedException (); }
581 // Generic code emitter context
583 public class BuilderContext
589 /// This flag tracks the `checked' state of the compilation,
590 /// it controls whether we should generate code that does overflow
591 /// checking, or if we generate code that ignores overflows.
593 /// The default setting comes from the command line option to generate
594 /// checked or unchecked code plus any source code changes using the
595 /// checked/unchecked statements or expressions. Contrast this with
596 /// the ConstantCheckState flag.
598 CheckedScope
= 1 << 0,
601 /// The constant check state is always set to `true' and cant be changed
602 /// from the command line. The source code can change this setting with
603 /// the `checked' and `unchecked' statements and expressions.
605 ConstantCheckState
= 1 << 1,
607 AllCheckStateFlags
= CheckedScope
| ConstantCheckState
,
609 OmitDebugInfo
= 1 << 2,
611 ConstructorScope
= 1 << 3
614 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
615 // it's public so that we can use a struct at the callsite
616 public struct FlagsHandle
: IDisposable
619 readonly Options invmask
, oldval
;
621 public FlagsHandle (BuilderContext ec
, Options flagsToSet
)
622 : this (ec
, flagsToSet
, flagsToSet
)
626 internal FlagsHandle (BuilderContext ec
, Options mask
, Options val
)
630 oldval
= ec
.flags
& mask
;
631 ec
.flags
= (ec
.flags
& invmask
) | (val
& mask
);
634 public void Dispose ()
636 ec
.flags
= (ec
.flags
& invmask
) | oldval
;
642 public bool HasSet (Options options
)
644 return (this.flags
& options
) == options
;
647 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
648 public FlagsHandle
With (Options options
, bool enable
)
650 return new FlagsHandle (this, options
, enable
? options
: 0);