Don't check constraints for anonymous method stories it's not needed and it's hard...
[mono.git] / mcs / mcs / codegen.cs
index cb705c4b2e598619c50933d648749f1d78b38015..e8900de8bf1d5ea9d1116526a2b78e35101b1f75 100644 (file)
 
 using System;
 using System.Collections.Generic;
+
+#if STATIC
+using MetaType = IKVM.Reflection.Type;
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
+#else
+using MetaType = System.Type;
 using System.Reflection;
 using System.Reflection.Emit;
-using System.Runtime.InteropServices;
-using System.Security.Cryptography;
-
-namespace Mono.CSharp {
-
-       /// <summary>
-       ///    Code generator class.
-       /// </summary>
-       public class CodeGen {
-               static AppDomain current_domain;
-
-               // Breaks dynamic and repl
-               public static AssemblyClass Assembly;
-
-               static CodeGen ()
-               {
-                       Reset ();
-               }
-
-               public static void Reset ()
-               {
-                       Assembly = new AssemblyClass ();
-               }
-
-               public static string Basename (string name)
-               {
-                       int pos = name.LastIndexOf ('/');
-
-                       if (pos != -1)
-                               return name.Substring (pos + 1);
-
-                       pos = name.LastIndexOf ('\\');
-                       if (pos != -1)
-                               return name.Substring (pos + 1);
-
-                       return name;
-               }
-
-               public static string Dirname (string name)
-               {
-                       int pos = name.LastIndexOf ('/');
-
-                       if (pos != -1)
-                               return name.Substring (0, pos);
-
-                       pos = name.LastIndexOf ('\\');
-                       if (pos != -1)
-                               return name.Substring (0, pos);
-
-                       return ".";
-               }
-
-               static public string FileName;
-                               
-               //
-               // Initializes the code generator variables for interactive use (repl)
-               //
-               static public void InitDynamic (CompilerContext ctx, string name)
-               {
-                       current_domain = AppDomain.CurrentDomain;
-                       AssemblyName an = Assembly.GetAssemblyName (name, name);
-                       
-                       Assembly.Builder = current_domain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
-                       RootContext.ToplevelTypes = new ModuleCompiled (ctx, true);
-                       RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (Basename (name), false);
-                       Assembly.Name = Assembly.Builder.GetName ();
-               }
-
-               //
-               // Initializes the code generator variables
-               //
-               static public bool Init (string name, string output, bool want_debugging_support, CompilerContext ctx)
-               {
-                       FileName = output;
-                       AssemblyName an = Assembly.GetAssemblyName (name, output);
-                       if (an == null)
-                               return false;
-
-                       if (an.KeyPair != null) {
-                               // If we are going to strong name our assembly make
-                               // sure all its refs are strong named
-                               foreach (Assembly a in ctx.GlobalRootNamespace.Assemblies) {
-                                       AssemblyName ref_name = a.GetName ();
-                                       byte [] b = ref_name.GetPublicKeyToken ();
-                                       if (b == null || b.Length == 0) {
-                                               ctx.Report.Error (1577, "Assembly generation failed " +
-                                                               "-- Referenced assembly '" +
-                                                               ref_name.Name +
-                                                               "' does not have a strong name.");
-                                               //Environment.Exit (1);
-                                       }
-                               }
-                       }
-                       
-                       current_domain = AppDomain.CurrentDomain;
-
-                       try {
-                               Assembly.Builder = current_domain.DefineDynamicAssembly (an,
-                                       AssemblyBuilderAccess.RunAndSave, Dirname (name));
-                       }
-                       catch (ArgumentException) {
-                               // specified key may not be exportable outside it's container
-                               if (RootContext.StrongNameKeyContainer != null) {
-                                       ctx.Report.Error (1548, "Could not access the key inside the container `" +
-                                               RootContext.StrongNameKeyContainer + "'.");
-                                       Environment.Exit (1);
-                               }
-                               throw;
-                       }
-                       catch (CryptographicException) {
-                               if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
-                                       ctx.Report.Error (1548, "Could not use the specified key to strongname the assembly.");
-                                       Environment.Exit (1);
-                               }
-                               return false;
-                       }
-
-                       // Get the complete AssemblyName from the builder
-                       // (We need to get the public key and token)
-                       Assembly.Name = Assembly.Builder.GetName ();
-
-                       //
-                       // Pass a path-less name to DefineDynamicModule.  Wonder how
-                       // this copes with output in different directories then.
-                       // FIXME: figure out how this copes with --output /tmp/blah
-                       //
-                       // If the third argument is true, the ModuleBuilder will dynamically
-                       // load the default symbol writer.
-                       //
-                       try {
-                               RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (
-                                       Basename (name), Basename (output), want_debugging_support);
-
-#if !MS_COMPATIBLE
-                               // TODO: We should use SymbolWriter from DefineDynamicModule
-                               if (want_debugging_support && !SymbolWriter.Initialize (RootContext.ToplevelTypes.Builder, output)) {
-                                       ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
-                                               "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll)");
-                                       return false;
-                               }
 #endif
-                       } catch (ExecutionEngineException e) {
-                               ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
-                                       e.Message);
-                               return false;
-                       }
-
-                       return true;
-               }
-
-               public static void Save (string name, Report Report)
-               {
-                       PortableExecutableKinds pekind;
-                       ImageFileMachine machine;
-
-                       switch (RootContext.Platform) {
-                       case Platform.X86:
-                               pekind = PortableExecutableKinds.Required32Bit | PortableExecutableKinds.ILOnly;
-                               machine = ImageFileMachine.I386;
-                               break;
-                       case Platform.X64:
-                               pekind = PortableExecutableKinds.ILOnly;
-                               machine = ImageFileMachine.AMD64;
-                               break;
-                       case Platform.IA64:
-                               pekind = PortableExecutableKinds.ILOnly;
-                               machine = ImageFileMachine.IA64;
-                               break;
-                       case Platform.AnyCPU:
-                       default:
-                               pekind = PortableExecutableKinds.ILOnly;
-                               machine = ImageFileMachine.I386;
-                               break;
-                       }
-                       try {
-                               Assembly.Builder.Save (Basename (name), pekind, machine);
-                       }
-                       catch (COMException) {
-                               if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
-                                       throw;
-
-                               // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies 
-                               Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
-                                       RootContext.StrongNameKeyFile +
-                                       "', Use MCS with the Mono runtime or CSC to compile this assembly.");
-                       }
-                       catch (System.IO.IOException io) {
-                               Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
-                               return;
-                       }
-                       catch (System.UnauthorizedAccessException ua) {
-                               Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
-                               return;
-                       }
-                       catch (System.NotImplementedException nie) {
-                               Report.RuntimeMissingSupport (Location.Null, nie.Message);
-                               return;
-                       }
-               }
-       }
 
