condition tests passes
[mono.git] / mcs / mcs / codegen.cs
index a2c100bc519c7faf9c2bb55cb42577a2be3ae238..af57f0f9a717474010dcfc76972972dbc59dc82e 100644 (file)
 //
 // Only remove it if you need to debug locally on your tree.
 //
-//#define PRODUCTION
+#define PRODUCTION
 
 using System;
 using System.IO;
 using System.Collections;
 using System.Collections.Specialized;
+using System.Globalization;
 using System.Reflection;
 using System.Reflection.Emit;
 using System.Runtime.InteropServices;
@@ -220,12 +221,18 @@ namespace Mono.CSharp {
        /// </summary>
        public class EmitContext : IResolveContext {
 
-               DeclSpace declSpace;
+               //
+               // Holds a varible used during collection or object initialization.
+               //
+               public Expression CurrentInitializerVariable;
+
+               DeclSpace decl_space;
+               
                public DeclSpace TypeContainer;
-               public ILGenerator   ig;
+               public ILGenerator ig;
 
                [Flags]
-               public enum Flags : byte {
+               public enum Flags : int {
                        /// <summary>
                        ///   This flag tracks the `checked' state of the compilation,
                        ///   it controls whether we should generate code that does overflow
@@ -264,7 +271,21 @@ namespace Mono.CSharp {
                        ///   Whether control flow analysis is disabled on structs
                        ///   (only meaningful when DoFlowAnalysis is set)
                        /// </summary>
-                       OmitStructFlowAnalysis = 1 << 6
+                       OmitStructFlowAnalysis = 1 << 6,
+
+                       ///
+                       /// Indicates the current context is in probing mode, no errors are reported. 
+                       ///
+                       ProbingMode = 1 <<      7,
+
+                       //
+                       // Inside field intializer expression
+                       //
+                       InFieldInitializer = 1 << 8,
+                       
+                       InferReturnType = 1 << 9,
+                       
+                       InCompoundAssignment = 1 << 10
                }
 
                Flags flags;
@@ -284,22 +305,17 @@ namespace Mono.CSharp {
                /// </summary>
                public bool MethodIsStatic;
 
-               /// <summary>
-               ///   Whether we are emitting a field initializer
-               /// </summary>
-               public bool IsFieldInitializer;
-
                /// <summary>
                ///   The value that is allowed to be returned or NULL if there is no
                ///   return type.
                /// </summary>
-               public readonly Type ReturnType;
+               Type return_type;
 
                /// <summary>
                ///   Points to the Type (extracted from the TypeContainer) that
                ///   declares this body of code
                /// </summary>
-               public Type ContainerType;
+               public readonly Type ContainerType;
                
                /// <summary>
                ///   Whether this is generating code for a constructor
@@ -338,8 +354,6 @@ namespace Mono.CSharp {
                /// </summary>
                public bool InIterator;
 
-               public bool IsLastStatement;
-
                /// <summary>
                ///  Whether we are in a `fixed' initialization
                /// </summary>
@@ -406,11 +420,13 @@ namespace Mono.CSharp {
                        this.ig = ig;
 
                        TypeContainer = parent;
-                       this.declSpace = ds;
+                       this.decl_space = ds;
                        if (RootContext.Checked)
                                flags |= Flags.CheckState;
                        flags |= Flags.ConstantCheckState;
 
+                       if (return_type == null)
+                               throw new ArgumentNullException ("return_type");
 #if GMCS_SOURCE
                        if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition)
                                throw new InternalErrorException ();
@@ -432,9 +448,6 @@ namespace Mono.CSharp {
                                        flags |= Flags.InUnsafe;
                        }
                        loc = l;
-
-                       if (ReturnType == TypeManager.void_type)
-                               ReturnType = null;
                }
 
                public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
@@ -450,8 +463,8 @@ namespace Mono.CSharp {
                }
 
                public DeclSpace DeclContainer { 
-                       get { return declSpace; }
-                       set { declSpace = value; }
+                       get { return decl_space; }
+                       set { decl_space = value; }
                }
 
                public DeclSpace GenericDeclContainer {
@@ -491,21 +504,39 @@ namespace Mono.CSharp {
                public struct FlagsHandle : IDisposable
                {
                        EmitContext ec;
-                       Flags invmask, oldval;
+                       readonly Flags invmask, oldval;
+
+                       public FlagsHandle (EmitContext ec, Flags flagsToSet)
+                               : this (ec, flagsToSet, flagsToSet)
+                       {
+                       }
+
                        internal FlagsHandle (EmitContext ec, Flags mask, Flags val)
                        {
                                this.ec = ec;
                                invmask = ~mask;
                                oldval = ec.flags & mask;
                                ec.flags = (ec.flags & invmask) | (val & mask);
+
+                               if ((mask & Flags.ProbingMode) != 0)
+                                       Report.DisableReporting ();
                        }
+
                        public void Dispose ()
                        {
+                               if ((invmask & Flags.ProbingMode) == 0)
+                                       Report.EnableReporting ();
+
                                ec.flags = (ec.flags & invmask) | oldval;
                        }
                }
 
                // Temporarily set all the given flags to the given value.  Should be used in an 'using' statement
+               public FlagsHandle Set (Flags flagsToSet)
+               {
+                       return new FlagsHandle (this, flagsToSet);
+               }
+
                public FlagsHandle With (Flags bits, bool enable)
                {
                        return new FlagsHandle (this, bits, enable ? bits : 0);
@@ -518,9 +549,26 @@ namespace Mono.CSharp {
                                (omit_struct_analysis ? Flags.OmitStructFlowAnalysis : 0);
                        return new FlagsHandle (this, Flags.DoFlowAnalysis | Flags.OmitStructFlowAnalysis, newflags);
                }
+               
+               /// <summary>
+               ///   If this is true, then Return and ContextualReturn statements
+               ///   will set the ReturnType value based on the expression types
+               ///   of each return statement instead of the method return type
+               ///   (which is initially null).
+               /// </summary>
+               public bool InferReturnType {
+                       get { return (flags & Flags.InferReturnType) != 0; }
+               }
 
                public bool IsInObsoleteScope {
-                       get { return ResolveContext.IsInObsoleteScope; }
+                       get {
+                               // Disables obsolete checks when probing is on
+                               return IsInProbingMode || ResolveContext.IsInObsoleteScope;
+                       }
+               }
+
+               public bool IsInProbingMode {
+                       get { return (flags & Flags.ProbingMode) != 0; }
                }
 
                public bool IsInUnsafeScope {
@@ -532,6 +580,14 @@ namespace Mono.CSharp {
                        set { isAnonymousMethodAllowed = value; }
                }
 
+               public bool IsInFieldInitializer {
+                       get { return (flags & Flags.InFieldInitializer) != 0; }
+               }
+               
+               public bool IsInCompoundAssignment {
+                       get { return (flags & Flags.InCompoundAssignment) != 0; }
+               }               
+
                public FlowBranching CurrentBranching {
                        get { return current_flow_branching; }
                }
@@ -603,11 +659,11 @@ namespace Mono.CSharp {
                //   Ends a code branching.  Merges the state of locals and parameters
                //   from all the children of the ending branching.
                // </summary>
-               public FlowBranching.Reachability EndFlowBranching ()
+               public bool EndFlowBranching ()
                {
                        FlowBranching.UsageVector vector = DoEndFlowBranching ();
 
-                       return vector.Reachability;
+                       return vector.IsUnreachable;
                }
 
                // <summary>
@@ -649,6 +705,9 @@ namespace Mono.CSharp {
                        bool unreachable;
                        
                        if (ResolveTopBlock (null, block, md.ParameterInfo, md, out unreachable)){
+                               if (Report.Errors > 0)
+                                       return;
+
                                EmitMeta (block);
 
                                current_phase = Phase.Emitting;
@@ -678,7 +737,7 @@ namespace Mono.CSharp {
                                        return false;
 
                                if ((md != null) && (md.Iterator != null)) {
-                                       if (!md.Iterator.Resolve (this))
+                                       if (!md.Iterator.Define (this))
                                                return false;
                                }
 
@@ -696,8 +755,8 @@ namespace Mono.CSharp {
                                        if (!ok)
                                                return false;
 
-                                       FlowBranching.Reachability reachability = top_level.End ();
-                                       if (reachability.IsUnreachable)
+                                       bool flow_unreachable = top_level.End ();
+                                       if (flow_unreachable)
                                                unreachable = true;
                                }
 #if PRODUCTION
@@ -714,7 +773,7 @@ namespace Mono.CSharp {
                        }
 #endif
 
-                       if (ReturnType != null && !unreachable) {
+                       if (return_type != TypeManager.void_type && !unreachable) {
                                if (CurrentAnonymousMethod == null) {
                                        Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
                                        return false;
@@ -732,6 +791,15 @@ namespace Mono.CSharp {
                        return true;
                }
 
+               public Type ReturnType {
+                       set {
+                               return_type = value;
+                       }
+                       get {
+                               return return_type;
+                       }
+               }
+
                public void EmitResolvedTopBlock (ToplevelBlock block, bool unreachable)
                {
                        if (block != null)
@@ -763,7 +831,7 @@ namespace Mono.CSharp {
                                if ((block != null) && block.IsDestructor) {
                                        // Nothing to do; S.R.E automatically emits a leave.
                                } else if (HasReturnLabel || (!unreachable && !in_iterator)) {
-                                       if (ReturnType != null)
+                                       if (return_type != TypeManager.void_type)
                                                ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
                                        ig.Emit (OpCodes.Ret);
                                }
@@ -886,7 +954,7 @@ namespace Mono.CSharp {
                public LocalBuilder TemporaryReturn ()
                {
                        if (return_value == null){
-                               return_value = ig.DeclareLocal (ReturnType);
+                               return_value = ig.DeclareLocal (return_type);
                                if (!HasReturnLabel){
                                        ReturnLabel = ig.DefineLabel ();
                                        HasReturnLabel = true;
@@ -997,12 +1065,12 @@ namespace Mono.CSharp {
                public AssemblyBuilder Builder;
                bool is_cls_compliant;
                bool wrap_non_exception_throws;
-               bool has_extension_method;
 
                public Attribute ClsCompliantAttribute;
 
                ListDictionary declarative_security;
 #if GMCS_SOURCE
+               bool has_extension_method;              
                public AssemblyName Name;
                MethodInfo add_type_forwarder;
                ListDictionary emitted_forwarders;
@@ -1019,7 +1087,11 @@ namespace Mono.CSharp {
                }
 
                public bool HasExtensionMethods {
-                       set { has_extension_method = value; }
+                       set {
+#if GMCS_SOURCE                                
+                               has_extension_method = value;
+#endif
+                       }
                }
 
                public bool IsClsCompliant {
@@ -1240,7 +1312,7 @@ namespace Mono.CSharp {
                        else if (aname.Version != null || aname.CultureInfo != null)
                                throw new Exception ("Friend assembly `" + a.GetString () + 
                                                "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
-                       else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null) {
+                       else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null && Name.GetPublicKey ().Length != 0) {
                                Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
                                                " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
                                return false;
@@ -1250,6 +1322,28 @@ namespace Mono.CSharp {
                }
 #endif
 
+               static bool IsValidAssemblyVersion (string version)
+               {
+                       Version v;
+                       try {
+                               v = new Version (version);
+                       } catch {
+                               try {
+                                       int major = int.Parse (version, CultureInfo.InvariantCulture);
+                                       v = new Version (major, 0);
+                               } catch {
+                                       return false;
+                               }
+                       }
+
+                       foreach (int candidate in new int [] { v.Major, v.Minor, v.Build, v.Revision }) {
+                               if (candidate > ushort.MaxValue)
+                                       return false;
+                       }
+
+                       return true;
+               }
+
                public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
                {
                        if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) {
@@ -1271,6 +1365,19 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       if (a.Type == TypeManager.assembly_version_attribute_type) {
+                               string value = a.GetString ();
+                               if (value == null || value.Length == 0)
+                                       return;
+
+                               value = value.Replace ('*', '0');
+
+                               if (!IsValidAssemblyVersion (value)) {
+                                       a.Error_AttributeEmitError (string.Format ("Specified version `{0}' is not valid", value));
+                                       return;
+                               }
+                       }
+
 #if GMCS_SOURCE
                        if (a.Type == TypeManager.internals_visible_attr_type && !CheckInternalsVisibleAttribute (a))
                                return;
@@ -1415,6 +1522,7 @@ namespace Mono.CSharp {
                // TODO: make it private and move all builder based methods here
                public ModuleBuilder Builder;
                bool m_module_is_unsafe;
+               bool has_default_charset;
 
                public CharSet DefaultCharSet = CharSet.Ansi;
                public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
@@ -1468,6 +1576,12 @@ namespace Mono.CSharp {
                        Builder.SetCustomAttribute (customBuilder);
                }
 
+               public bool HasDefaultCharSet {
+                       get {
+                               return has_default_charset;
+                       }
+               }
+
                /// <summary>
                /// It is called very early therefore can resolve only predefined attributes
                /// </summary>
@@ -1482,6 +1596,7 @@ namespace Mono.CSharp {
 
                        Attribute a = ResolveAttribute (TypeManager.default_charset_type);
                        if (a != null) {
+                               has_default_charset = true;
                                DefaultCharSet = a.GetCharSetValue ();
                                switch (DefaultCharSet) {
                                        case CharSet.Ansi: