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);
        }
Example #3
0
        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);
        }