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.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using System.Security.Cryptography;
20 public enum LookupMode
24 IgnoreAccessibility = 2
28 // Implemented by elements which can act as independent contexts
29 // during resolve phase. Used mostly for lookups.
31 public interface IMemberContext : IModuleContext
34 // A scope type context, it can be inflated for generic types
36 TypeSpec CurrentType { get; }
39 // A scope type parameters either VAR or MVAR
41 TypeParameters CurrentTypeParameters { get; }
44 // A member definition of the context. For partial types definition use
45 // CurrentTypeDefinition.PartialContainer otherwise the context is local
47 // TODO: Obsolete it in this context, dynamic context cannot guarantee sensible value
49 MemberCore CurrentMemberDefinition { get; }
51 bool IsObsolete { get; }
52 bool IsUnsafe { get; }
53 bool IsStatic { get; }
55 string GetSignatureForError ();
57 ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity);
58 FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc);
59 FullNamedExpression LookupNamespaceAlias (string name);
62 public interface IModuleContext
64 ModuleContainer Module { get; }
68 // Block or statement resolving context
70 public class BlockContext : ResolveContext
72 readonly TypeSpec return_type;
75 // Tracks the last offset used by VariableInfo
77 public int AssignmentInfoOffset;
79 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
82 if (returnType == null)
83 throw new ArgumentNullException ("returnType");
85 this.return_type = returnType;
87 // TODO: check for null value
91 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
92 : this (rc.MemberContext, block, returnType)
95 flags |= ResolveContext.Options.UnsafeScope;
97 if (rc.HasSet (ResolveContext.Options.CheckedScope))
98 flags |= ResolveContext.Options.CheckedScope;
100 if (rc.IsInProbingMode)
101 flags |= ResolveContext.Options.ProbingMode;
103 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
104 flags |= ResolveContext.Options.FieldInitializerScope;
106 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
107 flags |= ResolveContext.Options.ExpressionTreeConversion;
109 if (rc.HasSet (ResolveContext.Options.BaseInitializer))
110 flags |= ResolveContext.Options.BaseInitializer;
113 public ExceptionStatement CurrentTryBlock { get; set; }
115 public LoopStatement EnclosingLoop { get; set; }
117 public LoopStatement EnclosingLoopOrSwitch { get; set; }
119 public Switch Switch { get; set; }
121 public TypeSpec ReturnType {
122 get { return return_type; }
127 // Expression resolving context
129 public class ResolveContext : IMemberContext
135 /// This flag tracks the `checked' state of the compilation,
136 /// it controls whether we should generate code that does overflow
137 /// checking, or if we generate code that ignores overflows.
139 /// The default setting comes from the command line option to generate
140 /// checked or unchecked code plus any source code changes using the
141 /// checked/unchecked statements or expressions. Contrast this with
142 /// the ConstantCheckState flag.
144 CheckedScope = 1 << 0,
147 /// The constant check state is always set to `true' and cant be changed
148 /// from the command line. The source code can change this setting with
149 /// the `checked' and `unchecked' statements and expressions.
151 ConstantCheckState = 1 << 1,
153 AllCheckStateFlags = CheckedScope | ConstantCheckState,
156 // unsafe { ... } scope
158 UnsafeScope = 1 << 2,
160 FinallyScope = 1 << 4,
161 FieldInitializerScope = 1 << 5,
162 CompoundAssignmentScope = 1 << 6,
163 FixedInitializerScope = 1 << 7,
164 BaseInitializer = 1 << 8,
167 // Inside an enum definition, we do not resolve enumeration values
168 // to their enumerations, but rather to the underlying type/value
169 // This is so EnumVal + EnumValB can be evaluated.
171 // There is no "E operator + (E x, E y)", so during an enum evaluation
172 // we relax the rules
176 ConstantScope = 1 << 10,
178 ConstructorScope = 1 << 11,
180 UsingInitializerScope = 1 << 12,
186 TryWithCatchScope = 1 << 15,
189 /// Indicates the current context is in probing mode, no errors are reported.
191 ProbingMode = 1 << 22,
194 // Return and ContextualReturn statements will set the ReturnType
195 // value based on the expression types of each return statement
196 // instead of the method return type which is initially null.
198 InferReturnType = 1 << 23,
200 OmitDebuggingInfo = 1 << 24,
202 ExpressionTreeConversion = 1 << 25,
204 InvokeSpecialName = 1 << 26
207 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
208 // it's public so that we can use a struct at the callsite
209 public struct FlagsHandle : IDisposable
211 readonly ResolveContext ec;
212 readonly Options invmask, oldval;
214 public FlagsHandle (ResolveContext ec, Options flagsToSet)
215 : this (ec, flagsToSet, flagsToSet)
219 internal FlagsHandle (ResolveContext ec, Options mask, Options val)
223 oldval = ec.flags & mask;
224 ec.flags = (ec.flags & invmask) | (val & mask);
226 // if ((mask & Options.ProbingMode) != 0)
227 // ec.Report.DisableReporting ();
230 public void Dispose ()
232 // if ((invmask & Options.ProbingMode) == 0)
233 // ec.Report.EnableReporting ();
235 ec.flags = (ec.flags & invmask) | oldval;
239 protected Options flags;
242 // Whether we are inside an anonymous method.
244 public AnonymousExpression CurrentAnonymousMethod;
247 // Holds a varible used during collection or object initialization.
249 public Expression CurrentInitializerVariable;
251 public Block CurrentBlock;
253 public readonly IMemberContext MemberContext;
255 public ResolveContext (IMemberContext mc)
258 throw new ArgumentNullException ();
263 // The default setting comes from the command line option
265 if (mc.Module.Compiler.Settings.Checked)
266 flags |= Options.CheckedScope;
269 // The constant check state is always set to true
271 flags |= Options.ConstantCheckState;
274 public ResolveContext (IMemberContext mc, Options options)
282 public BuiltinTypes BuiltinTypes {
284 return MemberContext.Module.Compiler.BuiltinTypes;
288 public virtual ExplicitBlock ConstructorBlock {
290 return CurrentBlock.Explicit;
295 // The current iterator
297 public Iterator CurrentIterator {
298 get { return CurrentAnonymousMethod as Iterator; }
301 public TypeSpec CurrentType {
302 get { return MemberContext.CurrentType; }
305 public TypeParameters CurrentTypeParameters {
306 get { return MemberContext.CurrentTypeParameters; }
309 public MemberCore CurrentMemberDefinition {
310 get { return MemberContext.CurrentMemberDefinition; }
313 public bool ConstantCheckState {
314 get { return (flags & Options.ConstantCheckState) != 0; }
317 public bool IsInProbingMode {
319 return (flags & Options.ProbingMode) != 0;
323 public bool IsObsolete {
325 // Disables obsolete checks when probing is on
326 return MemberContext.IsObsolete;
330 public bool IsStatic {
332 return MemberContext.IsStatic;
336 public bool IsUnsafe {
338 return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe;
342 public bool IsRuntimeBinder {
344 return Module.Compiler.IsRuntimeBinder;
348 public bool IsVariableCapturingRequired {
350 return !IsInProbingMode;
354 public ModuleContainer Module {
356 return MemberContext.Module;
360 public Report Report {
362 return Module.Compiler.Report;
368 public bool MustCaptureVariable (INamedBlockVariable local)
370 if (CurrentAnonymousMethod == null)
374 // Capture only if this or any of child blocks contain yield
375 // or it's a parameter
377 if (CurrentAnonymousMethod.IsIterator)
378 return local.IsParameter || local.Block.Explicit.HasYield;
381 // Capture only if this or any of child blocks contain await
382 // or it's a parameter or we need to access variable from
383 // different parameter block
385 if (CurrentAnonymousMethod is AsyncInitializer)
386 return local.IsParameter || local.Block.Explicit.HasAwait || CurrentBlock.Explicit.HasAwait ||
387 local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
389 return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
392 public bool HasSet (Options options)
394 return (this.flags & options) == options;
397 public bool HasAny (Options options)
399 return (this.flags & options) != 0;
403 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
404 public FlagsHandle Set (Options options)
406 return new FlagsHandle (this, options);
409 public FlagsHandle With (Options options, bool enable)
411 return new FlagsHandle (this, options, enable ? options : 0);
414 #region IMemberContext Members
416 public string GetSignatureForError ()
418 return MemberContext.GetSignatureForError ();
421 public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
423 return MemberContext.LookupExtensionMethod (extensionType, name, arity);
426 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
428 return MemberContext.LookupNamespaceOrType (name, arity, mode, loc);
431 public FullNamedExpression LookupNamespaceAlias (string name)
433 return MemberContext.LookupNamespaceAlias (name);
439 public class FlowAnalysisContext
441 readonly CompilerContext ctx;
443 public FlowAnalysisContext (CompilerContext ctx, ParametersBlock parametersBlock, int definiteAssignmentLength)
446 this.ParametersBlock = parametersBlock;
448 DefiniteAssignment = definiteAssignmentLength == 0 ?
449 DefiniteAssignmentBitSet.Empty :
450 new DefiniteAssignmentBitSet (definiteAssignmentLength);
453 public DefiniteAssignmentBitSet DefiniteAssignment { get; set; }
455 public DefiniteAssignmentBitSet DefiniteAssignmentOnTrue { get; set; }
457 public DefiniteAssignmentBitSet DefiniteAssignmentOnFalse { get; set; }
459 public List<LabeledStatement> LabelStack { get; set; }
461 public ParametersBlock ParametersBlock { get; set; }
463 public Report Report {
469 public DefiniteAssignmentBitSet SwitchInitialDefinitiveAssignment { get; set; }
471 public TryFinally TryFinally { get; set; }
473 public bool UnreachableReported { get; set; }
475 public DefiniteAssignmentBitSet BranchDefiniteAssignment ()
477 var dat = DefiniteAssignment;
478 if (dat != DefiniteAssignmentBitSet.Empty)
479 DefiniteAssignment = new DefiniteAssignmentBitSet (dat);
483 public bool IsDefinitelyAssigned (VariableInfo variable)
485 return variable.IsAssigned (DefiniteAssignment);
488 public bool IsStructFieldDefinitelyAssigned (VariableInfo variable, string name)
490 return variable.IsStructFieldAssigned (DefiniteAssignment, name);
493 public void SetVariableAssigned (VariableInfo variable, bool generatedAssignment = false)
495 variable.SetAssigned (DefiniteAssignment, generatedAssignment);
498 public void SetStructFieldAssigned (VariableInfo variable, string name)
500 variable.SetStructFieldAssigned (DefiniteAssignment, name);
506 // This class is used during the Statement.Clone operation
507 // to remap objects that have been cloned.
509 // Since blocks are cloned by Block.Clone, we need a way for
510 // expressions that must reference the block to be cloned
511 // pointing to the new cloned block.
513 public class CloneContext
515 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
517 public void AddBlockMap (Block from, Block to)
519 block_map.Add (from, to);
522 public Block LookupBlock (Block from)
525 if (!block_map.TryGetValue (from, out result)) {
526 result = (Block) from.Clone (this);
533 /// Remaps block to cloned copy if one exists.
535 public Block RemapBlockCopy (Block from)
538 if (!block_map.TryGetValue (from, out mapped_to))
546 // Main compiler context
548 public class CompilerContext
550 static readonly TimeReporter DisabledTimeReporter = new TimeReporter (false);
552 readonly Report report;
553 readonly BuiltinTypes builtin_types;
554 readonly CompilerSettings settings;
556 Dictionary<string, SourceFile> all_source_files;
558 public CompilerContext (CompilerSettings settings, ReportPrinter reportPrinter)
560 this.settings = settings;
561 this.report = new Report (this, reportPrinter);
562 this.builtin_types = new BuiltinTypes ();
563 this.TimeReporter = DisabledTimeReporter;
568 public BuiltinTypes BuiltinTypes {
570 return builtin_types;
574 // Used for special handling of runtime dynamic context mostly
575 // by error reporting but also by member accessibility checks
576 public bool IsRuntimeBinder {
580 public Report Report {
586 public CompilerSettings Settings {
592 public List<SourceFile> SourceFiles {
594 return settings.SourceFiles;
598 internal TimeReporter TimeReporter {
605 // This is used when we encounter a #line preprocessing directive during parsing
606 // to register additional source file names
608 public SourceFile LookupFile (CompilationSourceFile comp_unit, string name)
610 if (all_source_files == null) {
611 all_source_files = new Dictionary<string, SourceFile> ();
612 foreach (var source in SourceFiles)
613 all_source_files[source.FullPathName] = source;
617 if (!Path.IsPathRooted (name)) {
618 string root = Path.GetDirectoryName (comp_unit.SourceFile.FullPathName);
619 path = Path.GetFullPath (Path.Combine (root, name));
624 if (all_source_files.TryGetValue (path, out retval))
627 retval = new SourceFile (name, path, all_source_files.Count + 1);
628 Location.AddFile (retval);
629 all_source_files.Add (path, retval);
635 // Generic code emitter context
637 public class BuilderContext
643 /// This flag tracks the `checked' state of the compilation,
644 /// it controls whether we should generate code that does overflow
645 /// checking, or if we generate code that ignores overflows.
647 /// The default setting comes from the command line option to generate
648 /// checked or unchecked code plus any source code changes using the
649 /// checked/unchecked statements or expressions. Contrast this with
650 /// the ConstantCheckState flag.
652 CheckedScope = 1 << 0,
654 AccurateDebugInfo = 1 << 1,
656 OmitDebugInfo = 1 << 2,
658 ConstructorScope = 1 << 3,
663 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
664 // it's public so that we can use a struct at the callsite
665 public struct FlagsHandle : IDisposable
667 readonly BuilderContext ec;
668 readonly Options invmask, oldval;
670 public FlagsHandle (BuilderContext ec, Options flagsToSet)
671 : this (ec, flagsToSet, flagsToSet)
675 internal FlagsHandle (BuilderContext ec, Options mask, Options val)
679 oldval = ec.flags & mask;
680 ec.flags = (ec.flags & invmask) | (val & mask);
683 public void Dispose ()
685 ec.flags = (ec.flags & invmask) | oldval;
689 protected Options flags;
691 public bool HasSet (Options options)
693 return (this.flags & options) == options;
696 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
697 public FlagsHandle With (Options options, bool enable)
699 return new FlagsHandle (this, options, enable ? options : 0);
704 // Parser session objects. We could recreate all these objects for each parser
705 // instance but the best parser performance the session object can be reused
707 public class ParserSession
711 public readonly char[] StreamReaderBuffer = new char[SeekableStreamReader.DefaultReadAheadSize * 2];
712 public readonly Dictionary<char[], string>[] Identifiers = new Dictionary<char[], string>[Tokenizer.MaxIdentifierLength + 1];
713 public readonly List<Parameter> ParametersStack = new List<Parameter> (4);
714 public readonly char[] IDBuilder = new char[Tokenizer.MaxIdentifierLength];
715 public readonly char[] NumberBuilder = new char[Tokenizer.MaxNumberLength];
717 public LocationsBag LocationsBag { get; set; }
718 public bool UseJayGlobalArrays { get; set; }
719 public LocatedToken[] LocatedTokens { get; set; }
721 public MD5 GetChecksumAlgorithm ()
723 return md5 ?? (md5 = MD5.Create ());