TypeSpec CreateType(MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType)
{
TypeSpec spec;
if (import_cache.TryGetValue (type, out spec)) {
if (spec == TypeManager.object_type) {
if (dtype.IsDynamicObject (this))
return InternalType.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 ();
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.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;
BuildinTypeSpec bts = pt as BuildinTypeSpec;
if (bts != null)
bts.SetDefinition (definition, type, mod);
}
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;
}