public abstract class MetadataImporter
{
//
- // Dynamic types reader with additional logic to reconstruct a dynamic
- // type using DynamicAttribute values
+ // Types reader with additional logic to reconstruct extra
+ // type information encoded in custom attributes values
//
- protected struct DynamicTypeReader
+ protected struct AttributesTypeInfoReader
{
static readonly bool[] single_attribute = { true };
- public int Position;
- bool[] flags;
+ public int DynamicPosition;
+ bool[] dynamicFlags;
+
+ public int TuplePosition;
+ string[] tupleNames;
// There is no common type for CustomAttributeData and we cannot
// use ICustomAttributeProvider
//
// A member provider which can be used to get CustomAttributeData
//
- public DynamicTypeReader (object provider)
+ public AttributesTypeInfoReader (object provider)
{
- Position = 0;
- flags = null;
+ DynamicPosition = 0;
+ TuplePosition = 0;
+ dynamicFlags = null;
+ tupleNames = null;
this.provider = provider;
}
if (provider != null)
ReadAttribute ();
- return flags != null && Position < flags.Length && flags[Position];
+ return dynamicFlags != null && DynamicPosition < dynamicFlags.Length && dynamicFlags [DynamicPosition];
}
//
if (provider != null)
ReadAttribute ();
- return flags != null;
+ return dynamicFlags != null;
+ }
+
+ public bool HasNamedTupleAttribute ()
+ {
+ if (provider != null)
+ ReadAttribute ();
+
+ return tupleNames != null;
+ }
+
+ public IList<string> GetNamedTupleElements (int length)
+ {
+ if (TuplePosition == 0 && length == tupleNames.Length)
+ return tupleNames;
+
+ for (int i = TuplePosition; i < length + TuplePosition; ++i) {
+ if (tupleNames [i] != null) {
+ var res = new string [length];
+ Array.Copy (tupleNames, TuplePosition, res, 0, length);
+ return res;
+ }
+ }
+
+ //
+ // Current range can be just padding
+ //
+ return null;
}
IList<CustomAttributeData> GetCustomAttributes ()
if (cad.Count > 0) {
foreach (var ca in cad) {
var dt = ca.Constructor.DeclaringType;
- if (dt.Name != "DynamicAttribute" || dt.Namespace != CompilerServicesNamespace)
+ if (dt.Namespace != CompilerServicesNamespace)
continue;
- if (ca.ConstructorArguments.Count == 0) {
- flags = single_attribute;
- break;
- }
+ switch (dt.Name) {
+ case "DynamicAttribute":
+ if (ca.ConstructorArguments.Count == 0) {
+ dynamicFlags = single_attribute;
+ break;
+ }
+
+ var arg_type = ca.ConstructorArguments [0].ArgumentType;
+
+ if (arg_type.IsArray && MetaType.GetTypeCode (arg_type.GetElementType ()) == TypeCode.Boolean) {
+ var carg = (IList<CustomAttributeTypedArgument>)ca.ConstructorArguments [0].Value;
+ dynamicFlags = new bool [carg.Count];
+ for (int i = 0; i < dynamicFlags.Length; ++i) {
+ if (MetaType.GetTypeCode (carg [i].ArgumentType) == TypeCode.Boolean)
+ dynamicFlags [i] = (bool)carg [i].Value;
+ }
+ }
- var arg_type = ca.ConstructorArguments[0].ArgumentType;
+ break;
+ case "TupleElementNamesAttribute":
+ if (ca.ConstructorArguments.Count != 1)
+ break;
- if (arg_type.IsArray && MetaType.GetTypeCode (arg_type.GetElementType ()) == TypeCode.Boolean) {
- var carg = (IList<CustomAttributeTypedArgument>) ca.ConstructorArguments[0].Value;
- flags = new bool[carg.Count];
- for (int i = 0; i < flags.Length; ++i) {
- if (MetaType.GetTypeCode (carg[i].ArgumentType) == TypeCode.Boolean)
- flags[i] = (bool) carg[i].Value;
+ var tuple_arg_type = ca.ConstructorArguments [0].ArgumentType;
+ if (tuple_arg_type.IsArray && MetaType.GetTypeCode (tuple_arg_type.GetElementType ()) == TypeCode.String) {
+ var carg = (IList<CustomAttributeTypedArgument>)ca.ConstructorArguments [0].Value;
+ tupleNames = new string [carg.Count];
+ for (int i = 0; i < tupleNames.Length; ++i) {
+ if (MetaType.GetTypeCode (carg [i].ArgumentType) == TypeCode.String)
+ tupleNames [i] = (string)carg [i].Value;
+ }
}
break;
compiled_types = new Dictionary<MetaType, TypeSpec> (40, ReferenceEquality<MetaType>.Default);
assembly_2_definition = new Dictionary<Assembly, IAssemblyDefinition> (ReferenceEquality<Assembly>.Default);
IgnorePrivateMembers = true;
+ IgnoreCompilerGeneratedField = true;
}
#region Properties
public bool IgnorePrivateMembers { get; set; }
+ public bool IgnoreCompilerGeneratedField { get; set; }
+
#endregion
public abstract void AddCompiledType (TypeBuilder builder, TypeSpec spec);
break;
default:
// Ignore private fields (even for error reporting) to not require extra dependencies
- if ((IgnorePrivateMembers && !declaringType.IsStruct) ||
- HasAttribute (CustomAttributeData.GetCustomAttributes (fi), "CompilerGeneratedAttribute", CompilerServicesNamespace))
+ if (IgnorePrivateMembers && !declaringType.IsStruct)
+ return null;
+
+ if (IgnoreCompilerGeneratedField && HasAttribute (CustomAttributeData.GetCustomAttributes (fi), "CompilerGeneratedAttribute", CompilerServicesNamespace))
return null;
mod = Modifiers.PRIVATE;
TypeSpec field_type;
try {
- field_type = ImportType (fi.FieldType, new DynamicTypeReader (fi));
+ field_type = ImportType (fi.FieldType, new AttributesTypeInfoReader (fi), declaringType);
//
// Private field has private type which is not fixed buffer
if (add.Modifiers != remove.Modifiers)
throw new NotImplementedException ("Different accessor modifiers " + ei.Name);
- var event_type = ImportType (ei.EventHandlerType, new DynamicTypeReader (ei));
+ var event_type = ImportType (ei.EventHandlerType, new AttributesTypeInfoReader (ei), declaringType);
var definition = new ImportedMemberDefinition (ei, event_type, this);
return new EventSpec (declaringType, definition, event_type, add.Modifiers, add, remove);
}
var type = tparams[pos];
int index = pos - first;
- tspec[index] = (TypeParameterSpec) CreateType (type, new DynamicTypeReader (), false);
+ tspec[index] = (TypeParameterSpec) CreateType (type, new AttributesTypeInfoReader (), false);
}
return tspec;
}
- TypeSpec[] CreateGenericArguments (int first, MetaType[] tparams, DynamicTypeReader dtype)
+ TypeSpec[] CreateGenericArguments (int first, MetaType[] tparams, AttributesTypeInfoReader dtype)
{
- ++dtype.Position;
+ ++dtype.DynamicPosition;
var tspec = new TypeSpec [tparams.Length - first];
for (int pos = first; pos < tparams.Length; ++pos) {
TypeSpec spec;
if (type.HasElementType) {
var element = type.GetElementType ();
- ++dtype.Position;
- spec = ImportType (element, dtype);
+ ++dtype.DynamicPosition;
+ spec = ImportType (element, dtype, null);
if (!type.IsArray) {
throw new NotImplementedException ("Unknown element type " + type.ToString ());
// }
//
if (!IsMissingType (type) && type.IsGenericTypeDefinition) {
- var start_pos = spec.DeclaringType == null ? 0 : spec.DeclaringType.MemberDefinition.TypeParametersCount;
+ var start_pos = GetDeclaringTypesTypeParametersCount (spec);
var targs = CreateGenericArguments (start_pos, type.GetGenericArguments (), dtype);
spec = spec.MakeGenericType (module, targs);
}
if (spec == null)
return null;
- ++dtype.Position;
+ ++dtype.DynamicPosition;
tspec[index] = spec;
}
return tspec;
}
+ static int GetDeclaringTypesTypeParametersCount (TypeSpec spec)
+ {
+ int total = 0;
+ while (spec.DeclaringType != null) {
+ total += spec.DeclaringType.MemberDefinition.TypeParametersCount;
+ spec = spec.DeclaringType;
+ }
+
+ return total;
+ }
+
public MethodSpec CreateMethod (MethodBase mb, TypeSpec declaringType)
{
Modifiers mod = ReadMethodModifiers (mb, declaringType);
kind = MemberKind.Constructor;
returnType = module.Compiler.BuiltinTypes.Void;
} else {
+ var mi = (MethodInfo)mb;
+ returnType = ImportType (mi.ReturnType, new AttributesTypeInfoReader (mi.ReturnParameter), declaringType);
+
//
// Detect operators and destructors
//
kind = MemberKind.Operator;
}
}
- } else if (parameters.IsEmpty && name == Destructor.MetadataName) {
+ } else if (parameters.IsEmpty && name == Destructor.MetadataName && returnType.Kind == MemberKind.Void) {
kind = MemberKind.Destructor;
if (declaringType.BuiltinType == BuiltinTypeSpec.Type.Object) {
mod &= ~Modifiers.OVERRIDE;
}
}
- var mi = (MethodInfo) mb;
- returnType = ImportType (mi.ReturnType, new DynamicTypeReader (mi.ReturnParameter));
-
// Cannot set to OVERRIDE without full hierarchy checks
// this flag indicates that the method could be override
// but further validation is needed
// Strip reference wrapping
//
var el = p.ParameterType.GetElementType ();
- types[i] = ImportType (el, new DynamicTypeReader (p)); // TODO: 1-based positio to be csc compatible
+ types[i] = ImportType (el, new AttributesTypeInfoReader (p), parent); // TODO: 1-based positio to be csc compatible
} else if (i == 0 && method.IsStatic && (parent.Modifiers & Modifiers.METHOD_EXTENSION) != 0 &&
HasAttribute (CustomAttributeData.GetCustomAttributes (method), "ExtensionAttribute", CompilerServicesNamespace)) {
mod = Parameter.Modifier.This;
- types[i] = ImportType (p.ParameterType, new DynamicTypeReader (p));
+ types[i] = ImportType (p.ParameterType, new AttributesTypeInfoReader (p), parent);
} else {
- types[i] = ImportType (p.ParameterType, new DynamicTypeReader (p));
+ types[i] = ImportType (p.ParameterType, new AttributesTypeInfoReader (p), parent);
if (i >= pi.Length - 2 && types[i] is ArrayContainer) {
if (HasAttribute (CustomAttributeData.GetCustomAttributes (p), "ParamArrayAttribute", "System")) {
if (set_param_count == 0) {
set_based_param = ParametersCompiled.EmptyReadOnlyParameters;
} else {
- //
- // Create indexer parameters based on setter method parameters (the last parameter has to be removed)
- //
- var data = new IParameterData[set_param_count];
- var types = new TypeSpec[set_param_count];
- Array.Copy (set.Parameters.FixedParameters, data, set_param_count);
- Array.Copy (set.Parameters.Types, types, set_param_count);
- set_based_param = new ParametersImported (data, types, set.Parameters.HasParams);
+ set_based_param = IndexerSpec.CreateParametersFromSetter (set, set_param_count);
}
mod = set.Modifiers;
public TypeSpec CreateType (MetaType type)
{
- return CreateType (type, new DynamicTypeReader (), true);
+ return CreateType (type, new AttributesTypeInfoReader (), true);
}
public TypeSpec CreateNestedType (MetaType type, TypeSpec declaringType)
{
- return CreateType (type, declaringType, new DynamicTypeReader (type), false);
+ return CreateType (type, declaringType, new AttributesTypeInfoReader (type), false);
}
- TypeSpec CreateType (MetaType type, DynamicTypeReader dtype, bool canImportBaseType)
+ TypeSpec CreateType (MetaType type, AttributesTypeInfoReader dtype, bool canImportBaseType)
{
TypeSpec declaring_type;
if (type.IsNested && !type.IsGenericParameter)
- declaring_type = CreateType (type.DeclaringType, new DynamicTypeReader (type.DeclaringType), true);
+ declaring_type = CreateType (type.DeclaringType, new AttributesTypeInfoReader (type.DeclaringType), true);
else
declaring_type = null;
return CreateType (type, declaring_type, dtype, canImportBaseType);
}
- protected TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType)
+ protected TypeSpec CreateType (MetaType type, TypeSpec declaringType, AttributesTypeInfoReader dtype, bool canImportBaseType)
{
TypeSpec spec;
if (import_cache.TryGetValue (type, out spec)) {
return null;
if (declaringType == null) {
// Simple case, no nesting
- spec = CreateType (type_def, null, new DynamicTypeReader (), canImportBaseType);
+ spec = CreateType (type_def, null, new AttributesTypeInfoReader (), canImportBaseType);
spec = spec.MakeGenericType (module, targs);
} else {
//
if (t.Kind == MemberKind.MissingType)
spec = t;
else
- spec = MemberCache.FindNestedType (spec, t.Name, t.Arity);
+ spec = MemberCache.FindNestedType (spec, t.Name, t.Arity, false);
if (t.Arity > 0) {
spec = spec.MakeGenericType (module, targs.Skip (targs_pos).Take (spec.Arity).ToArray ());
if (index > 0)
name = name.Substring (0, index);
- spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos);
+ spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos, false);
if (spec.Arity > 0) {
spec = spec.MakeGenericType (module, targs.Skip (targs_pos).ToArray ());
}
}
+ if (spec.IsTupleType && dtype.HasNamedTupleAttribute ()) {
+ var names = dtype.GetNamedTupleElements (spec.Arity);
+ if (names != null)
+ return NamedTupleSpec.MakeType (module, (InflatedTypeSpec) spec, names);
+
+ dtype.TuplePosition += spec.Arity;
+ }
+
// Don't add generic type with dynamic arguments, they can interfere with same type
// using object type arguments
if (!spec.HasDynamicElement) {
else if (type.BaseType != null) {
TypeSpec base_type;
if (!IsMissingType (type.BaseType) && type.BaseType.IsGenericType)
- base_type = CreateType (type.BaseType, new DynamicTypeReader (type), true);
+ base_type = CreateType (type.BaseType, new AttributesTypeInfoReader (type), true);
else
base_type = CreateType (type.BaseType);
}
}
- protected void ImportTypes (MetaType[] types, Namespace targetNamespace, bool importExtensionTypes)
+ public void ImportTypes (MetaType[] types, Namespace targetNamespace, bool importExtensionTypes)
{
Namespace ns = targetNamespace;
string prev_namespace = null;
if (t.Name[0] == '<')
continue;
- var it = CreateType (t, null, new DynamicTypeReader (t), true);
+ var it = CreateType (t, null, new AttributesTypeInfoReader (t), true);
if (it == null)
continue;
public TypeSpec ImportType (MetaType type)
{
- return ImportType (type, new DynamicTypeReader (type));
+ return ImportType (type, new AttributesTypeInfoReader (type), null);
}
- TypeSpec ImportType (MetaType type, DynamicTypeReader dtype)
+ TypeSpec ImportType (MetaType type, AttributesTypeInfoReader dtype, TypeSpec currentType)
{
if (type.HasElementType) {
var element = type.GetElementType ();
- ++dtype.Position;
- var spec = ImportType (element, dtype);
+ ++dtype.DynamicPosition;
+ var spec = ImportType (element, dtype, currentType);
if (type.IsArray)
return ArrayContainer.MakeType (module, spec, type.GetArrayRank ());
if (compiled_types.TryGetValue (type, out compiled_type)) {
if (compiled_type.BuiltinType == BuiltinTypeSpec.Type.Object && dtype.IsDynamicObject ())
return module.Compiler.BuiltinTypes.Dynamic;
+ } else {
+ compiled_type = CreateType (type, dtype, true);
+ }
- return compiled_type;
+ if (currentType == compiled_type && currentType?.IsGeneric == true) {
+ //
+ // Inflates current type to match behaviour of TypeDefinition::CurrentType used by compiled types
+ //
+ var targs = compiled_type.MemberDefinition.TypeParameters;
+ compiled_type = compiled_type.MakeGenericType (module, targs);
}
- return CreateType (type, dtype, true);
+ return compiled_type;
}
static bool IsMissingType (MetaType type)
token = null;
foreach (var internals in internals_visible_to) {
- if (internals.Name != assembly.Name)
+ if (!String.Equals(internals.Name, assembly.Name, StringComparison.OrdinalIgnoreCase))
continue;
if (token == null && assembly is AssemblyDefinition) {