private NamedTypeSymbol ApplyGenericArguments(NamedTypeSymbol symbol, Type[] typeArguments, ref int currentTypeArgument, bool includeReferences) { int remainingTypeArguments = typeArguments.Length - currentTypeArgument; // in case we are specializing a nested generic definition we might have more arguments than the current symbol: Debug.Assert(remainingTypeArguments >= symbol.Arity); if (remainingTypeArguments == 0) { return(symbol); } var length = symbol.TypeArgumentsNoUseSiteDiagnostics.Length; var typeArgumentSymbols = ArrayBuilder <TypeSymbolWithAnnotations> .GetInstance(length); for (int i = 0; i < length; i++) { var argSymbol = GetTypeByReflectionType(typeArguments[currentTypeArgument++], includeReferences); if ((object)argSymbol == null) { return(null); } typeArgumentSymbols.Add(TypeSymbolWithAnnotations.Create(argSymbol)); } return(symbol.ConstructIfGeneric(typeArgumentSymbols.ToImmutableAndFree())); }
/// <summary> /// SubstType, but for NamedTypeSymbols only. This is used for concrete types, so no alpha substitution appears in the result. /// </summary> internal NamedTypeSymbol SubstituteNamedType(NamedTypeSymbol previous) { if (ReferenceEquals(previous, null)) { return(null); } if (previous.IsUnboundGenericType) { return(previous); } if (previous.IsAnonymousType) { ImmutableArray <TypeSymbolWithAnnotations> oldFieldTypes = AnonymousTypeManager.GetAnonymousTypePropertyTypes(previous); ImmutableArray <TypeSymbolWithAnnotations> newFieldTypes = SubstituteTypes(oldFieldTypes); return((oldFieldTypes == newFieldTypes) ? previous : AnonymousTypeManager.ConstructAnonymousTypeSymbol(previous, newFieldTypes)); } if (previous.IsTupleType) { var previousTuple = (TupleTypeSymbol)previous; NamedTypeSymbol oldUnderlyingType = previousTuple.TupleUnderlyingType; NamedTypeSymbol newUnderlyingType = (NamedTypeSymbol)SubstituteType(oldUnderlyingType).TypeSymbol; return(((object)newUnderlyingType == (object)oldUnderlyingType) ? previous : previousTuple.WithUnderlyingType(newUnderlyingType)); } // TODO: we could construct the result's ConstructedFrom lazily by using a "deep" // construct operation here (as VB does), thereby avoiding alpha renaming in most cases. // Aleksey has shown that would reduce GC pressure if substitutions of deeply nested generics are common. NamedTypeSymbol oldConstructedFrom = previous.ConstructedFrom; NamedTypeSymbol newConstructedFrom = SubstituteMemberType(oldConstructedFrom); ImmutableArray <TypeSymbolWithAnnotations> oldTypeArguments = previous.TypeArgumentsNoUseSiteDiagnostics; bool changed = !ReferenceEquals(oldConstructedFrom, newConstructedFrom); var newTypeArguments = ArrayBuilder <TypeSymbolWithAnnotations> .GetInstance(oldTypeArguments.Length); for (int i = 0; i < oldTypeArguments.Length; i++) { var oldArgument = oldTypeArguments[i]; var newArgument = oldArgument.SubstituteTypeWithTupleUnification(this); if (!changed && !oldArgument.IsSameAs(newArgument)) { changed = true; } newTypeArguments.Add(newArgument); } if (!changed) { newTypeArguments.Free(); return(previous); } return(newConstructedFrom.ConstructIfGeneric(newTypeArguments.ToImmutableAndFree())); }