[fix] #631810: Form.DialogResult needs to call its close events *before* closing.
[mono.git] / mcs / mcs / context.cs
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.
10 //
11
12 using System;
13 using System.Collections.Generic;
14 using System.Reflection.Emit;
15
16 namespace Mono.CSharp
17 {
18         //
19         // Implemented by elements which can act as independent contexts
20         // during resolve phase. Used mostly for lookups.
21         //
22         public interface IMemberContext
23         {
24                 //
25                 // A scope type context, it can be inflated for generic types
26                 //
27                 TypeSpec CurrentType { get; }
28
29                 //
30                 // A scope type parameters either VAR or MVAR
31                 //
32                 TypeParameter[] CurrentTypeParameters { get; }
33
34                 //
35                 // A member definition of the context. For partial types definition use
36                 // CurrentTypeDefinition.PartialContainer otherwise the context is local
37                 //
38                 MemberCore CurrentMemberDefinition { get; }
39
40                 bool IsObsolete { get; }
41                 bool IsUnsafe { get; }
42                 bool IsStatic { get; }
43                 bool HasUnresolvedConstraints { get; }
44
45                 string GetSignatureForError ();
46
47                 IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope);
48                 FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104);
49                 FullNamedExpression LookupNamespaceAlias (string name);
50
51                 CompilerContext Compiler { get; }
52         }
53
54         //
55         // Block or statement resolving context
56         //
57         public class BlockContext : ResolveContext
58         {
59                 FlowBranching current_flow_branching;
60
61                 TypeSpec return_type;
62
63                 /// <summary>
64                 ///   The location where return has to jump to return the
65                 ///   value
66                 /// </summary>
67                 public Label ReturnLabel;       // TODO: It's emit dependant
68
69                 /// <summary>
70                 ///   If we already defined the ReturnLabel
71                 /// </summary>
72                 public bool HasReturnLabel;
73
74                 public int FlowOffset;
75
76                 public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
77                         : base (mc)
78                 {
79                         if (returnType == null)
80                                 throw new ArgumentNullException ("returnType");
81
82                         this.return_type = returnType;
83
84                         // TODO: check for null value
85                         CurrentBlock = block;
86                 }
87
88                 public BlockContext (ResolveContext rc, ExplicitBlock block, TypeSpec returnType)
89                         : this (rc.MemberContext, block, returnType)
90                 {
91                         if (rc.IsUnsafe)
92                                 flags |= ResolveContext.Options.UnsafeScope;
93
94                         if (rc.HasSet (ResolveContext.Options.CheckedScope))
95                                 flags |= ResolveContext.Options.CheckedScope;
96                 }
97
98                 public override FlowBranching CurrentBranching {
99                         get { return current_flow_branching; }
100                 }
101
102                 // <summary>
103                 //   Starts a new code branching.  This inherits the state of all local
104                 //   variables and parameters from the current branching.
105                 // </summary>
106                 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
107                 {
108                         current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
109                         return current_flow_branching;
110                 }
111
112                 // <summary>
113                 //   Starts a new code branching for block `block'.
114                 // </summary>
115                 public FlowBranching StartFlowBranching (Block block)
116                 {
117                         Set (Options.DoFlowAnalysis);
118
119                         current_flow_branching = FlowBranching.CreateBranching (
120                                 CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
121                         return current_flow_branching;
122                 }
123
124                 public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
125                 {
126                         FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
127                         current_flow_branching = branching;
128                         return branching;
129                 }
130
131                 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
132                 {
133                         FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
134                         current_flow_branching = branching;
135                         return branching;
136                 }
137
138                 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
139                 {
140                         FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
141                         current_flow_branching = branching;
142                         return branching;
143                 }
144
145                 public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
146                 {
147                         FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
148                         current_flow_branching = branching;
149                         return branching;
150                 }
151
152                 public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
153                 {
154                         FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
155                         current_flow_branching = branching;
156                         return branching;
157                 }
158
159                 // <summary>
160                 //   Ends a code branching.  Merges the state of locals and parameters
161                 //   from all the children of the ending branching.
162                 // </summary>
163                 public bool EndFlowBranching ()
164                 {
165                         FlowBranching old = current_flow_branching;
166                         current_flow_branching = current_flow_branching.Parent;
167
168                         FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
169                         return vector.IsUnreachable;
170                 }
171
172                 // <summary>
173                 //   Kills the current code branching.  This throws away any changed state
174                 //   information and should only be used in case of an error.
175                 // </summary>
176                 // FIXME: this is evil
177                 public void KillFlowBranching ()
178                 {
179                         current_flow_branching = current_flow_branching.Parent;
180                 }
181
182                 //
183                 // This method is used during the Resolution phase to flag the
184                 // need to define the ReturnLabel
185                 //
186                 public void NeedReturnLabel ()
187                 {
188                         if (!HasReturnLabel)
189                                 HasReturnLabel = true;
190                 }
191
192                 public TypeSpec ReturnType {
193                         get { return return_type; }
194                 }
195         }
196
197         //
198         // Expression resolving context
199         //
200         public class ResolveContext : IMemberContext
201         {
202                 [Flags]
203                 public enum Options
204                 {
205                         /// <summary>
206                         ///   This flag tracks the `checked' state of the compilation,
207                         ///   it controls whether we should generate code that does overflow
208                         ///   checking, or if we generate code that ignores overflows.
209                         ///
210                         ///   The default setting comes from the command line option to generate
211                         ///   checked or unchecked code plus any source code changes using the
212                         ///   checked/unchecked statements or expressions.   Contrast this with
213                         ///   the ConstantCheckState flag.
214                         /// </summary>
215                         CheckedScope = 1 << 0,
216
217                         /// <summary>
218                         ///   The constant check state is always set to `true' and cant be changed
219                         ///   from the command line.  The source code can change this setting with
220                         ///   the `checked' and `unchecked' statements and expressions. 
221                         /// </summary>
222                         ConstantCheckState = 1 << 1,
223
224                         AllCheckStateFlags = CheckedScope | ConstantCheckState,
225
226                         //
227                         // unsafe { ... } scope
228                         //
229                         UnsafeScope = 1 << 2,
230                         CatchScope = 1 << 3,
231                         FinallyScope = 1 << 4,
232                         FieldInitializerScope = 1 << 5,
233                         CompoundAssignmentScope = 1 << 6,
234                         FixedInitializerScope = 1 << 7,
235                         BaseInitializer = 1 << 8,
236
237                         //
238                         // Inside an enum definition, we do not resolve enumeration values
239                         // to their enumerations, but rather to the underlying type/value
240                         // This is so EnumVal + EnumValB can be evaluated.
241                         //
242                         // There is no "E operator + (E x, E y)", so during an enum evaluation
243                         // we relax the rules
244                         //
245                         EnumScope = 1 << 9,
246
247                         ConstantScope = 1 << 10,
248
249                         ConstructorScope = 1 << 11,
250
251                         UsingInitializerScope = 1 << 12,
252
253                         /// <summary>
254                         ///   Whether control flow analysis is enabled
255                         /// </summary>
256                         DoFlowAnalysis = 1 << 20,
257
258                         /// <summary>
259                         ///   Whether control flow analysis is disabled on structs
260                         ///   (only meaningful when DoFlowAnalysis is set)
261                         /// </summary>
262                         OmitStructFlowAnalysis = 1 << 21,
263
264                         ///
265                         /// Indicates the current context is in probing mode, no errors are reported. 
266                         ///
267                         ProbingMode = 1 << 22,
268
269                         //
270                         // Return and ContextualReturn statements will set the ReturnType
271                         // value based on the expression types of each return statement
272                         // instead of the method return type which is initially null.
273                         //
274                         InferReturnType = 1 << 23,
275
276                         OmitDebuggingInfo = 1 << 24,
277
278                         ExpressionTreeConversion = 1 << 25,
279
280                         InvokeSpecialName = 1 << 26
281                 }
282
283                 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
284                 // it's public so that we can use a struct at the callsite
285                 public struct FlagsHandle : IDisposable
286                 {
287                         ResolveContext ec;
288                         readonly Options invmask, oldval;
289
290                         public FlagsHandle (ResolveContext ec, Options flagsToSet)
291                                 : this (ec, flagsToSet, flagsToSet)
292                         {
293                         }
294
295                         internal FlagsHandle (ResolveContext ec, Options mask, Options val)
296                         {
297                                 this.ec = ec;
298                                 invmask = ~mask;
299                                 oldval = ec.flags & mask;
300                                 ec.flags = (ec.flags & invmask) | (val & mask);
301
302 //                              if ((mask & Options.ProbingMode) != 0)
303 //                                      ec.Report.DisableReporting ();
304                         }
305
306                         public void Dispose ()
307                         {
308 //                              if ((invmask & Options.ProbingMode) == 0)
309 //                                      ec.Report.EnableReporting ();
310
311                                 ec.flags = (ec.flags & invmask) | oldval;
312                         }
313                 }
314
315                 protected Options flags;
316
317                 //
318                 // Whether we are inside an anonymous method.
319                 //
320                 public AnonymousExpression CurrentAnonymousMethod;
321
322                 //
323                 // Holds a varible used during collection or object initialization.
324                 //
325                 public Expression CurrentInitializerVariable;
326
327                 public Block CurrentBlock;
328
329                 public IMemberContext MemberContext;
330
331                 /// <summary>
332                 ///   If this is non-null, points to the current switch statement
333                 /// </summary>
334                 public Switch Switch;
335
336                 public ResolveContext (IMemberContext mc)
337                 {
338                         if (mc == null)
339                                 throw new ArgumentNullException ();
340
341                         MemberContext = mc;
342
343                         //
344                         // The default setting comes from the command line option
345                         //
346                         if (RootContext.Checked)
347                                 flags |= Options.CheckedScope;
348
349                         //
350                         // The constant check state is always set to true
351                         //
352                         flags |= Options.ConstantCheckState;
353                 }
354
355                 public ResolveContext (IMemberContext mc, Options options)
356                         : this (mc)
357                 {
358                         flags |= options;
359                 }
360
361                 public CompilerContext Compiler {
362                         get { return MemberContext.Compiler; }
363                 }
364
365                 public virtual ExplicitBlock ConstructorBlock {
366                         get {
367                                 return CurrentBlock.Explicit;
368                         }
369                 }
370
371                 public virtual FlowBranching CurrentBranching {
372                         get { return null; }
373                 }
374
375                 //
376                 // The current iterator
377                 //
378                 public Iterator CurrentIterator {
379                         get { return CurrentAnonymousMethod as Iterator; }
380                 }
381
382                 public TypeSpec CurrentType {
383                         get { return MemberContext.CurrentType; }
384                 }
385
386                 public TypeParameter[] CurrentTypeParameters {
387                         get { return MemberContext.CurrentTypeParameters; }
388                 }
389
390                 public MemberCore CurrentMemberDefinition {
391                         get { return MemberContext.CurrentMemberDefinition; }
392                 }
393
394                 public bool ConstantCheckState {
395                         get { return (flags & Options.ConstantCheckState) != 0; }
396                 }
397
398                 public bool DoFlowAnalysis {
399                         get { return (flags & Options.DoFlowAnalysis) != 0; }
400                 }
401
402                 public bool HasUnresolvedConstraints {
403                         get { return false; }
404                 }
405
406                 public bool IsInProbingMode {
407                         get { return (flags & Options.ProbingMode) != 0; }
408                 }
409
410                 public bool IsVariableCapturingRequired {
411                         get {
412                                 return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
413                         }
414                 }
415
416                 public bool OmitStructFlowAnalysis {
417                         get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
418                 }
419
420                 // TODO: Merge with CompilerGeneratedThis
421                 public Expression GetThis (Location loc)
422                 {
423                         This my_this = new This (loc);
424                         my_this.ResolveBase (this);
425                         return my_this;
426                 }
427
428                 public bool MustCaptureVariable (INamedBlockVariable local)
429                 {
430                         if (CurrentAnonymousMethod == null)
431                                 return false;
432
433                         // FIXME: IsIterator is too aggressive, we should capture only if child
434                         // block contains yield
435                         if (CurrentAnonymousMethod.IsIterator)
436                                 return true;
437
438                         return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
439                 }
440
441                 public bool HasSet (Options options)
442                 {
443                         return (this.flags & options) == options;
444                 }
445
446                 public bool HasAny (Options options)
447                 {
448                         return (this.flags & options) != 0;
449                 }
450
451                 public Report Report {
452                         get {
453                                 return Compiler.Report;
454                         }
455                 }
456
457                 // Temporarily set all the given flags to the given value.  Should be used in an 'using' statement
458                 public FlagsHandle Set (Options options)
459                 {
460                         return new FlagsHandle (this, options);
461                 }
462
463                 public FlagsHandle With (Options options, bool enable)
464                 {
465                         return new FlagsHandle (this, options, enable ? options : 0);
466                 }
467
468                 #region IMemberContext Members
469
470                 public string GetSignatureForError ()
471                 {
472                         return MemberContext.GetSignatureForError ();
473                 }
474
475                 public bool IsObsolete {
476                         get {
477                                 // Disables obsolete checks when probing is on
478                                 return MemberContext.IsObsolete;
479                         }
480                 }
481
482                 public bool IsStatic {
483                         get { return MemberContext.IsStatic; }
484                 }
485
486                 public bool IsUnsafe {
487                         get { return HasSet (Options.UnsafeScope) || MemberContext.IsUnsafe; }
488                 }
489
490                 public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
491                 {
492                         return MemberContext.LookupExtensionMethod (extensionType, name, arity, ref scope);
493                 }
494
495                 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
496                 {
497                         return MemberContext.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
498                 }
499
500                 public FullNamedExpression LookupNamespaceAlias (string name)
501                 {
502                         return MemberContext.LookupNamespaceAlias (name);
503                 }
504
505                 #endregion
506         }
507
508         //
509         // This class is used during the Statement.Clone operation
510         // to remap objects that have been cloned.
511         //
512         // Since blocks are cloned by Block.Clone, we need a way for
513         // expressions that must reference the block to be cloned
514         // pointing to the new cloned block.
515         //
516         public class CloneContext
517         {
518                 Dictionary<Block, Block> block_map = new Dictionary<Block, Block> ();
519
520                 public void AddBlockMap (Block from, Block to)
521                 {
522                         block_map.Add (from, to);
523                 }
524
525                 public Block LookupBlock (Block from)
526                 {
527                         Block result;
528                         if (!block_map.TryGetValue (from, out result)) {
529                                 result = (Block) from.Clone (this);
530                         }
531
532                         return result;
533                 }
534
535                 ///
536                 /// Remaps block to cloned copy if one exists.
537                 ///
538                 public Block RemapBlockCopy (Block from)
539                 {
540                         Block mapped_to;
541                         if (!block_map.TryGetValue (from, out mapped_to))
542                                 return from;
543
544                         return mapped_to;
545                 }
546         }
547
548         //
549         // Main compiler context
550         //
551         public class CompilerContext
552         {
553                 readonly Report report;
554                 readonly ReflectionMetaImporter meta_importer;
555                 readonly PredefinedAttributes attributes;
556                 readonly GlobalRootNamespace root;
557
558                 public CompilerContext (ReflectionMetaImporter metaImporter, Report report)
559                 {
560                         this.meta_importer = metaImporter;
561                         this.report = report;
562
563                         this.attributes = new PredefinedAttributes ();
564                         this.root = new GlobalRootNamespace ();
565                 }
566
567                 public GlobalRootNamespace GlobalRootNamespace {
568                         get {
569                                 return root;
570                         }
571                 }
572
573                 public bool IsRuntimeBinder { get; set; }
574
575                 public ReflectionMetaImporter MetaImporter {
576                         get {
577                                 return meta_importer;
578                         }
579                 }
580
581                 public PredefinedAttributes PredefinedAttributes {
582                         get {
583                                 return attributes;
584                         }
585                 }
586
587                 public Report Report {
588                         get {
589                                 return report;
590                         }
591                 }
592         }
593
594         //
595         // Generic code emitter context
596         //
597         public class BuilderContext
598         {
599                 [Flags]
600                 public enum Options
601                 {
602                         /// <summary>
603                         ///   This flag tracks the `checked' state of the compilation,
604                         ///   it controls whether we should generate code that does overflow
605                         ///   checking, or if we generate code that ignores overflows.
606                         ///
607                         ///   The default setting comes from the command line option to generate
608                         ///   checked or unchecked code plus any source code changes using the
609                         ///   checked/unchecked statements or expressions.   Contrast this with
610                         ///   the ConstantCheckState flag.
611                         /// </summary>
612                         CheckedScope = 1 << 0,
613
614                         /// <summary>
615                         ///   The constant check state is always set to `true' and cant be changed
616                         ///   from the command line.  The source code can change this setting with
617                         ///   the `checked' and `unchecked' statements and expressions. 
618                         /// </summary>
619                         ConstantCheckState = 1 << 1,
620
621                         AllCheckStateFlags = CheckedScope | ConstantCheckState,
622
623                         OmitDebugInfo = 1 << 2,
624
625                         ConstructorScope = 1 << 3
626                 }
627
628                 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
629                 // it's public so that we can use a struct at the callsite
630                 public struct FlagsHandle : IDisposable
631                 {
632                         BuilderContext ec;
633                         readonly Options invmask, oldval;
634
635                         public FlagsHandle (BuilderContext ec, Options flagsToSet)
636                                 : this (ec, flagsToSet, flagsToSet)
637                         {
638                         }
639
640                         internal FlagsHandle (BuilderContext ec, Options mask, Options val)
641                         {
642                                 this.ec = ec;
643                                 invmask = ~mask;
644                                 oldval = ec.flags & mask;
645                                 ec.flags = (ec.flags & invmask) | (val & mask);
646                         }
647
648                         public void Dispose ()
649                         {
650                                 ec.flags = (ec.flags & invmask) | oldval;
651                         }
652                 }
653
654                 Options flags;
655
656                 public bool HasSet (Options options)
657                 {
658                         return (this.flags & options) == options;
659                 }
660
661                 // Temporarily set all the given flags to the given value.  Should be used in an 'using' statement
662                 public FlagsHandle With (Options options, bool enable)
663                 {
664                         return new FlagsHandle (this, options, enable ? options : 0);
665                 }
666         }
667 }