private IMember GetSpecificReturnType(IPythonClassType selfClassType, IArgumentSet args) { var returnValueType = StaticReturnValue.GetPythonType(); switch (returnValueType) { case PythonClassType cls when cls.IsGeneric(): return(CreateSpecificReturnFromClassType(selfClassType, cls, args)); // -> A[_T1, _T2, ...] case IGenericTypeDefinition gtd1 when selfClassType != null: return(CreateSpecificReturnFromTypeVar(selfClassType, gtd1)); // -> _T case IGenericTypeDefinition gtd2 when args != null: // -> T on standalone function. return(args.Arguments.FirstOrDefault(a => gtd2.Equals(a.Type))?.Value as IMember); case IGenericType gt when args != null: // -> CLASS[T] on standalone function (i.e. -> List[T]). var typeArgs = ExpressionEval.GetTypeArgumentsFromParameters(this, args); if (typeArgs != null) { return(gt.CreateSpecificType(typeArgs)); } break; } return(StaticReturnValue); }
private IMember CreateSpecificReturnFromClassType(IPythonClassType selfClassType, PythonClassType returnClassType, IArgumentSet args) { // -> A[_T1, _T2, ...] // Match arguments IReadOnlyList <IPythonType> typeArgs = null; var classGenericParameters = selfClassType?.GenericParameters.Keys.ToArray() ?? Array.Empty <string>(); if (classGenericParameters.Length > 0 && selfClassType != null) { // Declaring class is specific and provides definitions of generic parameters typeArgs = classGenericParameters .Select(n => selfClassType.GenericParameters.TryGetValue(n, out var t) ? t : null) .ExcludeDefault() .ToArray(); } else if (args != null) { typeArgs = ExpressionEval.GetTypeArgumentsFromParameters(this, args); } if (typeArgs != null) { var specificReturnValue = returnClassType.CreateSpecificType(new ArgumentSet(typeArgs)); return(new PythonInstance(specificReturnValue)); } return(null); }
public IMember Call(IArgumentSet args, IPythonType self, Node callLocation = null) { if (!_fromAnnotation) { // First try supplied specialization callback. var rt = _returnValueProvider?.Invoke(DeclaringModule, this, args); if (!rt.IsUnknown()) { return(rt); } } // If function returns generic, determine actual type based on the passed in specific type (self). // If there is no self and no declaring type, the function is standalone. if (self == null && StaticReturnValue.IsGeneric() && Parameters.Any(p => p.IsGeneric)) { return(null); // Evaluate standalone generic with arguments instead. } if (!(self is IPythonClassType selfClassType)) { return(StaticReturnValue); } var returnType = StaticReturnValue.GetPythonType(); switch (returnType) { case PythonClassType cls when cls.IsGeneric(): // -> A[_T1, _T2, ...] // Match arguments IReadOnlyList <IPythonType> typeArgs = null; var classGenericParameters = selfClassType.GenericParameters.Keys.ToArray(); if (classGenericParameters.Length > 0) { // Declaring class is specific and provides definitions of generic parameters typeArgs = classGenericParameters .Select(n => selfClassType.GenericParameters.TryGetValue(n, out var t) ? t : null) .ExcludeDefault() .ToArray(); } else { typeArgs = ExpressionEval.GetTypeArgumentsFromParameters(this, args); } if (typeArgs != null) { var specificReturnValue = cls.CreateSpecificType(new ArgumentSet(typeArgs)); return(new PythonInstance(specificReturnValue)); } break; case IGenericTypeDefinition gtp1: { // -> _T if (selfClassType.GenericParameters.TryGetValue(gtp1.Name, out var specificType)) { return(new PythonInstance(specificType)); } // Try returning the constraint // TODO: improve this, the heuristic is pretty basic and tailored to simple func(_T) -> _T var name = StaticReturnValue.GetPythonType()?.Name; var typeDefVar = DeclaringModule.Analysis.GlobalScope.Variables[name]; if (typeDefVar?.Value is IGenericTypeDefinition gtp2) { return(gtp2.Constraints.FirstOrDefault()); } break; } } return(StaticReturnValue); }