private CapnpType _ResolveName(NamePart part, CapnpComposite nameScope, CapnpBoundGenericType genericScope = null) { var result = _ResolveName(part.Name); if (result == null) { // Todo: this is somewhat "bolted" on, can we unify with generics? if (part.Name == "List" && part.TypeParameters.Length == 1) { var param = nameScope.ResolveFullName(part.TypeParameters[0]); if (param == null) { return(null); } return(new CapnpList { Parameter = param }); } } // E.g. an unresolved Using. if (result is CapnpReference) { return(result); } if (result is CapnpGenericType) { // Resolve generic parameters given our generic state. // Note that the name could refer to a generic parameter creating a *partially closed* type. var generic = (CapnpGenericType)result; // We don't allow *partial* closing of a generic type (there's no syntax for it). if (generic.TypeParameters.Length != part.TypeParameters.Length && part.TypeParameters.Length > 0) { return(null); } // Nothing to parameterize. if (generic.TypeParameters.Length == 0 && part.TypeParameters.Length > 0) { return(null); } // If the type does not actually have generic parameters, and we're not a nested type of a generic type, we're done. if (!generic.IsGeneric && genericScope == null) { return(result); } Debug.Assert(generic.TypeParameters.Length == part.TypeParameters.Length || part.TypeParameters.Length == 0); var resolvedParams = part.TypeParameters.Length == 0 ? generic.TypeParameters : // the type is fully open part.TypeParameters.Select(p => nameScope.ResolveFullName(p)).ToArray(); // If any of the type parameters are unresolved, we have to wait. if (resolvedParams.Any(p => p == null || p is CapnpReference)) { return(null); } // The generic scope is the scope in which generic parameters our bound. // If none are defined the parent scope is closed using just the generic parameters. var parentScope = genericScope ?? generic.Scope.MakeOpenGenericType(); return(new CapnpBoundGenericType { OpenType = generic, ParentScope = parentScope, TypeParameters = resolvedParams }); } else if (result is CapnpBoundGenericType) { var closed = (CapnpBoundGenericType)result; if (part.TypeParameters.Length > 0 && closed.TypeParameters.Length != part.TypeParameters.Length) { return(null); } var resolvedParams = closed.TypeParameters; if (part.TypeParameters.Length > 0) { // Cannot be partially closed and it makes no sense to close an already fully closed generic type Debug.Assert(closed.TypeParameters.All(p => (p is CapnpGenericParameter))); resolvedParams = part.TypeParameters.Select(p => nameScope.ResolveFullName(p)).ToArray(); if (resolvedParams.Any(p => p == null || p is CapnpReference)) { return(null); } } // Return a new closed generic whose scope is the current genericScope if defined. // Note that in the case both genericScope and clode.ParentScope exist, genericScope is "more closed" but point // to the same open type. Debug.Assert(genericScope == null || closed.ParentScope == null || genericScope.OpenType == closed.ParentScope.OpenType); return(new CapnpBoundGenericType { OpenType = closed.OpenType, ParentScope = genericScope ?? closed.ParentScope, TypeParameters = resolvedParams }); } else if (part.TypeParameters.Length > 0) { // The name defines generic parameters but the type is not generic. return(null); } else if (result is CapnpGenericParameter) { return(result); } else if (genericScope != null) { // An annotation or enumeration or whatever contained within a generic struct is itself generic. return(new CapnpBoundGenericType { OpenType = (CapnpNamedType)result, ParentScope = genericScope, TypeParameters = Empty <CapnpType> .Array }); } else { return(result); } }