Exemplo n.º 1
0
        public async Task <IMember> GetValueFromFunctionTypeAsync(IPythonFunctionType fn, IPythonInstance instance, CallExpression expr, CancellationToken cancellationToken = default)
        {
            // Determine argument types
            var args = new ArgumentSet(fn, instance, expr, this);

            args = await args.EvaluateAsync(cancellationToken);

            // If order to be able to find matching overload, we need to know
            // parameter types and count. This requires function to be analyzed.
            // Since we don't know which overload we will need, we have to
            // process all known overloads for the function.
            foreach (var o in fn.Overloads)
            {
                await SymbolTable.EvaluateAsync(o.FunctionDefinition, cancellationToken);
            }

            // Re-declare parameters in the function scope since originally
            // their types might not have been known and now argument set
            // may contain concrete values.
            if (fn.FunctionDefinition != null)
            {
                using (OpenScope(fn.FunctionDefinition, out _)) {
                    args.DeclareParametersInScope(this);
                }
            }

            // If instance is not the same as the declaring type, then call
            // most probably comes from the derived class which means that
            // the original 'self' and 'cls' variables are no longer valid
            // and function has to be re-evaluated with new arguments.
            var instanceType = instance?.GetPythonType();

            if (instanceType == null || fn.DeclaringType == null || fn.IsSpecialized ||
                instanceType.IsSpecialized || fn.DeclaringType.IsSpecialized ||
                instanceType.Equals(fn.DeclaringType))
            {
                var t = instance?.Call(fn.Name, args) ?? fn.Call(null, fn.Name, args);
                if (!t.IsUnknown())
                {
                    return(t);
                }
            }

            // Try and evaluate with specific arguments but prevent recursion.
            return(await TryEvaluateVithArgumentsAsync(fn.FunctionDefinition, args, cancellationToken));
        }
        public IMember GetValueFromFunctionType(IPythonFunctionType fn, IPythonInstance instance, CallExpression expr)
        {
            // If order to be able to find matching overload, we need to know
            // parameter types and count. This requires function to be analyzed.
            // Since we don't know which overload we will need, we have to
            // process all known overloads for the function.
            foreach (var o in fn.Overloads)
            {
                SymbolTable.Evaluate(o.FunctionDefinition);
            }

            // Pick the best overload.
            FunctionDefinition fd;
            ArgumentSet        args;
            var instanceType = instance?.GetPythonType();

            if (fn.Overloads.Count == 1)
            {
                fd   = fn.Overloads[0].FunctionDefinition;
                args = new ArgumentSet(fn, 0, instanceType, expr, this);
                args = args.Evaluate();
            }
            else
            {
                args = FindOverload(fn, instanceType, expr);
                if (args == null)
                {
                    return(UnknownType);
                }
                fd = fn.Overloads.Count > 0 ? fn.Overloads[args.OverloadIndex].FunctionDefinition : null;
            }

            // Re-declare parameters in the function scope since originally
            // their types might not have been known and now argument set
            // may contain concrete values.
            if (fd != null && EvaluateFunctionBody(fn))
            {
                using (OpenScope(fn.DeclaringModule, fn.FunctionDefinition, out _)) {
                    args.DeclareParametersInScope(this);
                }
            }

            // If instance type is not the same as the declaring type, then call most probably comes
            // from the derived class which means that the original 'self' and 'cls' variables
            // are no longer valid and function has to be re-evaluated with new arguments.
            // Note that there is nothing to re-evaluate in stubs.
            if (instanceType == null || fn.DeclaringType == null || fn.IsSpecialized ||
                instanceType.IsSpecialized || fn.DeclaringType.IsSpecialized ||
                instanceType.Equals(fn.DeclaringType) ||
                fn.IsStub || !string.IsNullOrEmpty(fn.Overloads[args.OverloadIndex].GetReturnDocumentation()))
            {
                LoadFunctionDependencyModules(fn);

                var m = instance?.Call(fn.Name, args) ?? fn.Call(null, fn.Name, args);
                if (!m.IsUnknown())
                {
                    return(m);
                }
            }

            // We could not tell the return type from the call. Here we try and evaluate with specific arguments.
            // Note that it does not make sense evaluating stubs or compiled/scraped modules since they
            // should be either annotated or static return type known from the analysis.
            //
            // Also, we do not evaluate library code with arguments for performance reasons.
            // This will prevent cases like
            //      def func(a, b): return a + b
            // from working in libraries, but this is small sacrifice for significant performance
            // increase in library analysis.
            if (fn.DeclaringModule is IDocument && EvaluateFunctionBody(fn))
            {
                // Stubs are coming from another module.
                return(TryEvaluateWithArguments(fn, args));
            }
            return(UnknownType);
        }