+namespace Mono.CSharp
+{
        /// <summary>
        ///   An Emit Context is created for each body of code (from methods,
        ///   properties bodies, indexer bodies or constructor bodies)
@@ -221,13 +31,13 @@ namespace Mono.CSharp {
        public class EmitContext : BuilderContext
        {
                // TODO: Has to be private
-               public ILGenerator ig;
+               public readonly ILGenerator ig;
 
                /// <summary>
                ///   The value that is allowed to be returned or NULL if there is no
                ///   return type.
                /// </summary>
-               TypeSpec return_type;
+               readonly TypeSpec return_type;
 
                /// <summary>
                ///   Keeps track of the Type to LocalBuilder temporary storage created
@@ -273,37 +83,47 @@ namespace Mono.CSharp {
                /// </summary>
                public AnonymousExpression CurrentAnonymousMethod;
                
-               public readonly IMemberContext MemberContext;
+               readonly IMemberContext member_context;
 
                DynamicSiteClass dynamic_site_container;
 
                public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
                {
-                       this.MemberContext = rc;
+                       this.member_context = rc;
                        this.ig = ig;
 
                        this.return_type = return_type;
+
+#if STATIC
+                       ig.__CleverExceptionBlockAssistance ();
+#endif
                }
 
                #region Properties
 
+               public BuiltinTypes BuiltinTypes {
+                       get {
+                               return MemberContext.Module.Compiler.BuiltinTypes;
+                       }
+               }
+
                public TypeSpec CurrentType {
-                       get { return MemberContext.CurrentType; }
+                       get { return member_context.CurrentType; }
                }
 
                public TypeParameter[] CurrentTypeParameters {
-                       get { return MemberContext.CurrentTypeParameters; }
+                       get { return member_context.CurrentTypeParameters; }
                }
 
                public MemberCore CurrentTypeDefinition {
-                       get { return MemberContext.CurrentMemberDefinition; }
+                       get { return member_context.CurrentMemberDefinition; }
                }
 
                public bool IsStatic {
-                       get { return MemberContext.IsStatic; }
+                       get { return member_context.IsStatic; }
                }
 
-               bool IsAnonymousStoreyMutateRequired {
+               public bool IsAnonymousStoreyMutateRequired {
                        get {
                                return CurrentAnonymousMethod != null &&
                                        CurrentAnonymousMethod.Storey != null &&
@@ -311,9 +131,24 @@ namespace Mono.CSharp {
                        }
                }
 
-               // Has to be used for emitter errors only
+               public IMemberContext MemberContext {
+                       get {
+                               return member_context;
+                       }
+               }
+
+               public ModuleContainer Module {
+                       get {
+                               return member_context.Module;
+                       }
+               }
+
+               // Has to be used for specific emitter errors only any
+               // possible resolver errors have to be reported during Resolve
                public Report Report {
-                       get { return MemberContext.Compiler.Report; }
+                       get {
+                               return member_context.Module.Compiler.Report;
+                       }
                }
 
                public TypeSpec ReturnType {
@@ -321,7 +156,7 @@ namespace Mono.CSharp {
                                return return_type;
                        }
                }
-#endregion
+               #endregion
 
                /// <summary>
                ///   This is called immediately before emitting an IL opcode to tell the symbol
@@ -357,7 +192,6 @@ namespace Mono.CSharp {
 
                public void BeginScope ()
                {
-                       ig.BeginScope();
                        SymbolWriter.OpenScope(ig);
                }
 
@@ -368,24 +202,27 @@ namespace Mono.CSharp {
 
                public void EndScope ()
                {
-                       ig.EndScope();
                        SymbolWriter.CloseScope(ig);
                }
 
                //
                // Creates a nested container in this context for all dynamic compiler generated stuff
                //
-               public DynamicSiteClass CreateDynamicSite ()
+               internal DynamicSiteClass CreateDynamicSite ()
                {
                        if (dynamic_site_container == null) {
-                               var mc = MemberContext.CurrentMemberDefinition as MemberBase;
+                               var mc = member_context.CurrentMemberDefinition as MemberBase;
                                dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, CurrentTypeParameters);
 
-                               RootContext.ToplevelTypes.AddCompilerGeneratedClass (dynamic_site_container);
+                               CurrentTypeDefinition.Module.AddCompilerGeneratedClass (dynamic_site_container);
                                dynamic_site_container.CreateType ();
                                dynamic_site_container.DefineType ();
                                dynamic_site_container.ResolveTypeParameters ();
                                dynamic_site_container.Define ();
+
+                               var inflator = new TypeParameterInflator (Module, CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes);
+                               var inflated = dynamic_site_container.CurrentType.InflateMember (inflator);
+                               CurrentType.MemberCache.AddMember (inflated);
                        }
 
                        return dynamic_site_container;
@@ -487,13 +324,7 @@ namespace Mono.CSharp {
                        ig.Emit (opcode, method);
                }
 
-               // TODO: REMOVE breaks mutator
-               public void Emit (OpCode opcode, FieldBuilder field)
-               {
-                       ig.Emit (opcode, field);
-               }
-
-               public void Emit (OpCode opcode, MethodSpec method, Type[] vargs)
+               public void Emit (OpCode opcode, MethodSpec method, MetaType[] vargs)
                {
                        // TODO MemberCache: This should mutate too
                        ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
@@ -540,40 +371,60 @@ namespace Mono.CSharp {
                        }
 
                        var type = ac.Element;
-                       if (TypeManager.IsEnumType (type))
+                       if (type.Kind == MemberKind.Enum)
                                type = EnumSpec.GetUnderlyingType (type);
 
-                       if (type == TypeManager.byte_type || type == TypeManager.bool_type)
+                       switch (type.BuiltinType) {
+                       case BuiltinTypeSpec.Type.Byte:
+                       case BuiltinTypeSpec.Type.Bool:
                                Emit (OpCodes.Ldelem_U1);
-                       else if (type == TypeManager.sbyte_type)
+                               return;
+                       case BuiltinTypeSpec.Type.SByte:
                                Emit (OpCodes.Ldelem_I1);
-                       else if (type == TypeManager.short_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Short:
                                Emit (OpCodes.Ldelem_I2);
-                       else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
+                               return;
+                       case BuiltinTypeSpec.Type.UShort:
+                       case BuiltinTypeSpec.Type.Char:
                                Emit (OpCodes.Ldelem_U2);
-                       else if (type == TypeManager.int32_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Int:
                                Emit (OpCodes.Ldelem_I4);
-                       else if (type == TypeManager.uint32_type)
+                               return;
+                       case BuiltinTypeSpec.Type.UInt:
                                Emit (OpCodes.Ldelem_U4);
-                       else if (type == TypeManager.uint64_type)
-                               Emit (OpCodes.Ldelem_I8);
-                       else if (type == TypeManager.int64_type)
+                               return;
+                       case BuiltinTypeSpec.Type.ULong:
+                       case BuiltinTypeSpec.Type.Long:
                                Emit (OpCodes.Ldelem_I8);
-                       else if (type == TypeManager.float_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Float:
                                Emit (OpCodes.Ldelem_R4);
-                       else if (type == TypeManager.double_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Double:
                                Emit (OpCodes.Ldelem_R8);
-                       else if (type == TypeManager.intptr_type)
+                               return;
+                       case BuiltinTypeSpec.Type.IntPtr:
                                Emit (OpCodes.Ldelem_I);
-                       else if (TypeManager.IsStruct (type)) {
+                               return;
+                       }
+
+                       switch (type.Kind) {
+                       case MemberKind.Struct:
                                Emit (OpCodes.Ldelema, type);
                                Emit (OpCodes.Ldobj, type);
-                       } else if (type.IsGenericParameter) {
+                               break;
+                       case MemberKind.TypeParameter:
                                Emit (OpCodes.Ldelem, type);
-                       } else if (type.IsPointer)
+                               break;
+                       case MemberKind.PointerType:
                                Emit (OpCodes.Ldelem_I);
-                       else
+                               break;
+                       default:
                                Emit (OpCodes.Ldelem_Ref);
+                               break;
+                       }
                }
 
                //
@@ -591,31 +442,50 @@ namespace Mono.CSharp {
 
                        var type = ac.Element;
 
-                       if (type.IsEnum)
+                       if (type.Kind == MemberKind.Enum)
                                type = EnumSpec.GetUnderlyingType (type);
 
-                       if (type == TypeManager.byte_type || type == TypeManager.sbyte_type || type == TypeManager.bool_type)
+                       switch (type.BuiltinType) {
+                       case BuiltinTypeSpec.Type.Byte:
+                       case BuiltinTypeSpec.Type.SByte:
+                       case BuiltinTypeSpec.Type.Bool:
                                Emit (OpCodes.Stelem_I1);
-                       else if (type == TypeManager.short_type || type == TypeManager.ushort_type || type == TypeManager.char_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Short:
+                       case BuiltinTypeSpec.Type.UShort:
+                       case BuiltinTypeSpec.Type.Char:
                                Emit (OpCodes.Stelem_I2);
-                       else if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Int:
+                       case BuiltinTypeSpec.Type.UInt:
                                Emit (OpCodes.Stelem_I4);
-                       else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Long:
+                       case BuiltinTypeSpec.Type.ULong:
                                Emit (OpCodes.Stelem_I8);
-                       else if (type == TypeManager.float_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Float:
                                Emit (OpCodes.Stelem_R4);
-                       else if (type == TypeManager.double_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Double:
                                Emit (OpCodes.Stelem_R8);
-                       else if (type == TypeManager.intptr_type)
-                               Emit (OpCodes.Stobj, type);
-                       else if (TypeManager.IsStruct (type))
+                               return;
+                       }
+
+                       switch (type.Kind) {
+                       case MemberKind.Struct:
                                Emit (OpCodes.Stobj, type);
-                       else if (type.IsGenericParameter)
+                               break;
+                       case MemberKind.TypeParameter:
                                Emit (OpCodes.Stelem, type);
-                       else if (type.IsPointer)
+                               break;
+                       case MemberKind.PointerType:
                                Emit (OpCodes.Stelem_I);
-                       else
+                               break;
+                       default:
                                Emit (OpCodes.Stelem_Ref);
+                               break;
+                       }
                }
 
                public void EmitInt (int i)
@@ -690,45 +560,59 @@ namespace Mono.CSharp {
                //
                // Load the object from the pointer.  
                //
-               public void EmitLoadFromPtr (TypeSpec t)
+               public void EmitLoadFromPtr (TypeSpec type)
                {
-                       if (t == TypeManager.int32_type)
+                       if (type.Kind == MemberKind.Enum)
+                               type = EnumSpec.GetUnderlyingType (type);
+
+                       switch (type.BuiltinType) {
+                       case BuiltinTypeSpec.Type.Int:
                                ig.Emit (OpCodes.Ldind_I4);
-                       else if (t == TypeManager.uint32_type)
+                               return;
+                       case BuiltinTypeSpec.Type.UInt:
                                ig.Emit (OpCodes.Ldind_U4);
-                       else if (t == TypeManager.short_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Short:
                                ig.Emit (OpCodes.Ldind_I2);
-                       else if (t == TypeManager.ushort_type)
-                               ig.Emit (OpCodes.Ldind_U2);
-                       else if (t == TypeManager.char_type)
+                               return;
+                       case BuiltinTypeSpec.Type.UShort:
+                       case BuiltinTypeSpec.Type.Char:
                                ig.Emit (OpCodes.Ldind_U2);
-                       else if (t == TypeManager.byte_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Byte:
                                ig.Emit (OpCodes.Ldind_U1);
-                       else if (t == TypeManager.sbyte_type)
+                               return;
+                       case BuiltinTypeSpec.Type.SByte:
+                       case BuiltinTypeSpec.Type.Bool:
                                ig.Emit (OpCodes.Ldind_I1);
-                       else if (t == TypeManager.uint64_type)
-                               ig.Emit (OpCodes.Ldind_I8);
-                       else if (t == TypeManager.int64_type)
+                               return;
+                       case BuiltinTypeSpec.Type.ULong:
+                       case BuiltinTypeSpec.Type.Long:
                                ig.Emit (OpCodes.Ldind_I8);
-                       else if (t == TypeManager.float_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Float:
                                ig.Emit (OpCodes.Ldind_R4);
-                       else if (t == TypeManager.double_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Double:
                                ig.Emit (OpCodes.Ldind_R8);
-                       else if (t == TypeManager.bool_type)
-                               ig.Emit (OpCodes.Ldind_I1);
-                       else if (t == TypeManager.intptr_type)
+                               return;
+                       case BuiltinTypeSpec.Type.IntPtr:
                                ig.Emit (OpCodes.Ldind_I);
-                       else if (t.IsEnum) {
-                               if (t == TypeManager.enum_type)
-                                       ig.Emit (OpCodes.Ldind_Ref);
-                               else
-                                       EmitLoadFromPtr (EnumSpec.GetUnderlyingType (t));
-                       } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
-                               Emit (OpCodes.Ldobj, t);
-                       else if (t.IsPointer)
+                               return;
+                       }
+
+                       switch (type.Kind) {
+                       case MemberKind.Struct:
+                       case MemberKind.TypeParameter:
+                               Emit (OpCodes.Ldobj, type);
+                               break;
+                       case MemberKind.PointerType:
                                ig.Emit (OpCodes.Ldind_I);
-                       else
+                               break;
+                       default:
                                ig.Emit (OpCodes.Ldind_Ref);
+                               break;
+                       }
                }
 
                //
@@ -739,24 +623,38 @@ namespace Mono.CSharp {
                        if (type.IsEnum)
                                type = EnumSpec.GetUnderlyingType (type);
 
-                       if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
+                       switch (type.BuiltinType) {
+                       case BuiltinTypeSpec.Type.Int:
+                       case BuiltinTypeSpec.Type.UInt:
                                ig.Emit (OpCodes.Stind_I4);
-                       else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Long:
+                       case BuiltinTypeSpec.Type.ULong:
                                ig.Emit (OpCodes.Stind_I8);
-                       else if (type == TypeManager.char_type || type == TypeManager.short_type ||
-                                type == TypeManager.ushort_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Char:
+                       case BuiltinTypeSpec.Type.Short:
+                       case BuiltinTypeSpec.Type.UShort:
                                ig.Emit (OpCodes.Stind_I2);
-                       else if (type == TypeManager.float_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Float:
                                ig.Emit (OpCodes.Stind_R4);
-                       else if (type == TypeManager.double_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Double:
                                ig.Emit (OpCodes.Stind_R8);
-                       else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
-                                type == TypeManager.bool_type)
+                               return;
+                       case BuiltinTypeSpec.Type.Byte:
+                       case BuiltinTypeSpec.Type.SByte:
+                       case BuiltinTypeSpec.Type.Bool:
                                ig.Emit (OpCodes.Stind_I1);
-                       else if (type == TypeManager.intptr_type)
+                               return;
+                       case BuiltinTypeSpec.Type.IntPtr:
                                ig.Emit (OpCodes.Stind_I);
-                       else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
-                               ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
+                               return;
+                       }
+
+                       if (type.IsStruct || TypeManager.IsGenericParameter (type))
+                               Emit (OpCodes.Stobj, type);
                        else
                                ig.Emit (OpCodes.Stind_Ref);
                }