public IPythonType CreateSpecificType(IArgumentSet args, IPythonModule declaringModule, LocationInfo location = null) { location = location ?? LocationInfo.Empty; // Get declared generic parameters of the class, i.e. list of Ts in Generic[T1, T2, ...] var genericClassParameters = Bases.OfType <IGenericClassParameter>().ToArray(); // Optimistically use the first one // TODO: handle optional generics as class A(Generic[_T1], Optional[Generic[_T2]]) var genericClassParameter = genericClassParameters.FirstOrDefault(); // Create map of names listed in Generic[...] in the class definition. // We will be filling the map with specific types, if any provided. var genericTypeDefinitions = genericClassParameter?.TypeDefinitions ?? Array.Empty <IGenericTypeDefinition>(); var genericClassTypeParameters = genericTypeDefinitions.ToDictionary(td => td.Name, td => td); var specificClassTypeParameters = new Dictionary <string, IPythonType>(); var newBases = new List <IPythonType>(); // Arguments passed are those of __init__ or it is a copy constructor. // They do not necessarily match all of the declared generic parameters. // Some generic parameters may be used to specify method return types or // method arguments and do not appear in the constructor argument list. // Figure out whatever specific types we can from the arguments. foreach (var a in args.Arguments) { // The argument may either match generic type definition of be a specific type // created off generic type. Consider '__init__(self, v: _T)' and // 'class A(Generic[K, V], Mapping[K, V])'. if (a.Type is IGenericTypeDefinition argTypeDefinition) { // Parameter is annotated as generic type definition. Check if its generic type // name matches any of the generic class parameters. I.e. if there is // an argument like 'v: _T' we need to check if class has matching Generic[_T]. if (genericClassTypeParameters.ContainsKey(argTypeDefinition.Name)) { // TODO: Check if specific type matches generic type definition constraints and report mismatches. // Assign specific type. if (a.Value is IMember m && m.GetPythonType() is IPythonType pt) { specificClassTypeParameters[argTypeDefinition.Name] = pt; } else { // TODO: report supplied parameter is not a type. } } else { // TODO: report generic parameter name mismatch. } }
public IPythonType CreateSpecificType(IArgumentSet args) { // Get declared generic parameters of the class, i.e. list of Ts in Generic[T1, T2, ...] var genericClassParameters = Bases.OfType <IGenericClassParameter>().ToArray(); // Optimistically use the first one // TODO: handle optional generics as class A(Generic[_T1], Optional[Generic[_T2]]) var genericClassParameter = genericClassParameters.FirstOrDefault(); // Create map of names listed in Generic[...] in the class definition. // We will be filling the map with specific types, if any provided. var genericTypeDefinitions = genericClassParameter?.TypeDefinitions ?? Array.Empty <IGenericTypeDefinition>(); var genericClassTypeParameters = genericTypeDefinitions.ToDictionary(td => td.Name, td => td); var specificClassTypeParameters = new Dictionary <string, IPythonType>(); var newBases = new List <IPythonType>(); // Arguments passed are those of __init__ or it is a copy constructor. // They do not necessarily match all of the declared generic parameters. // Some generic parameters may be used to specify method return types or // method arguments and do not appear in the constructor argument list. // Figure out whatever specific types we can from the arguments. foreach (var arg in args.Arguments) { // The argument may either match generic type definition of be a specific type // created off generic type. Consider '__init__(self, v: _T)' and // 'class A(Generic[K, V], Mapping[K, V])'. if (arg.Type is IGenericTypeDefinition argTypeDefinition) { // Parameter is annotated as generic type definition. Check if its generic type // name matches any of the generic class parameters. I.e. if there is // an argument like 'v: _T' we need to check if class has matching Generic[_T]. if (genericClassTypeParameters.ContainsKey(argTypeDefinition.Name)) { // TODO: Check if specific type matches generic type definition constraints and report mismatches. // Assign specific type. if (arg.Value is IMember m && m.GetPythonType() is IPythonType pt) { specificClassTypeParameters[argTypeDefinition.Name] = pt; } else { // TODO: report supplied parameter is not a type. } } else { // TODO: report generic parameter name mismatch. } continue; } if (arg.Value is IMember member && !member.GetPythonType().IsUnknown()) { var type = member.GetPythonType(); // Type may be a specific type created off generic or just a type // for the copy constructor. Consider 'class A(Generic[K, V], Mapping[K, V])' // constructed as 'd = {1:'a', 2:'b'}; A(d)'. Here we look through bases // and see if any matches the builtin type id. For example, Mapping or Dict // will have BultinTypeId.Dict and we can figure out specific types from // the content of the collection. var b = _bases.OfType <IGenericType>().FirstOrDefault(x => x.TypeId == type.TypeId); if (b != null && b.Parameters.Count > 0) { newBases.Add(type); // Optimistically assign argument types if they match. // Handle common cases directly. GetSpecificTypeFromArgumentValue(b, arg.Value, specificClassTypeParameters); continue; } // Any regular base match? if (_bases.Any(x => x.TypeId == type.TypeId) && !type.Equals(this)) { newBases.Add(type); } } }