/// <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 <TypeSymbol> oldFieldTypes = AnonymousTypeManager.GetAnonymousTypePropertyTypes(previous); ImmutableArray <TypeSymbol> newFieldTypes = SubstituteTypes(oldFieldTypes); return((oldFieldTypes == newFieldTypes) ? previous : AnonymousTypeManager.ConstructAnonymousTypeSymbol(previous, newFieldTypes)); } // 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 <TypeSymbol> oldTypeArguments = previous.TypeArgumentsNoUseSiteDiagnostics; ImmutableArray <TypeSymbol> newTypeArguments = SubstituteTypes(oldTypeArguments); if (ReferenceEquals(oldConstructedFrom, newConstructedFrom) && oldTypeArguments == newTypeArguments) { return(previous); } return(newConstructedFrom.ConstructIfGeneric(newTypeArguments)); }
/// <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 <TypeSymbol> oldFieldTypes = AnonymousTypeManager.GetAnonymousTypePropertyTypes(previous); ImmutableArray <TypeSymbol> newFieldTypes = SubstituteTypesWithoutModifiers(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).Type; 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 <TypeSymbol> oldTypeArguments = previous.TypeArgumentsNoUseSiteDiagnostics; bool changed = !ReferenceEquals(oldConstructedFrom, newConstructedFrom); bool hasModifiers = previous.HasTypeArgumentsCustomModifiers; var newTypeArguments = ArrayBuilder <TypeWithModifiers> .GetInstance(oldTypeArguments.Length); for (int i = 0; i < oldTypeArguments.Length; i++) { var oldArgument = hasModifiers ? new TypeWithModifiers(oldTypeArguments[i], previous.GetTypeArgumentCustomModifiers(i)) : new TypeWithModifiers(oldTypeArguments[i]); var newArgument = oldArgument.SubstituteTypeWithTupleUnification(this); if (!changed && oldArgument != newArgument) { changed = true; } newTypeArguments.Add(newArgument); } if (!changed) { newTypeArguments.Free(); return(previous); } return(newConstructedFrom.ConstructIfGeneric(newTypeArguments.ToImmutableAndFree())); }