2 // module.cs: keeps a tree representation of the generated code
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@gmail.com)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
11 // Copyright 2011 Xamarin Inc
15 using System.Collections.Generic;
16 using System.Runtime.InteropServices;
17 using Mono.CompilerServices.SymbolWriter;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
31 // Module (top-level type) container
33 public sealed class ModuleContainer : TypeContainer
37 // Compiler generated container for static data
39 sealed class StaticDataContainer : CompilerGeneratedContainer
41 readonly Dictionary<int, Struct> size_types;
44 public StaticDataContainer (ModuleContainer module)
45 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null),
46 Modifiers.STATIC | Modifiers.INTERNAL)
48 size_types = new Dictionary<int, Struct> ();
51 public override void CloseContainer ()
53 base.CloseContainer ();
55 foreach (var entry in size_types) {
56 entry.Value.CloseContainer ();
60 public FieldSpec DefineInitializedData (byte[] data, Location loc)
63 if (!size_types.TryGetValue (data.Length, out size_type)) {
65 // Build common type for this data length. We cannot use
66 // DefineInitializedData because it creates public type,
67 // and its name is not unique among modules
69 size_type = new Struct (this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
70 size_type.CreateContainer ();
71 size_type.DefineContainer ();
73 size_types.Add (data.Length, size_type);
75 // It has to work even if StructLayoutAttribute does not exist
76 size_type.TypeBuilder.__SetLayout (1, data.Length);
79 var name = "$field-" + fields.ToString ("X");
81 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
82 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
83 fbuilder.__SetDataAndRVA (data);
85 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
89 StaticDataContainer static_data;
92 // Makes const data field inside internal type container
94 public FieldSpec MakeStaticData (byte[] data, Location loc)
96 if (static_data == null) {
97 static_data = new StaticDataContainer (this);
98 static_data.CreateContainer ();
99 static_data.DefineContainer ();
101 AddCompilerGeneratedClass (static_data);
104 return static_data.DefineInitializedData (data, loc);
108 public sealed class PatternMatchingHelper : CompilerGeneratedContainer
110 public PatternMatchingHelper (ModuleContainer module)
111 : base (module, new MemberName ("<PatternMatchingHelper>", Location.Null),
112 Modifiers.STATIC | Modifiers.INTERNAL | Modifiers.DEBUGGER_HIDDEN)
116 public Method NumberMatcher { get; private set; }
118 protected override bool DoDefineMembers ()
120 if (!base.DoDefineMembers ())
123 NumberMatcher = GenerateNumberMatcher ();
127 Method GenerateNumberMatcher ()
130 var parameters = ParametersCompiled.CreateFullyResolved (
132 new Parameter (new TypeExpression (Compiler.BuiltinTypes.Object, loc), "obj", 0, null, loc),
133 new Parameter (new TypeExpression (Compiler.BuiltinTypes.Object, loc), "value", 0, null, loc),
134 new Parameter (new TypeExpression (Compiler.BuiltinTypes.Bool, loc), "enumType", 0, null, loc),
137 Compiler.BuiltinTypes.Object,
138 Compiler.BuiltinTypes.Object,
139 Compiler.BuiltinTypes.Bool
142 var m = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Bool, loc),
143 Modifiers.PUBLIC | Modifiers.STATIC | Modifiers.DEBUGGER_HIDDEN, new MemberName ("NumberMatcher", loc),
146 parameters [0].Resolve (m, 0);
147 parameters [1].Resolve (m, 1);
148 parameters [2].Resolve (m, 2);
150 ToplevelBlock top_block = new ToplevelBlock (Compiler, parameters, loc);
155 // return Equals (obj, value);
157 var equals_args = new Arguments (2);
158 equals_args.Add (new Argument (top_block.GetParameterReference (0, loc)));
159 equals_args.Add (new Argument (top_block.GetParameterReference (1, loc)));
161 var if_type = new If (
162 top_block.GetParameterReference (2, loc),
163 new Return (new Invocation (new SimpleName ("Equals", loc), equals_args), loc),
166 top_block.AddStatement (if_type);
169 // if (obj is Enum || obj == null)
173 var if_enum = new If (
174 new Binary (Binary.Operator.LogicalOr,
175 new Is (top_block.GetParameterReference (0, loc), new TypeExpression (Compiler.BuiltinTypes.Enum, loc), loc),
176 new Binary (Binary.Operator.Equality, top_block.GetParameterReference (0, loc), new NullLiteral (loc))),
177 new Return (new BoolLiteral (Compiler.BuiltinTypes, false, loc), loc),
180 top_block.AddStatement (if_enum);
183 var system_convert = new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "Convert", loc);
184 var expl_block = new ExplicitBlock (top_block, loc, loc);
187 // var converted = System.Convert.ChangeType (obj, System.Convert.GetTypeCode (value));
189 var lv_converted = LocalVariable.CreateCompilerGenerated (Compiler.BuiltinTypes.Object, top_block, loc);
191 var arguments_gettypecode = new Arguments (1);
192 arguments_gettypecode.Add (new Argument (top_block.GetParameterReference (1, loc)));
194 var gettypecode = new Invocation (new MemberAccess (system_convert, "GetTypeCode", loc), arguments_gettypecode);
196 var arguments_changetype = new Arguments (1);
197 arguments_changetype.Add (new Argument (top_block.GetParameterReference (0, loc)));
198 arguments_changetype.Add (new Argument (gettypecode));
200 var changetype = new Invocation (new MemberAccess (system_convert, "ChangeType", loc), arguments_changetype);
202 expl_block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (lv_converted, loc), changetype, loc)));
206 // return converted.Equals (value)
208 var equals_arguments = new Arguments (1);
209 equals_arguments.Add (new Argument (top_block.GetParameterReference (1, loc)));
210 var equals_invocation = new Invocation (new MemberAccess (new LocalVariableReference (lv_converted, loc), "Equals"), equals_arguments);
211 expl_block.AddStatement (new Return (equals_invocation, loc));
213 var catch_block = new ExplicitBlock (top_block, loc, loc);
214 catch_block.AddStatement (new Return (new BoolLiteral (Compiler.BuiltinTypes, false, loc), loc));
215 top_block.AddStatement (new TryCatch (expl_block, new List<Catch> () {
216 new Catch (catch_block, loc)
227 PatternMatchingHelper pmh;
229 public PatternMatchingHelper CreatePatterMatchingHelper ()
232 pmh = new PatternMatchingHelper (this);
234 pmh.CreateContainer ();
235 pmh.DefineContainer ();
237 AddCompilerGeneratedClass (pmh);
243 public CharSet? DefaultCharSet;
244 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
246 readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
247 readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
248 readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
249 readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
250 readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
251 readonly Dictionary<TypeSpec, AwaiterDefinition> awaiters;
253 AssemblyDefinition assembly;
254 readonly CompilerContext context;
255 readonly RootNamespace global_ns;
256 readonly Dictionary<string, RootNamespace> alias_ns;
258 ModuleBuilder builder;
260 bool has_extenstion_method;
262 PredefinedAttributes predefined_attributes;
263 PredefinedTypes predefined_types;
264 PredefinedMembers predefined_members;
266 public Binary.PredefinedOperator[] OperatorsBinaryEqualityLifted;
267 public Binary.PredefinedOperator[] OperatorsBinaryLifted;
269 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
271 public ModuleContainer (CompilerContext context)
272 : base (null, MemberName.Null, null, 0)
274 this.context = context;
276 caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
278 containers = new List<TypeContainer> ();
279 anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
280 global_ns = new GlobalRootNamespace ();
281 alias_ns = new Dictionary<string, RootNamespace> ();
282 array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
283 pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
284 reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
285 attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
286 awaiters = new Dictionary<TypeSpec, AwaiterDefinition> ();
291 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
298 // Cache for parameter-less attributes
300 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
306 public override AttributeTargets AttributeTargets {
308 return AttributeTargets.Assembly;
312 public ModuleBuilder Builder {
318 public override CompilerContext Compiler {
324 public int CounterAnonymousTypes { get; set; }
326 public AssemblyDefinition DeclaringAssembly {
332 internal DocumentationBuilder DocumentationBuilder {
336 public override string DocCommentHeader {
338 throw new NotSupportedException ();
342 public Evaluator Evaluator {
346 public bool HasDefaultCharSet {
348 return DefaultCharSet.HasValue;
352 public bool HasExtensionMethod {
354 return has_extenstion_method;
357 has_extenstion_method = value;
361 public bool HasTypesFullyDefined {
366 // Returns module global:: namespace
368 public RootNamespace GlobalRootNamespace {
374 public override ModuleContainer Module {
380 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
382 return pointer_types;
386 internal PredefinedAttributes PredefinedAttributes {
388 return predefined_attributes;
392 internal PredefinedMembers PredefinedMembers {
394 return predefined_members;
398 internal PredefinedTypes PredefinedTypes {
400 return predefined_types;
404 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
406 return reference_types;
410 public override string[] ValidAttributeTargets {
412 return attribute_targets;
418 public override void Accept (StructuralVisitor visitor)
420 visitor.Visit (this);
423 public void AddAnonymousType (AnonymousTypeClass type)
425 List<AnonymousTypeClass> existing;
426 if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
427 if (existing == null) {
428 existing = new List<AnonymousTypeClass> ();
429 anonymous_types.Add (type.Parameters.Count, existing);
435 public void AddAttribute (Attribute attr, IMemberContext context)
437 attr.AttachTo (this, context);
439 if (attributes == null) {
440 attributes = new Attributes (attr);
444 attributes.AddAttribute (attr);
447 public override void AddTypeContainer (TypeContainer tc)
449 AddTypeContainerMember (tc);
452 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
454 if (a.Target == AttributeTargets.Assembly) {
455 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
459 if (a.Type == pa.DefaultCharset) {
460 switch (a.GetCharSetValue ()) {
465 DefaultCharSet = CharSet.Auto;
466 DefaultCharSetType = TypeAttributes.AutoClass;
468 case CharSet.Unicode:
469 DefaultCharSet = CharSet.Unicode;
470 DefaultCharSetType = TypeAttributes.UnicodeClass;
473 Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
474 a.GetSignatureForError ());
477 } else if (a.Type == pa.CLSCompliant) {
478 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
480 Report.Warning (3012, 1, a.Location,
481 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
482 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
483 Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
484 Report.Warning (3017, 1, a.Location,
485 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
490 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
493 public override void CloseContainer ()
495 if (anonymous_types != null) {
496 foreach (var atypes in anonymous_types)
497 foreach (var at in atypes.Value)
498 at.CloseContainer ();
501 base.CloseContainer ();
504 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
506 return builder.DefineType (name, attr, null, typeSize);
510 // Creates alias global namespace
512 public RootNamespace CreateRootNamespace (string alias)
514 if (alias == global_ns.Alias) {
515 RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
520 if (!alias_ns.TryGetValue (alias, out rn)) {
521 rn = new RootNamespace (alias);
522 alias_ns.Add (alias, rn);
528 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
530 this.assembly = assembly;
531 builder = moduleBuilder;
534 public override bool Define ()
538 ExpandBaseInterfaces ();
542 HasTypesFullyDefined = true;
547 public override bool DefineContainer ()
551 return base.DefineContainer ();
554 public void EnableRedefinition ()
559 public override void EmitContainer ()
561 if (OptAttributes != null)
562 OptAttributes.Emit ();
564 if (Compiler.Settings.Unsafe && !assembly.IsSatelliteAssembly) {
565 var pa = PredefinedAttributes.UnverifiableCode;
567 pa.EmitAttribute (builder);
570 foreach (var tc in containers) {
574 base.EmitContainer ();
576 if (Compiler.Report.Errors == 0 && !Compiler.Settings.WriteMetadataOnly)
579 if (anonymous_types != null) {
580 foreach (var atypes in anonymous_types)
581 foreach (var at in atypes.Value)
586 internal override void GenerateDocComment (DocumentationBuilder builder)
588 foreach (var tc in containers)
589 tc.GenerateDocComment (builder);
592 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
594 List<AnonymousTypeClass> candidates;
595 if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
599 foreach (AnonymousTypeClass at in candidates) {
600 for (i = 0; i < parameters.Count; ++i) {
601 if (!parameters [i].Equals (at.Parameters [i]))
605 if (i == parameters.Count)
613 // Return container with awaiter definition. It never returns null
614 // but all container member can be null for easier error reporting
616 public AwaiterDefinition GetAwaiter (TypeSpec type)
618 AwaiterDefinition awaiter;
619 if (awaiters.TryGetValue (type, out awaiter))
622 awaiter = new AwaiterDefinition ();
625 // Predefined: bool IsCompleted { get; }
627 awaiter.IsCompleted = MemberCache.FindMember (type, MemberFilter.Property ("IsCompleted", Compiler.BuiltinTypes.Bool),
628 BindingRestriction.InstanceOnly) as PropertySpec;
631 // Predefined: GetResult ()
633 // The method return type is also result type of await expression
635 awaiter.GetResult = MemberCache.FindMember (type, MemberFilter.Method ("GetResult", 0,
636 ParametersCompiled.EmptyReadOnlyParameters, null),
637 BindingRestriction.InstanceOnly) as MethodSpec;
640 // Predefined: INotifyCompletion.OnCompleted (System.Action)
642 var nc = PredefinedTypes.INotifyCompletion;
643 awaiter.INotifyCompletion = !nc.Define () || type.ImplementsInterface (nc.TypeSpec, false);
645 awaiters.Add (type, awaiter);
649 public override void GetCompletionStartingWith (string prefix, List<string> results)
651 var names = Evaluator.GetVarNames ();
652 results.AddRange (names.Where (l => l.StartsWith (prefix)));
655 public RootNamespace GetRootNamespace (string name)
658 alias_ns.TryGetValue (name, out rn);
662 public override string GetSignatureForError ()
667 public Binary.PredefinedOperator[] GetPredefinedEnumAritmeticOperators (TypeSpec enumType, bool nullable)
670 Binary.Operator mask = 0;
673 underlying = Nullable.NullableInfo.GetEnumUnderlyingType (this, enumType);
674 mask = Binary.Operator.NullableMask;
676 underlying = EnumSpec.GetUnderlyingType (enumType);
679 var operators = new[] {
680 new Binary.PredefinedOperator (enumType, underlying,
681 mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
682 new Binary.PredefinedOperator (underlying, enumType,
683 mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
684 new Binary.PredefinedOperator (enumType, mask | Binary.Operator.SubtractionMask, underlying)
690 public void InitializePredefinedTypes ()
692 predefined_attributes = new PredefinedAttributes (this);
693 predefined_types = new PredefinedTypes (this);
694 predefined_members = new PredefinedMembers (this);
696 OperatorsBinaryEqualityLifted = Binary.CreateEqualityLiftedOperatorsTable (this);
697 OperatorsBinaryLifted = Binary.CreateStandardLiftedOperatorsTable (this);
700 public override bool IsClsComplianceRequired ()
702 return DeclaringAssembly.IsCLSCompliant;
705 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
707 Attribute a = OptAttributes.Search ("assembly", a_type);
714 public void SetDeclaringAssembly (AssemblyDefinition assembly)
716 // TODO: This setter is quite ugly but I have not found a way around it yet
717 this.assembly = assembly;