/// <summary> /// Returns the constructed form of the provided generic type. /// </summary> public static IdSpan GetConstructed(this TypeConverter formatter, IdSpan unconstructed, params Type[] typeArguments) { var typeString = unconstructed.AsSpan(); var indicatorIndex = typeString.IndexOf((byte)GenericTypeIndicator); var arityString = typeString.Slice(indicatorIndex + 1); if (indicatorIndex < 0 || arityString.IndexOf((byte)StartArgument) >= 0) { throw new InvalidOperationException("Cannot construct an already-constructed type"); } if (!Utf8Parser.TryParse(arityString, out int arity, out var len) || len < arityString.Length || typeArguments.Length != arity) { throw new InvalidOperationException($"Insufficient number of type arguments, {typeArguments.Length}, provided while constructing type \"{unconstructed}\""); } var typeSpecs = new TypeSpec[typeArguments.Length]; for (var i = 0; i < typeArguments.Length; i++) { typeSpecs[i] = RuntimeTypeNameParser.Parse(formatter.Format(typeArguments[i])); } var constructed = new ConstructedGenericTypeSpec(new NamedTypeSpec(null, unconstructed.ToStringUtf8(), typeArguments.Length), typeSpecs).Format(); return(IdSpan.Create(constructed)); }
private static (TypeSpec Type, string Assembly) HandleGeneric(ConstructedGenericTypeSpec type, string assemblyName, Func <QualifiedType, QualifiedType> replaceTypeName) { var(unconstructed, replacementAssembly) = ApplyInner(type.UnconstructedType, assemblyName, replaceTypeName); var newArguments = new TypeSpec[type.Arguments.Length]; var didChange = false; for (var i = 0; i < type.Arguments.Length; i++) { // Generic type parameters do not inherit the assembly of the generic type. var args = ApplyInner(type.Arguments[i], null, replaceTypeName); if (args.Assembly is object) { newArguments[i] = new AssemblyQualifiedTypeSpec(args.Type, args.Assembly); } else { newArguments[i] = args.Type; } didChange |= !ReferenceEquals(newArguments[i], type.Arguments[i]); } if (ReferenceEquals(type.UnconstructedType, unconstructed) && !didChange) { return(type, replacementAssembly); } return(new ConstructedGenericTypeSpec((NamedTypeSpec)unconstructed, newArguments), replacementAssembly); }
private static TypeSpec ParseInternal(ref ReadOnlySpan <char> input) { TypeSpec result; char c; Reader s = default; s.Input = input; // Read namespace and class name, including generic arity, which is a part of the class name. NamedTypeSpec named = null; while (true) { var typeName = ParseTypeName(ref s); named = new NamedTypeSpec(named, typeName.ToString(), s.TotalGenericArity); if (s.TryPeek(out c) && c == NestedTypeIndicator) { // Consume the nested type indicator, then loop to parse the nested type. s.ConsumeCharacter(NestedTypeIndicator); continue; } break; } // Parse generic type parameters if (s.TotalGenericArity > 0 && s.TryPeek(out c) && c == ArrayStartIndicator) { s.ConsumeCharacter(ArrayStartIndicator); var arguments = new TypeSpec[s.TotalGenericArity]; for (var i = 0; i < s.TotalGenericArity; i++) { if (i > 0) { s.ConsumeCharacter(ParameterSeparator); } // Parse the argument type s.ConsumeCharacter(ArrayStartIndicator); var remaining = s.Remaining; arguments[i] = ParseInternal(ref remaining); var consumed = s.Remaining.Length - remaining.Length; s.Consume(consumed); s.ConsumeCharacter(ArrayEndIndicator); } s.ConsumeCharacter(ArrayEndIndicator); result = new ConstructedGenericTypeSpec(named, arguments); } else { // This is not a constructed generic type result = named; } // Parse modifiers bool hadModifier; do { hadModifier = false; if (!s.TryPeek(out c)) { break; } switch (c) { case ArrayStartIndicator: var dimensions = ParseArraySpecifier(ref s); result = new ArrayTypeSpec(result, dimensions); hadModifier = true; break; case PointerIndicator: result = new PointerTypeSpec(result); s.ConsumeCharacter(PointerIndicator); hadModifier = true; break; case ReferenceIndicator: result = new ReferenceTypeSpec(result); s.ConsumeCharacter(ReferenceIndicator); hadModifier = true; break; } } while (hadModifier); // Extract the assembly, if specified. if (s.TryPeek(out c) && c == AssemblyIndicator) { s.ConsumeCharacter(AssemblyIndicator); var assembly = ExtractAssemblySpec(ref s); result = new AssemblyQualifiedTypeSpec(result, assembly.ToString()); } input = s.Remaining; return(result); }