private Type ResolveType( Cci.ITypeReference typeRef, GenericContext genericContext = default(GenericContext), TypeBuilder dependentType = null, bool valueTypeDependency = false) { var typeDef = typeRef.AsTypeDefinition(_context); if (typeDef != null && IsLocal(typeRef)) { var builder = _typeBuilders[typeDef]; if (dependentType != null && (!valueTypeDependency || builder.IsValueType)) { AddDependency(dependentType, builder); } return builder; } Type result; Cci.IGenericParameterReference genericParamRef; Cci.IGenericTypeInstanceReference genericRef; Cci.ISpecializedNestedTypeReference specializedNestedRef; Cci.INestedTypeReference nestedRef; Cci.IArrayTypeReference arrayType; Cci.IManagedPointerTypeReference refType; Cci.IPointerTypeReference ptrType; Cci.INamespaceTypeReference nsType; Cci.IModifiedTypeReference modType; if ((nsType = typeRef.AsNamespaceTypeReference) != null) { // cache lookup (no type dependencies to track): if (_typeRefs.TryGetValue(typeRef, out result)) { return result; } // a namespace type builder would already be found in type builders, so we don't get here: Debug.Assert(!IsLocal(typeRef)); Cci.IUnitReference unitRef = nsType.GetUnit(_context); Cci.IAssemblyReference assemblyRef; var moduleRef = unitRef as Cci.IModuleReference; if (moduleRef != null) { if (ReferenceEquals(moduleRef.GetContainingAssembly(_context), _module.GetContainingAssembly(_context))) { throw new NotSupportedException("Ref.Emit limitation: modules not supported"); } else { assemblyRef = moduleRef.GetContainingAssembly(_context); } } else { assemblyRef = unitRef as Cci.IAssemblyReference; } // We only track dependency among type builders so we don't need to track it here. result = ResolveType(ResolveAssembly(assemblyRef), nsType); } else if ((specializedNestedRef = typeRef.AsSpecializedNestedTypeReference) != null) { Type unspecialized = ResolveType(specializedNestedRef.UnspecializedVersion, genericContext, dependentType, valueTypeDependency); // the resulting type doesn't depend on generic arguments if it is not a value type: if (valueTypeDependency && !unspecialized.IsValueType) { dependentType = null; } Type[] typeArgs = ResolveGenericArguments(specializedNestedRef, genericContext, dependentType); // cache lookup (all type dependencies already established above): if (_typeRefs.TryGetValue(typeRef, out result)) { return result; } result = unspecialized.MakeGenericType(typeArgs); } else if ((genericRef = typeRef.AsGenericTypeInstanceReference) != null) { Type genericType = ResolveType(genericRef.GenericType, genericContext, dependentType, valueTypeDependency); // the resulting type doesn't depend on generic arguments if it is not a value type: if (valueTypeDependency && !genericType.IsValueType) { dependentType = null; } Type[] typeArgs = ResolveGenericArguments(genericRef, genericContext, dependentType); // cache lookup (all type dependencies already established above): if (_typeRefs.TryGetValue(typeRef, out result)) { return result; } result = genericType.MakeGenericType(typeArgs); } else if ((nestedRef = typeRef.AsNestedTypeReference) != null) { // cache lookup (no type dependencies to track): if (_typeRefs.TryGetValue(typeRef, out result)) { return result; } // a nested type builder would already be found in type builders, so we don't get here: Debug.Assert(!IsLocal(typeRef)); // we only track dependency among type builders so we don't need to track it here: Type containingType = ResolveType(nestedRef.GetContainingType(_context), genericContext); result = containingType.GetNestedType(Cci.MetadataWriter.GetMangledName(nestedRef), BindingFlags.Public | BindingFlags.NonPublic); } else if ((arrayType = typeRef as Cci.IArrayTypeReference) != null) { // an array isn't a value type -> don't propagate dependency: Type elementType = ResolveType(arrayType.GetElementType(_context), genericContext, valueTypeDependency ? null : dependentType); // cache lookup (all type dependencies already established above): if (_typeRefs.TryGetValue(typeRef, out result)) { return result; } result = (arrayType.Rank > 1) ? elementType.MakeArrayType((int)arrayType.Rank) : elementType.MakeArrayType(); } else if ((refType = typeRef as Cci.IManagedPointerTypeReference) != null) { // a managed pointer isn't a value type -> don't propagate dependency: Type elementType = ResolveType(refType.GetTargetType(_context), genericContext, valueTypeDependency ? null : dependentType); // cache lookup (all type dependencies already established above): if (_typeRefs.TryGetValue(typeRef, out result)) { return result; } result = elementType.MakeByRefType(); } else if ((ptrType = typeRef as Cci.IPointerTypeReference) != null) { // a pointer isn't a value type -> don't propagate dependency: Type elementType = ResolveType(ptrType.GetTargetType(_context), genericContext, valueTypeDependency ? null : dependentType); // cache lookup (all type dependencies already established above): if (_typeRefs.TryGetValue(typeRef, out result)) { return result; } result = elementType.MakePointerType(); } else if ((modType = typeRef as Cci.IModifiedTypeReference) != null) { Type[] reqMods, optMods; ResolveCustomModifiers(modType, dependentType, out reqMods, out optMods); Type unmodified = ResolveType(modType.UnmodifiedType, genericContext, dependentType, valueTypeDependency); // cache lookup (all type dependencies already established above): if (_typeRefs.TryGetValue(typeRef, out result)) { return result; } result = new ModifiedType(unmodified, reqMods, optMods); } else if ((genericParamRef = typeRef as Cci.IGenericParameterReference) != null) { GenericTypeParameterBuilder builder; if (_genericParameterBuilders.TryGetValue(genericParamRef, out builder)) { return builder; } Debug.Assert(!genericContext.IsNull); if (genericParamRef.AsGenericMethodParameterReference != null) { // Note that all occurrences of M in the following snippet refer to the same // IGenericMethodParameterReference object // // void foo<M>() // { // C<M>.bar<T>(T, M); // } // // Though in the context of C<M>.bar<T>(T, M) method reference only T is bound to the generic parameter of method bar. // We never get to resolve M here, because it can only be a GenericTypeParameterBuilder resolved earlier. return genericContext.MethodParameters[genericParamRef.AsGenericMethodParameterReference.Index]; } else { return genericContext.TypeParameters[GetConsolidatedGenericTypeParameterIndex(genericParamRef.AsGenericTypeParameterReference)]; } } else { throw ExceptionUtilities.Unreachable; } // do not cache if the lookup is relative to a generic context: if (genericContext.IsNull) { _typeRefs.Add(typeRef, result); } return result; }