示例#1
0
        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;
        }