public override TypeNode VisitTypeReference(TypeNode type) { //TODO: break up this method if (type == null) { return(null); } TypeNodeList pars = this.pars; TypeNodeList args = this.args; switch (type.NodeType) { case NodeType.ArrayType: ArrayType arrType = (ArrayType)type; TypeNode elemType = this.VisitTypeReference(arrType.ElementType); if (elemType == arrType.ElementType || elemType == null) { return(arrType); } if (arrType.IsSzArray()) { return(elemType.GetArrayType(1)); } return(elemType.GetArrayType(arrType.Rank, arrType.Sizes, arrType.LowerBounds)); case NodeType.DelegateNode: { FunctionType ftype = type as FunctionType; if (ftype == null) { goto default; } TypeNode referringType = ftype.DeclaringType == null ? this.CurrentType : this.VisitTypeReference(ftype.DeclaringType); return(FunctionType.For(this.VisitTypeReference(ftype.ReturnType), this.VisitParameterList(ftype.Parameters), referringType)); } case NodeType.Pointer: Pointer pType = (Pointer)type; elemType = this.VisitTypeReference(pType.ElementType); if (elemType == pType.ElementType || elemType == null) { return(pType); } return(elemType.GetPointerType()); case NodeType.Reference: Reference rType = (Reference)type; elemType = this.VisitTypeReference(rType.ElementType); if (elemType == rType.ElementType || elemType == null) { return(rType); } return(elemType.GetReferenceType()); case NodeType.ArrayTypeExpression: ArrayTypeExpression aExpr = (ArrayTypeExpression)type; aExpr.ElementType = this.VisitTypeReference(aExpr.ElementType); return(aExpr); case NodeType.BoxedTypeExpression: BoxedTypeExpression bExpr = (BoxedTypeExpression)type; bExpr.ElementType = this.VisitTypeReference(bExpr.ElementType); return(bExpr); case NodeType.ClassExpression: { ClassExpression cExpr = (ClassExpression)type; cExpr.Expression = this.VisitTypeExpression(cExpr.Expression); //Could happen if the expression is a template parameter if (cExpr.Expression is Literal lit) { return(lit.Value as TypeNode); } cExpr.TemplateArguments = this.VisitTypeReferenceList(cExpr.TemplateArguments); return(cExpr); } case NodeType.ClassParameter: case NodeType.TypeParameter: int key = type.UniqueKey; for (int i = 0, n = pars == null ? 0 : pars.Count, m = args == null ? 0 : args.Count; i < n && i < m; i++) { //^ assert pars != null && args != null; TypeNode tp = pars[i]; if (tp == null) { continue; } if (tp.UniqueKey == key) { return(args[i]); } if (tp.Name.UniqueIdKey == type.Name.UniqueIdKey && (tp is ClassParameter && type is TypeParameter)) { //This shouldn't really happen, but in practice it does. Hack past it. return(args[i]); } } return(type); case NodeType.FlexArrayTypeExpression: FlexArrayTypeExpression flExpr = (FlexArrayTypeExpression)type; flExpr.ElementType = this.VisitTypeReference(flExpr.ElementType); return(flExpr); case NodeType.FunctionTypeExpression: FunctionTypeExpression ftExpr = (FunctionTypeExpression)type; ftExpr.Parameters = this.VisitParameterList(ftExpr.Parameters); ftExpr.ReturnType = this.VisitTypeReference(ftExpr.ReturnType); return(ftExpr); case NodeType.InvariantTypeExpression: InvariantTypeExpression invExpr = (InvariantTypeExpression)type; invExpr.ElementType = this.VisitTypeReference(invExpr.ElementType); return(invExpr); case NodeType.InterfaceExpression: InterfaceExpression iExpr = (InterfaceExpression)type; if (iExpr.Expression == null) { goto default; } iExpr.Expression = this.VisitTypeExpression(iExpr.Expression); iExpr.TemplateArguments = this.VisitTypeReferenceList(iExpr.TemplateArguments); return(iExpr); case NodeType.NonEmptyStreamTypeExpression: NonEmptyStreamTypeExpression neExpr = (NonEmptyStreamTypeExpression)type; neExpr.ElementType = this.VisitTypeReference(neExpr.ElementType); return(neExpr); case NodeType.NonNullTypeExpression: NonNullTypeExpression nnExpr = (NonNullTypeExpression)type; nnExpr.ElementType = this.VisitTypeReference(nnExpr.ElementType); return(nnExpr); case NodeType.NonNullableTypeExpression: NonNullableTypeExpression nbExpr = (NonNullableTypeExpression)type; nbExpr.ElementType = this.VisitTypeReference(nbExpr.ElementType); return(nbExpr); case NodeType.NullableTypeExpression: NullableTypeExpression nuExpr = (NullableTypeExpression)type; nuExpr.ElementType = this.VisitTypeReference(nuExpr.ElementType); return(nuExpr); case NodeType.OptionalModifier: { TypeModifier modType = (TypeModifier)type; TypeNode modifiedType = this.VisitTypeReference(modType.ModifiedType); TypeNode modifierType = this.VisitTypeReference(modType.Modifier); if (modifiedType == null || modifierType == null) { return(type); } return(OptionalModifier.For(modifierType, modifiedType)); } case NodeType.RequiredModifier: { TypeModifier modType = (TypeModifier)type; TypeNode modifiedType = this.VisitTypeReference(modType.ModifiedType); TypeNode modifierType = this.VisitTypeReference(modType.Modifier); if (modifiedType == null || modifierType == null) { Debug.Fail(""); return(type); } return(RequiredModifier.For(modifierType, modifiedType)); } case NodeType.OptionalModifierTypeExpression: OptionalModifierTypeExpression optmodType = (OptionalModifierTypeExpression)type; optmodType.ModifiedType = this.VisitTypeReference(optmodType.ModifiedType); optmodType.Modifier = this.VisitTypeReference(optmodType.Modifier); return(optmodType); case NodeType.RequiredModifierTypeExpression: RequiredModifierTypeExpression reqmodType = (RequiredModifierTypeExpression)type; reqmodType.ModifiedType = this.VisitTypeReference(reqmodType.ModifiedType); reqmodType.Modifier = this.VisitTypeReference(reqmodType.Modifier); return(reqmodType); case NodeType.PointerTypeExpression: PointerTypeExpression pExpr = (PointerTypeExpression)type; pExpr.ElementType = this.VisitTypeReference(pExpr.ElementType); return(pExpr); case NodeType.ReferenceTypeExpression: ReferenceTypeExpression rExpr = (ReferenceTypeExpression)type; rExpr.ElementType = this.VisitTypeReference(rExpr.ElementType); return(rExpr); case NodeType.StreamTypeExpression: StreamTypeExpression sExpr = (StreamTypeExpression)type; sExpr.ElementType = this.VisitTypeReference(sExpr.ElementType); return(sExpr); case NodeType.TupleTypeExpression: TupleTypeExpression tuExpr = (TupleTypeExpression)type; tuExpr.Domains = this.VisitFieldList(tuExpr.Domains); return(tuExpr); case NodeType.TypeExpression: { TypeExpression tExpr = (TypeExpression)type; tExpr.Expression = this.VisitTypeExpression(tExpr.Expression); if (tExpr.Expression is Literal) { return(type); } tExpr.TemplateArguments = this.VisitTypeReferenceList(tExpr.TemplateArguments); return(tExpr); } case NodeType.TypeIntersectionExpression: TypeIntersectionExpression tiExpr = (TypeIntersectionExpression)type; tiExpr.Types = this.VisitTypeReferenceList(tiExpr.Types); return(tiExpr); case NodeType.TypeUnionExpression: TypeUnionExpression tyuExpr = (TypeUnionExpression)type; tyuExpr.Types = this.VisitTypeReferenceList(tyuExpr.Types); return(tyuExpr); default: TypeNode declaringType = this.VisitTypeReference(type.DeclaringType); if (declaringType != null) { Identifier tname = type.Name; if (type.Template != null && type.IsGeneric) { tname = type.Template.Name; } TypeNode nt = declaringType.GetNestedType(tname); if (nt != null) { TypeNodeList arguments = type.TemplateArguments; type = nt; if (TargetPlatform.UseGenerics) { if (arguments != null && arguments.Count > 0 && nt.ConsolidatedTemplateParameters != null && nt.ConsolidatedTemplateParameters.Count > 0) { type = nt.GetTemplateInstance(this.TargetModule, this.CurrentType, declaringType, arguments); } } } } if (type.Template != null && (type.ConsolidatedTemplateParameters == null || type.ConsolidatedTemplateParameters.Count == 0)) { if (!type.IsNotFullySpecialized && (!type.IsNormalized || (this.CurrentType != null && type.DeclaringModule == this.CurrentType.DeclaringModule))) { return(type); } // Type is a template instance, but some of its arguments were themselves parameters. // See if any of these parameters are to be specialized by this specializer. bool mustSpecializeFurther = false; TypeNodeList targs = type.TemplateArguments; int numArgs = targs == null ? 0 : targs.Count; if (targs != null) { targs = new TypeNodeList(targs); for (int i = 0; i < numArgs; i++) { TypeNode targ = targs[i]; if (targ is ITypeParameter tparg) { for (int j = 0, np = pars == null ? 0 : pars.Count, m = args == null ? 0 : args.Count; j < np && j < m; j++) { //^ assert pars != null && args != null; if (TargetPlatform.UseGenerics) { if (!(pars[j] is ITypeParameter par)) { continue; } if (tparg == par || (tparg.ParameterListIndex == par.ParameterListIndex && tparg.DeclaringMember == par.DeclaringMember)) { targ = this.args[j]; break; } } else { if (targ == pars[j]) { targ = this.args[j]; break; } } } } else { if (targ != type) { targ = this.VisitTypeReference(targ); } if (targ == type) { continue; } } mustSpecializeFurther |= targs[i] != targ; targs[i] = targ; } } if (targs == null || !mustSpecializeFurther) { return(type); } return(type.Template.GetTemplateInstance(this.TargetModule, this.CurrentType, declaringType, targs)); } TypeNodeList tPars = type.TemplateParameters; if (tPars == null || tPars.Count == 0) { return(type); //Not a parameterized type. No need to get an instance. } TypeNodeList tArgs = new TypeNodeList(); for (int i = 0, n = tPars.Count; i < n; i++) { TypeNode tPar = tPars[i]; tArgs.Add(tPar); //Leave parameter in place if there is no match if (tPar == null || tPar.Name == null) { continue; } int idKey = tPar.Name.UniqueIdKey; for (int j = 0, m = pars == null ? 0 : pars.Count, k = args == null ? 0 : args.Count; j < m && j < k; j++) { //^ assert pars != null && args != null; TypeNode par = pars[j]; if (par == null || par.Name == null) { continue; } if (par.Name.UniqueIdKey == idKey) { tArgs[i] = args[j]; break; } } } return(type.GetTemplateInstance(this.TargetModule, this.CurrentType, this.VisitTypeReference(type.DeclaringType), tArgs)); } }
private static string GetStringForTypeNode(TypeNode type, List <TypeNode> typeTemplateParameters, List <TypeNode> memberTemplateParameters) { StringBuilder sb = new StringBuilder(); switch (type.NodeType) { /* Ordinary types */ case NodeType.Class: case NodeType.Interface: case NodeType.Struct: case NodeType.EnumNode: case NodeType.DelegateNode: if (type.DeclaringType == null) { if (type.Namespace.Name.Length != 0) { sb.Append(type.Namespace.Name); sb.Append('.'); } } else { sb.Append(GetStringForTypeNode(type.DeclaringType, typeTemplateParameters, memberTemplateParameters)); sb.Append('.'); } if (type.IsGeneric) { String templateName = type.Template.Name.Name.Replace('+', '.'); int pos = templateName.LastIndexOf('`'); if (pos != -1) { sb.Append(templateName.Substring(0, pos)); } else { sb.Append(templateName); } } else { sb.Append(type.Name.Name.Replace('+', '.')); } break; /* Simple pointer / reference types */ case NodeType.Reference: sb.Append(GetStringForTypeNode(((Reference)type).ElementType, typeTemplateParameters, memberTemplateParameters)); sb.Append('@'); break; case NodeType.Pointer: sb.Append(GetStringForTypeNode(((Pointer)type).ElementType, typeTemplateParameters, memberTemplateParameters)); sb.Append('*'); break; /* Generic parameters */ case NodeType.ClassParameter: case NodeType.TypeParameter: int index; if ((index = typeTemplateParameters.IndexOf(type)) != -1) { sb.AppendFormat(CultureInfo.InvariantCulture, "`{0}", index); } else if ((index = memberTemplateParameters.IndexOf(type)) != -1) { // Undocumented: based on output from MS compilers. sb.AppendFormat(CultureInfo.InvariantCulture, "``{0}", index); } else { throw new InvalidOperationException("Unable to resolve TypeParameter to a type argument."); } break; /* Arrays */ case NodeType.ArrayType: ArrayType array = ((ArrayType)type); sb.Append(GetStringForTypeNode(array.ElementType, typeTemplateParameters, memberTemplateParameters)); if (array.IsSzArray()) { sb.Append("[]"); } else { // This case handles true multidimensional arrays. // For example, in C#: string[,] myArray sb.Append('['); for (int i = 0; i < array.Rank; i++) { if (i != 0) { sb.Append(','); } // The following appears to be consistent with MS C# compiler output. sb.AppendFormat(CultureInfo.InvariantCulture, "{0}:", array.GetLowerBound(i)); if (array.GetSize(i) != 0) { sb.AppendFormat(CultureInfo.InvariantCulture, "{0}", array.GetSize(i)); } } sb.Append(']'); } break; /* Strange types (typically from C++/CLI) */ case NodeType.FunctionPointer: FunctionPointer funcPointer = (FunctionPointer)type; sb.Append("=FUNC:"); sb.Append(GetStringForTypeNode(funcPointer.ReturnType, typeTemplateParameters, memberTemplateParameters)); if (funcPointer.ParameterTypes.Count != 0) { bool comma = false; sb.Append('('); foreach (TypeNode parameterType in funcPointer.ParameterTypes) { if (comma) { sb.Append(','); } sb.Append(GetStringForTypeNode(parameterType, typeTemplateParameters, memberTemplateParameters)); comma = true; } sb.Append(')'); } else { // Inconsistent with documentation: based on MS C++ compiler output. sb.Append("(System.Void)"); } break; case NodeType.RequiredModifier: RequiredModifier reqModifier = (RequiredModifier)type; sb.Append(GetStringForTypeNode(reqModifier.ModifiedType, typeTemplateParameters, memberTemplateParameters)); sb.Append("|"); sb.Append(GetStringForTypeNode(reqModifier.Modifier, typeTemplateParameters, memberTemplateParameters)); break; case NodeType.OptionalModifier: OptionalModifier optModifier = (OptionalModifier)type; sb.Append(GetStringForTypeNode(optModifier.ModifiedType, typeTemplateParameters, memberTemplateParameters)); sb.Append("!"); sb.Append(GetStringForTypeNode(optModifier.Modifier, typeTemplateParameters, memberTemplateParameters)); break; default: throw new ArgumentException("Unsupported NodeType.", "type"); } if (type.IsGeneric && type.TemplateArguments.Count != 0) { // Undocumented: based on output from MS compilers. sb.Append('{'); bool comma = false; foreach (TypeNode templateArgumentType in type.TemplateArguments) { if (comma) { sb.Append(','); } sb.Append(GetStringForTypeNode(templateArgumentType, typeTemplateParameters, memberTemplateParameters)); comma = true; } sb.Append('}'); } return(sb.ToString()); }