Exemplo n.º 3
0
        public IMember GetValueFromFunctionType(IPythonFunctionType fn, IPythonInstance instance, CallExpression expr)
        {
            // If order to be able to find matching overload, we need to know
            // parameter types and count. This requires function to be analyzed.
            // Since we don't know which overload we will need, we have to
            // process all known overloads for the function.
            foreach (var o in fn.Overloads)
            {
                SymbolTable.Evaluate(o.FunctionDefinition);
            }

            // Pick the best overload.
            FunctionDefinition fd;
            ArgumentSet        args;

            if (fn.Overloads.Count == 1)
            {
                fd   = fn.Overloads[0].FunctionDefinition;
                args = new ArgumentSet(fn, 0, instance, expr, this);
                args = args.Evaluate();
            }
            else
            {
                args = FindOverload(fn, instance, expr);
                if (args == null)
                {
                    return(UnknownType);
                }
                fd = fn.Overloads.Count > 0 ? fn.Overloads[args.OverloadIndex].FunctionDefinition : null;
            }

            // Re-declare parameters in the function scope since originally
            // their types might not have been known and now argument set
            // may contain concrete values.
            if (fd != null)
            {
                using (OpenScope(fn.DeclaringModule, fn.FunctionDefinition, out _)) {
                    args.DeclareParametersInScope(this);
                }
            }

            // If instance is not the same as the declaring type, then call
            // most probably comes from the derived class which means that
            // the original 'self' and 'cls' variables are no longer valid
            // and function has to be re-evaluated with new arguments.
            // Note that there is nothing to re-evaluate in stubs.
            var instanceType = instance?.GetPythonType();

            if (instanceType == null || fn.DeclaringType == null || fn.IsSpecialized ||
                instanceType.IsSpecialized || fn.DeclaringType.IsSpecialized ||
                instanceType.Equals(fn.DeclaringType) ||
                fn.IsStub || !string.IsNullOrEmpty(fn.Overloads[args.OverloadIndex].GetReturnDocumentation(null)))
            {
                if (fn.IsSpecialized && fn is PythonFunctionType ft && ft.Dependencies.Count > 0)
                {
                    var dependencies = ImmutableArray <IPythonModule> .Empty;
                    foreach (var moduleName in ft.Dependencies)
                    {
                        var dependency = Interpreter.ModuleResolution.GetOrLoadModule(moduleName);
                        if (dependency != null)
                        {
                            dependencies = dependencies.Add(dependency);
                        }
                    }
                    Services.GetService <IPythonAnalyzer>().EnqueueDocumentForAnalysis(Module, dependencies);
                }

                var t = instance?.Call(fn.Name, args) ?? fn.Call(null, fn.Name, args);
                if (!t.IsUnknown())
                {
                    return(t);
                }
            }

            // Try and evaluate with specific arguments. Note that it does not
            // make sense to evaluate stubs since they already should be annotated.
            if (fn.DeclaringModule is IDocument doc && fd?.Ast == doc.GetAnyAst())
            {
                // Stubs are coming from another module.
                return(TryEvaluateWithArguments(fn.DeclaringModule, fd, args));
            }
            return(UnknownType);
        }