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 TypeSpec CurrentType { get; }
30 // A scope type parameters either VAR or MVAR
32 TypeParameter
[] CurrentTypeParameters { get; }
35 // A member definition of the context. For partial types definition use
36 // CurrentTypeDefinition.PartialContainer otherwise the context is local
38 MemberCore CurrentMemberDefinition { get; }
40 bool IsObsolete { get; }
41 bool IsUnsafe { get; }
42 bool IsStatic { get; }
43 bool HasUnresolvedConstraints { get; }
45 string GetSignatureForError ();
47 ExtensionMethodGroupExpr
LookupExtensionMethod (TypeSpec extensionType
, string name
, int arity
, Location loc
);
48 FullNamedExpression
LookupNamespaceOrType (string name
, int arity
, Location loc
, bool ignore_cs0104
);
49 FullNamedExpression
LookupNamespaceAlias (string name
);
51 CompilerContext Compiler { get; }
55 // Block or statement resolving context
57 public class BlockContext
: ResolveContext
59 FlowBranching current_flow_branching
;
61 public TypeInferenceContext ReturnTypeInference
;
66 /// The location where return has to jump to return the
69 public Label ReturnLabel
; // TODO: It's emit dependant
72 /// If we already defined the ReturnLabel
74 public bool HasReturnLabel
;
76 public BlockContext (IMemberContext mc
, ExplicitBlock block
, TypeSpec returnType
)
79 if (returnType
== null)
80 throw new ArgumentNullException ("returnType");
82 this.return_type
= returnType
;
84 // TODO: check for null value
88 public override FlowBranching CurrentBranching
{
89 get { return current_flow_branching; }
93 // Starts a new code branching. This inherits the state of all local
94 // variables and parameters from the current branching.
96 public FlowBranching
StartFlowBranching (FlowBranching
.BranchingType type
, Location loc
)
98 current_flow_branching
= FlowBranching
.CreateBranching (CurrentBranching
, type
, null, loc
);
99 return current_flow_branching
;
103 // Starts a new code branching for block `block'.
105 public FlowBranching
StartFlowBranching (Block block
)
107 Set (Options
.DoFlowAnalysis
);
109 current_flow_branching
= FlowBranching
.CreateBranching (
110 CurrentBranching
, FlowBranching
.BranchingType
.Block
, block
, block
.StartLocation
);
111 return current_flow_branching
;
114 public FlowBranchingTryCatch
StartFlowBranching (TryCatch stmt
)
116 FlowBranchingTryCatch branching
= new FlowBranchingTryCatch (CurrentBranching
, stmt
);
117 current_flow_branching
= branching
;
121 public FlowBranchingException
StartFlowBranching (ExceptionStatement stmt
)
123 FlowBranchingException branching
= new FlowBranchingException (CurrentBranching
, stmt
);
124 current_flow_branching
= branching
;
128 public FlowBranchingLabeled
StartFlowBranching (LabeledStatement stmt
)
130 FlowBranchingLabeled branching
= new FlowBranchingLabeled (CurrentBranching
, stmt
);
131 current_flow_branching
= branching
;
135 public FlowBranchingIterator
StartFlowBranching (Iterator iterator
)
137 FlowBranchingIterator branching
= new FlowBranchingIterator (CurrentBranching
, iterator
);
138 current_flow_branching
= branching
;
142 public FlowBranchingToplevel
StartFlowBranching (ToplevelBlock stmt
, FlowBranching parent
)
144 FlowBranchingToplevel branching
= new FlowBranchingToplevel (parent
, stmt
);
145 current_flow_branching
= branching
;
150 // Ends a code branching. Merges the state of locals and parameters
151 // from all the children of the ending branching.
153 public bool EndFlowBranching ()
155 FlowBranching old
= current_flow_branching
;
156 current_flow_branching
= current_flow_branching
.Parent
;
158 FlowBranching
.UsageVector vector
= current_flow_branching
.MergeChild (old
);
159 return vector
.IsUnreachable
;
163 // Kills the current code branching. This throws away any changed state
164 // information and should only be used in case of an error.
166 // FIXME: this is evil
167 public void KillFlowBranching ()
169 current_flow_branching
= current_flow_branching
.Parent
;
173 // This method is used during the Resolution phase to flag the
174 // need to define the ReturnLabel
176 public void NeedReturnLabel ()
179 HasReturnLabel
= true;
182 public TypeSpec ReturnType
{
183 get { return return_type; }
188 // Expression resolving context
190 public class ResolveContext
: IMemberContext
196 /// This flag tracks the `checked' state of the compilation,
197 /// it controls whether we should generate code that does overflow
198 /// checking, or if we generate code that ignores overflows.
200 /// The default setting comes from the command line option to generate
201 /// checked or unchecked code plus any source code changes using the
202 /// checked/unchecked statements or expressions. Contrast this with
203 /// the ConstantCheckState flag.
205 CheckedScope
= 1 << 0,
208 /// The constant check state is always set to `true' and cant be changed
209 /// from the command line. The source code can change this setting with
210 /// the `checked' and `unchecked' statements and expressions.
212 ConstantCheckState
= 1 << 1,
214 AllCheckStateFlags
= CheckedScope
| ConstantCheckState
,
217 // unsafe { ... } scope
219 UnsafeScope
= 1 << 2,
221 FinallyScope
= 1 << 4,
222 FieldInitializerScope
= 1 << 5,
223 CompoundAssignmentScope
= 1 << 6,
224 FixedInitializerScope
= 1 << 7,
225 BaseInitializer
= 1 << 8,
228 // Inside an enum definition, we do not resolve enumeration values
229 // to their enumerations, but rather to the underlying type/value
230 // This is so EnumVal + EnumValB can be evaluated.
232 // There is no "E operator + (E x, E y)", so during an enum evaluation
233 // we relax the rules
237 ConstantScope
= 1 << 10,
239 ConstructorScope
= 1 << 11,
242 /// Whether control flow analysis is enabled
244 DoFlowAnalysis
= 1 << 20,
247 /// Whether control flow analysis is disabled on structs
248 /// (only meaningful when DoFlowAnalysis is set)
250 OmitStructFlowAnalysis
= 1 << 21,
253 /// Indicates the current context is in probing mode, no errors are reported.
255 ProbingMode
= 1 << 22,
258 // Return and ContextualReturn statements will set the ReturnType
259 // value based on the expression types of each return statement
260 // instead of the method return type which is initially null.
262 InferReturnType
= 1 << 23,
264 OmitDebuggingInfo
= 1 << 24,
266 ExpressionTreeConversion
= 1 << 25,
268 InvokeSpecialName
= 1 << 26
271 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
272 // it's public so that we can use a struct at the callsite
273 public struct FlagsHandle
: IDisposable
276 readonly Options invmask
, oldval
;
278 public FlagsHandle (ResolveContext ec
, Options flagsToSet
)
279 : this (ec
, flagsToSet
, flagsToSet
)
283 internal FlagsHandle (ResolveContext ec
, Options mask
, Options val
)
287 oldval
= ec
.flags
& mask
;
288 ec
.flags
= (ec
.flags
& invmask
) | (val
& mask
);
290 // if ((mask & Options.ProbingMode) != 0)
291 // ec.Report.DisableReporting ();
294 public void Dispose ()
296 // if ((invmask & Options.ProbingMode) == 0)
297 // ec.Report.EnableReporting ();
299 ec
.flags
= (ec
.flags
& invmask
) | oldval
;
306 // Whether we are inside an anonymous method.
308 public AnonymousExpression CurrentAnonymousMethod
;
311 // Holds a varible used during collection or object initialization.
313 public Expression CurrentInitializerVariable
;
315 public Block CurrentBlock
;
317 public IMemberContext MemberContext
;
320 /// If this is non-null, points to the current switch statement
322 public Switch Switch
;
324 public ResolveContext (IMemberContext mc
)
327 throw new ArgumentNullException ();
332 // The default setting comes from the command line option
334 if (RootContext
.Checked
)
335 flags
|= Options
.CheckedScope
;
338 // The constant check state is always set to true
340 flags
|= Options
.ConstantCheckState
;
343 public ResolveContext (IMemberContext mc
, Options options
)
349 public CompilerContext Compiler
{
350 get { return MemberContext.Compiler; }
353 public virtual FlowBranching CurrentBranching
{
358 // The current iterator
360 public Iterator CurrentIterator
{
361 get { return CurrentAnonymousMethod as Iterator; }
364 public TypeSpec CurrentType
{
365 get { return MemberContext.CurrentType; }
368 public TypeParameter
[] CurrentTypeParameters
{
369 get { return MemberContext.CurrentTypeParameters; }
372 public MemberCore CurrentMemberDefinition
{
373 get { return MemberContext.CurrentMemberDefinition; }
376 public bool ConstantCheckState
{
377 get { return (flags & Options.ConstantCheckState) != 0; }
380 public bool DoFlowAnalysis
{
381 get { return (flags & Options.DoFlowAnalysis) != 0; }
384 public bool HasUnresolvedConstraints
{
385 get { return false; }
388 public bool IsInProbingMode
{
389 get { return (flags & Options.ProbingMode) != 0; }
392 public bool IsVariableCapturingRequired
{
394 return !IsInProbingMode
&& (CurrentBranching
== null || !CurrentBranching
.CurrentUsageVector
.IsUnreachable
);
398 public bool OmitStructFlowAnalysis
{
399 get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
402 // TODO: Merge with CompilerGeneratedThis
403 public Expression
GetThis (Location loc
)
405 This my_this
= new This (loc
);
407 if (!my_this
.ResolveBase (this))
413 public bool MustCaptureVariable (LocalInfo local
)
415 if (CurrentAnonymousMethod
== null)
418 // FIXME: IsIterator is too aggressive, we should capture only if child
419 // block contains yield
420 if (CurrentAnonymousMethod
.IsIterator
)
423 return local
.Block
.Toplevel
!= CurrentBlock
.Toplevel
;
426 public bool HasSet (Options options
)
428 return (this.flags
& options
) == options
;
431 public bool HasAny (Options options
)
433 return (this.flags
& options
) != 0;
436 public Report Report
{
438 return Compiler
.Report
;
442 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
443 public FlagsHandle
Set (Options options
)
445 return new FlagsHandle (this, options
);
448 public FlagsHandle
With (Options options
, bool enable
)
450 return new FlagsHandle (this, options
, enable
? options
: 0);
453 #region IMemberContext Members
455 public string GetSignatureForError ()
457 return MemberContext
.GetSignatureForError ();
460 public bool IsObsolete
{
462 // Disables obsolete checks when probing is on
463 return IsInProbingMode
|| MemberContext
.IsObsolete
;
467 public bool IsStatic
{
468 get { return MemberContext.IsStatic; }
471 public bool IsUnsafe
{
472 get { return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe; }
475 public ExtensionMethodGroupExpr
LookupExtensionMethod (TypeSpec extensionType
, string name
, int arity
, Location loc
)
477 return MemberContext
.LookupExtensionMethod (extensionType
, name
, arity
, loc
);
480 public FullNamedExpression
LookupNamespaceOrType (string name
, int arity
, Location loc
, bool ignore_cs0104
)
482 return MemberContext
.LookupNamespaceOrType (name
, arity
, loc
, ignore_cs0104
);
485 public FullNamedExpression
LookupNamespaceAlias (string name
)
487 return MemberContext
.LookupNamespaceAlias (name
);
494 // This class is used during the Statement.Clone operation
495 // to remap objects that have been cloned.
497 // Since blocks are cloned by Block.Clone, we need a way for
498 // expressions that must reference the block to be cloned
499 // pointing to the new cloned block.
501 public class CloneContext
503 Dictionary
<Block
, Block
> block_map
= new Dictionary
<Block
, Block
> ();
504 Dictionary
<LocalInfo
, LocalInfo
> variable_map
;
506 public void AddBlockMap (Block
from, Block to
)
508 if (block_map
.ContainsKey (from))
510 block_map
[from] = to
;
513 public Block
LookupBlock (Block
from)
516 if (!block_map
.TryGetValue (from, out result
)) {
517 result
= (Block
) from.Clone (this);
518 block_map
[from] = result
;
525 /// Remaps block to cloned copy if one exists.
527 public Block
RemapBlockCopy (Block
from)
530 if (!block_map
.TryGetValue (from, out mapped_to
))
536 public void AddVariableMap (LocalInfo
from, LocalInfo to
)
538 if (variable_map
== null)
539 variable_map
= new Dictionary
<LocalInfo
, LocalInfo
> ();
540 else if (variable_map
.ContainsKey (from))
543 variable_map
[from] = to
;
546 public LocalInfo
LookupVariable (LocalInfo
from)
549 return variable_map
[from];
550 } catch (KeyNotFoundException
) {
551 throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");
557 // Main compiler context
559 public class CompilerContext
561 readonly Report report
;
563 public CompilerContext (Report report
)
565 this.report
= report
;
568 public bool IsRuntimeBinder { get; set; }
570 public Report Report
{
571 get { return report; }
574 //public PredefinedAttributes PredefinedAttributes {
575 // get { throw new NotImplementedException (); }
580 // Generic code emitter context
582 public class BuilderContext
588 /// This flag tracks the `checked' state of the compilation,
589 /// it controls whether we should generate code that does overflow
590 /// checking, or if we generate code that ignores overflows.
592 /// The default setting comes from the command line option to generate
593 /// checked or unchecked code plus any source code changes using the
594 /// checked/unchecked statements or expressions. Contrast this with
595 /// the ConstantCheckState flag.
597 CheckedScope
= 1 << 0,
600 /// The constant check state is always set to `true' and cant be changed
601 /// from the command line. The source code can change this setting with
602 /// the `checked' and `unchecked' statements and expressions.
604 ConstantCheckState
= 1 << 1,
606 AllCheckStateFlags
= CheckedScope
| ConstantCheckState
,
608 OmitDebugInfo
= 1 << 2,
610 ConstructorScope
= 1 << 3
613 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
614 // it's public so that we can use a struct at the callsite
615 public struct FlagsHandle
: IDisposable
618 readonly Options invmask
, oldval
;
620 public FlagsHandle (BuilderContext ec
, Options flagsToSet
)
621 : this (ec
, flagsToSet
, flagsToSet
)
625 internal FlagsHandle (BuilderContext ec
, Options mask
, Options val
)
629 oldval
= ec
.flags
& mask
;
630 ec
.flags
= (ec
.flags
& invmask
) | (val
& mask
);
633 public void Dispose ()
635 ec
.flags
= (ec
.flags
& invmask
) | oldval
;
641 public bool HasSet (Options options
)
643 return (this.flags
& options
) == options
;
646 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
647 public FlagsHandle
With (Options options
, bool enable
)
649 return new FlagsHandle (this, options
, enable
? options
: 0);