public Enum(TypeContainer parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs) : base(parent, name, attrs, MemberKind.Enum) { underlying_type_expr = type; var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE; ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report); spec = new EnumSpec (null, this, null, null, ModFlags); }
public Enum(NamespaceEntry ns, DeclSpace parent, TypeExpr type, Modifiers mod_flags, MemberName name, Attributes attrs) : base(ns, parent, name, attrs, MemberKind.Enum) { this.base_type = type; var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE; ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report); spec = new EnumSpec (null, this, null, null, ModFlags); }
TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType) { TypeSpec spec; if (import_cache.TryGetValue (type, out spec)) { if (spec.BuiltinType == BuiltinTypeSpec.Type.Object) { if (dtype.IsDynamicObject (this)) return module.Compiler.BuiltinTypes.Dynamic; return spec; } if (!spec.IsGeneric || type.IsGenericTypeDefinition) return spec; if (!dtype.HasDynamicAttribute (this)) return spec; // We've found same object in the cache but this one has a dynamic custom attribute // and it's most likely dynamic version of same type IFoo<object> agains IFoo<dynamic> // Do type resolve process again in that case // TODO: Handle cases where they still unify } if (IsMissingType (type)) { spec = new TypeSpec (MemberKind.MissingType, declaringType, new ImportedTypeDefinition (type, this), type, Modifiers.PUBLIC); spec.MemberCache = MemberCache.Empty; import_cache.Add (type, spec); return spec; } if (type.IsGenericType && !type.IsGenericTypeDefinition) { var type_def = type.GetGenericTypeDefinition (); // Generic type definition can also be forwarded if (compiled_types.TryGetValue (type_def, out spec)) return spec; var targs = CreateGenericArguments (0, type.GetGenericArguments (), dtype); if (declaringType == null) { // Simple case, no nesting spec = CreateType (type_def, null, new DynamicTypeReader (), canImportBaseType); spec = spec.MakeGenericType (module, targs); } else { // // Nested type case, converting .NET types like // A`1.B`1.C`1<int, long, string> to typespec like // A<int>.B<long>.C<string> // var nested_hierarchy = new List<TypeSpec> (); while (declaringType.IsNested) { nested_hierarchy.Add (declaringType); declaringType = declaringType.DeclaringType; } int targs_pos = 0; if (declaringType.Arity > 0) { spec = declaringType.MakeGenericType (module, targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ()); targs_pos = spec.Arity; } else { spec = declaringType; } for (int i = nested_hierarchy.Count; i != 0; --i) { var t = nested_hierarchy [i - 1]; spec = MemberCache.FindNestedType (spec, t.Name, t.Arity); if (t.Arity > 0) { spec = spec.MakeGenericType (module, targs.Skip (targs_pos).Take (spec.Arity).ToArray ()); targs_pos += t.Arity; } } string name = type.Name; int index = name.IndexOf ('`'); if (index > 0) name = name.Substring (0, index); spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos); if (spec == null) return null; if (spec.Arity > 0) { spec = spec.MakeGenericType (module, targs.Skip (targs_pos).ToArray ()); } } // Don't add generic type with dynamic arguments, they can interfere with same type // using object type arguments if (!spec.HasDynamicElement) { // Add to reading cache to speed up reading if (!import_cache.ContainsKey (type)) import_cache.Add (type, spec); } return spec; } Modifiers mod; MemberKind kind; var ma = type.Attributes; switch (ma & TypeAttributes.VisibilityMask) { case TypeAttributes.Public: case TypeAttributes.NestedPublic: mod = Modifiers.PUBLIC; break; case TypeAttributes.NestedPrivate: mod = Modifiers.PRIVATE; break; case TypeAttributes.NestedFamily: mod = Modifiers.PROTECTED; break; case TypeAttributes.NestedFamORAssem: mod = Modifiers.PROTECTED | Modifiers.INTERNAL; break; default: mod = Modifiers.INTERNAL; break; } if ((ma & TypeAttributes.Interface) != 0) { kind = MemberKind.Interface; } else if (type.IsGenericParameter) { kind = MemberKind.TypeParameter; } else { var base_type = type.BaseType; if (base_type == null || (ma & TypeAttributes.Abstract) != 0) { kind = MemberKind.Class; } else { kind = DetermineKindFromBaseType (base_type); if (kind == MemberKind.Struct || kind == MemberKind.Delegate) { mod |= Modifiers.SEALED; } } if (kind == MemberKind.Class) { if ((ma & TypeAttributes.Sealed) != 0) { mod |= Modifiers.SEALED; if ((ma & TypeAttributes.Abstract) != 0) mod |= Modifiers.STATIC; } else if ((ma & TypeAttributes.Abstract) != 0) { mod |= Modifiers.ABSTRACT; } } } var definition = new ImportedTypeDefinition (type, this); TypeSpec pt; if (kind == MemberKind.Enum) { const BindingFlags underlying_member = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var type_members = type.GetFields (underlying_member); foreach (var type_member in type_members) { spec = new EnumSpec (declaringType, definition, CreateType (type_member.FieldType), type, mod); break; } if (spec == null) kind = MemberKind.Class; } else if (kind == MemberKind.TypeParameter) { spec = CreateTypeParameter (type, declaringType); } else if (type.IsGenericTypeDefinition) { definition.TypeParameters = CreateGenericParameters (type, declaringType); } else if (compiled_types.TryGetValue (type, out pt)) { // // Same type was found in inside compiled types. It's // either build-in type or forward referenced typed // which point into just compiled assembly. // spec = pt; BuiltinTypeSpec bts = pt as BuiltinTypeSpec; if (bts != null) bts.SetDefinition (definition, type, mod); } if (spec == null) spec = new TypeSpec (kind, declaringType, definition, type, mod); import_cache.Add (type, spec); if (kind == MemberKind.TypeParameter) { if (canImportBaseType) ImportTypeParameterTypeConstraints ((TypeParameterSpec) spec, type); return spec; } // // Two stage setup as the base type can be inflated declaring type or // another nested type inside same declaring type which has not been // loaded, therefore we can import a base type of nested types once // the types have been imported // if (canImportBaseType) ImportTypeBase (spec, type); return spec; }
// // Emits the right opcode to store to an array // public void EmitArrayStore(ArrayContainer ac) { if (ac.Rank > 1) { if (IsAnonymousStoreyMutateRequired) { ac = (ArrayContainer)ac.Mutate(CurrentAnonymousMethod.Storey.Mutator); } ig.Emit(OpCodes.Call, ac.GetSetMethod()); return; } var type = ac.Element; if (type.Kind == MemberKind.Enum) { type = EnumSpec.GetUnderlyingType(type); } switch (type.BuiltinType) { case BuiltinTypeSpec.Type.Byte: case BuiltinTypeSpec.Type.SByte: case BuiltinTypeSpec.Type.Bool: Emit(OpCodes.Stelem_I1); return; case BuiltinTypeSpec.Type.Short: case BuiltinTypeSpec.Type.UShort: case BuiltinTypeSpec.Type.Char: Emit(OpCodes.Stelem_I2); return; case BuiltinTypeSpec.Type.Int: case BuiltinTypeSpec.Type.UInt: Emit(OpCodes.Stelem_I4); return; case BuiltinTypeSpec.Type.Long: case BuiltinTypeSpec.Type.ULong: Emit(OpCodes.Stelem_I8); return; case BuiltinTypeSpec.Type.Float: Emit(OpCodes.Stelem_R4); return; case BuiltinTypeSpec.Type.Double: Emit(OpCodes.Stelem_R8); return; } switch (type.Kind) { case MemberKind.Struct: Emit(OpCodes.Stobj, type); break; case MemberKind.TypeParameter: Emit(OpCodes.Stelem, type); break; case MemberKind.PointerType: Emit(OpCodes.Stelem_I); break; default: Emit(OpCodes.Stelem_Ref); break; } }
// // The stack contains the pointer and the value of type `type' // public void EmitStoreFromPtr(TypeSpec type) { if (type.IsEnum) { type = EnumSpec.GetUnderlyingType(type); } switch (type.BuiltinType) { case BuiltinTypeSpec.Type.Int: case BuiltinTypeSpec.Type.UInt: ig.Emit(OpCodes.Stind_I4); return; case BuiltinTypeSpec.Type.Long: case BuiltinTypeSpec.Type.ULong: ig.Emit(OpCodes.Stind_I8); return; case BuiltinTypeSpec.Type.Char: case BuiltinTypeSpec.Type.Short: case BuiltinTypeSpec.Type.UShort: ig.Emit(OpCodes.Stind_I2); return; case BuiltinTypeSpec.Type.Float: ig.Emit(OpCodes.Stind_R4); return; case BuiltinTypeSpec.Type.Double: ig.Emit(OpCodes.Stind_R8); return; case BuiltinTypeSpec.Type.Byte: case BuiltinTypeSpec.Type.SByte: case BuiltinTypeSpec.Type.Bool: ig.Emit(OpCodes.Stind_I1); return; case BuiltinTypeSpec.Type.IntPtr: ig.Emit(OpCodes.Stind_I); return; } switch (type.Kind) { case MemberKind.Struct: case MemberKind.TypeParameter: if (IsAnonymousStoreyMutateRequired) { type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type); } ig.Emit(OpCodes.Stobj, type.GetMetaInfo()); break; default: ig.Emit(OpCodes.Stind_Ref); break; } }
public TypeSpec CreateType (Type type, TypeSpec declaringType, ICustomAttributeProvider ca, int dynamicCursor, bool canImportBaseType) { TypeSpec spec; if (import_cache.TryGetValue (type, out spec)) { if (ca == null) return spec; if (type == typeof (object)) { if (IsDynamicType (ca, dynamicCursor)) return InternalType.Dynamic; return spec; } if (!spec.IsGeneric) return spec; #if NET_4_0 if (!ca.IsDefined (typeof (DynamicAttribute), false)) #endif return spec; // We've found same object in the cache but this one has a dynamic custom attribute // and it's most likely dynamic version of same type IFoo<object> agains IFoo<dynamic> // Do resolve the type process again in that case } if (type.IsGenericType && !type.IsGenericTypeDefinition) { var type_def = type.GetGenericTypeDefinition (); var targs = CreateGenericArguments (0, type.GetGenericArguments (), ca, dynamicCursor + 1); if (declaringType == null) { // Simple case, no nesting spec = CreateType (type_def, null, null, 0, canImportBaseType); spec = spec.MakeGenericType (targs); } else { // // Nested type case, converting .NET types like // A`1.B`1.C`1<int, long, string> to typespec like // A<int>.B<long>.C<string> // var nested_hierarchy = new List<TypeSpec> (); while (declaringType.IsNested) { nested_hierarchy.Add (declaringType); declaringType = declaringType.DeclaringType; } int targs_pos = 0; if (declaringType.Arity > 0) { spec = declaringType.MakeGenericType (targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ()); targs_pos = spec.Arity; } else { spec = declaringType; } for (int i = nested_hierarchy.Count; i != 0; --i) { var t = nested_hierarchy [i - 1]; spec = MemberCache.FindNestedType (spec, t.Name, t.Arity); if (t.Arity > 0) { spec = spec.MakeGenericType (targs.Skip (targs_pos).Take (spec.Arity).ToArray ()); targs_pos += t.Arity; } } string name = type.Name; int index = name.IndexOf ('`'); if (index > 0) name = name.Substring (0, index); spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos); if (spec.Arity > 0) { spec = spec.MakeGenericType (targs.Skip (targs_pos).ToArray ()); } } // Don't add generic type with dynamic arguments, they can interfere with same type // using object type arguments if (!spec.HasDynamicElement) { // Add to reading cache to speed up reading if (!import_cache.ContainsKey (type)) import_cache.Add (type, spec); } return spec; } Modifiers mod; MemberKind kind; var ma = type.Attributes; switch (ma & TypeAttributes.VisibilityMask) { case TypeAttributes.Public: case TypeAttributes.NestedPublic: mod = Modifiers.PUBLIC; break; case TypeAttributes.NestedPrivate: mod = Modifiers.PRIVATE; break; case TypeAttributes.NestedFamily: mod = Modifiers.PROTECTED; break; case TypeAttributes.NestedFamORAssem: mod = Modifiers.PROTECTED | Modifiers.INTERNAL; break; default: mod = Modifiers.INTERNAL; break; } if ((ma & TypeAttributes.Interface) != 0) { kind = MemberKind.Interface; } else if (type.IsGenericParameter) { kind = MemberKind.TypeParameter; } else if (type.IsClass || type.IsAbstract) { // System.Reflection: System.Enum returns false for IsClass if ((ma & TypeAttributes.Sealed) != 0 && type.IsSubclassOf (typeof (MulticastDelegate))) { kind = MemberKind.Delegate; mod |= Modifiers.SEALED; } else { kind = MemberKind.Class; if ((ma & TypeAttributes.Sealed) != 0) { mod |= Modifiers.SEALED; if ((ma & TypeAttributes.Abstract) != 0) mod |= Modifiers.STATIC; } else if ((ma & TypeAttributes.Abstract) != 0) { mod |= Modifiers.ABSTRACT; } } } else if (type.IsEnum) { kind = MemberKind.Enum; } else { kind = MemberKind.Struct; mod |= Modifiers.SEALED; } var definition = new ImportedTypeDefinition (this, type); PredefinedTypeSpec pt; if (kind == MemberKind.Enum) { const BindingFlags underlying_member = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var type_members = type.GetFields (underlying_member); foreach (var type_member in type_members) { spec = new EnumSpec (declaringType, definition, CreateType (type_member.FieldType), type, mod); break; } if (spec == null) kind = MemberKind.Class; } else if (kind == MemberKind.TypeParameter) { // Return as type_cache was updated return CreateTypeParameter (type, declaringType); } else if (type.IsGenericTypeDefinition) { definition.TypeParameters = CreateGenericParameters (type, declaringType); // Constraints are not loaded on demand and can reference this type if (import_cache.TryGetValue (type, out spec)) return spec; } else if (type_2_predefined.TryGetValue (type, out pt)) { spec = pt; pt.SetDefinition (definition, type); } if (spec == null) spec = new TypeSpec (kind, declaringType, definition, type, mod); import_cache.Add (type, spec); // // Two stage setup as the base type can be inflated declaring type or // another nested type inside same declaring type which has not been // loaded, therefore we can import a base type of nested types once // the types have been imported // if (canImportBaseType) ImportTypeBase (spec, type); return spec; }
// // Emits the right opcode to load from an array // public void EmitArrayLoad(ArrayContainer ac) { if (ac.Rank > 1) { if (IsAnonymousStoreyMutateRequired) { ac = (ArrayContainer)ac.Mutate(CurrentAnonymousMethod.Storey.Mutator); } ig.Emit(OpCodes.Call, ac.GetGetMethod()); return; } var type = ac.Element; if (type.Kind == MemberKind.Enum) { type = EnumSpec.GetUnderlyingType(type); } switch (type.BuiltinType) { case BuiltinTypeSpec.Type.Bool: // // Workaround MSIL limitation. Load bool element as single bit, // bool array can actually store any byte value // ig.Emit(OpCodes.Ldelem_U1); ig.Emit(OpCodes.Ldc_I4_1); ig.Emit(OpCodes.And); break; case BuiltinTypeSpec.Type.Byte: ig.Emit(OpCodes.Ldelem_U1); break; case BuiltinTypeSpec.Type.SByte: ig.Emit(OpCodes.Ldelem_I1); break; case BuiltinTypeSpec.Type.Short: ig.Emit(OpCodes.Ldelem_I2); break; case BuiltinTypeSpec.Type.UShort: case BuiltinTypeSpec.Type.Char: ig.Emit(OpCodes.Ldelem_U2); break; case BuiltinTypeSpec.Type.Int: ig.Emit(OpCodes.Ldelem_I4); break; case BuiltinTypeSpec.Type.UInt: ig.Emit(OpCodes.Ldelem_U4); break; case BuiltinTypeSpec.Type.ULong: case BuiltinTypeSpec.Type.Long: ig.Emit(OpCodes.Ldelem_I8); break; case BuiltinTypeSpec.Type.Float: ig.Emit(OpCodes.Ldelem_R4); break; case BuiltinTypeSpec.Type.Double: ig.Emit(OpCodes.Ldelem_R8); break; case BuiltinTypeSpec.Type.IntPtr: ig.Emit(OpCodes.Ldelem_I); break; default: switch (type.Kind) { case MemberKind.Struct: if (IsAnonymousStoreyMutateRequired) { type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type); } ig.Emit(OpCodes.Ldelema, type.GetMetaInfo()); ig.Emit(OpCodes.Ldobj, type.GetMetaInfo()); break; case MemberKind.TypeParameter: if (IsAnonymousStoreyMutateRequired) { type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type); } ig.Emit(OpCodes.Ldelem, type.GetMetaInfo()); break; case MemberKind.PointerType: ig.Emit(OpCodes.Ldelem_I); break; default: ig.Emit(OpCodes.Ldelem_Ref); break; } break; } }
// // Emits the right opcode to load from an array // public void EmitArrayLoad(ArrayContainer ac) { if (ac.Rank > 1) { if (IsAnonymousStoreyMutateRequired) { ac = (ArrayContainer)ac.Mutate(CurrentAnonymousMethod.Storey.Mutator); } ig.Emit(OpCodes.Call, ac.GetGetMethod()); return; } var type = ac.Element; if (type.Kind == MemberKind.Enum) { type = EnumSpec.GetUnderlyingType(type); } switch (type.BuiltinType) { case BuiltinTypeSpec.Type.Bool: // // bool array can actually store any byte value in underlying byte slot // and C# spec does not specify any normalization rule, except the result // is undefined // case BuiltinTypeSpec.Type.Byte: ig.Emit(OpCodes.Ldelem_U1); break; case BuiltinTypeSpec.Type.SByte: ig.Emit(OpCodes.Ldelem_I1); break; case BuiltinTypeSpec.Type.Short: ig.Emit(OpCodes.Ldelem_I2); break; case BuiltinTypeSpec.Type.UShort: case BuiltinTypeSpec.Type.Char: ig.Emit(OpCodes.Ldelem_U2); break; case BuiltinTypeSpec.Type.Int: ig.Emit(OpCodes.Ldelem_I4); break; case BuiltinTypeSpec.Type.UInt: ig.Emit(OpCodes.Ldelem_U4); break; case BuiltinTypeSpec.Type.ULong: case BuiltinTypeSpec.Type.Long: ig.Emit(OpCodes.Ldelem_I8); break; case BuiltinTypeSpec.Type.Float: ig.Emit(OpCodes.Ldelem_R4); break; case BuiltinTypeSpec.Type.Double: ig.Emit(OpCodes.Ldelem_R8); break; case BuiltinTypeSpec.Type.IntPtr: ig.Emit(OpCodes.Ldelem_I); break; default: switch (type.Kind) { case MemberKind.Struct: if (IsAnonymousStoreyMutateRequired) { type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type); } ig.Emit(OpCodes.Ldelema, type.GetMetaInfo()); ig.Emit(OpCodes.Ldobj, type.GetMetaInfo()); break; case MemberKind.TypeParameter: if (IsAnonymousStoreyMutateRequired) { type = CurrentAnonymousMethod.Storey.Mutator.Mutate(type); } ig.Emit(OpCodes.Ldelem, type.GetMetaInfo()); break; case MemberKind.PointerType: ig.Emit(OpCodes.Ldelem_I); break; default: ig.Emit(OpCodes.Ldelem_Ref); break; } break; } }
// // Load the object from the pointer. // public void EmitLoadFromPtr(TypeSpec type) { if (type.Kind == MemberKind.Enum) { type = EnumSpec.GetUnderlyingType(type); } switch (type.BuiltinType) { case BuiltinTypeSpec.Type.Int: ig.Emit(OpCodes.Ldind_I4); return; case BuiltinTypeSpec.Type.UInt: ig.Emit(OpCodes.Ldind_U4); return; case BuiltinTypeSpec.Type.Short: ig.Emit(OpCodes.Ldind_I2); return; case BuiltinTypeSpec.Type.UShort: case BuiltinTypeSpec.Type.Char: ig.Emit(OpCodes.Ldind_U2); return; case BuiltinTypeSpec.Type.Byte: ig.Emit(OpCodes.Ldind_U1); return; case BuiltinTypeSpec.Type.SByte: case BuiltinTypeSpec.Type.Bool: ig.Emit(OpCodes.Ldind_I1); return; case BuiltinTypeSpec.Type.ULong: case BuiltinTypeSpec.Type.Long: ig.Emit(OpCodes.Ldind_I8); return; case BuiltinTypeSpec.Type.Float: ig.Emit(OpCodes.Ldind_R4); return; case BuiltinTypeSpec.Type.Double: ig.Emit(OpCodes.Ldind_R8); return; case BuiltinTypeSpec.Type.IntPtr: ig.Emit(OpCodes.Ldind_I); return; } switch (type.Kind) { case MemberKind.Struct: case MemberKind.TypeParameter: Emit(OpCodes.Ldobj, type); break; case MemberKind.PointerType: ig.Emit(OpCodes.Ldind_I); break; default: ig.Emit(OpCodes.Ldind_Ref); break; } }