private ArgumentSet FindOverload(IPythonFunctionType fn, IPythonType instanceType, CallExpression expr)
        {
            if (fn.Overloads.Count == 1)
            {
                return(null);
            }

            var sets = new List <ArgumentSet>();

            for (var i = 0; i < fn.Overloads.Count; i++)
            {
                var a    = new ArgumentSet(fn, i, instanceType, expr, this);
                var args = a.Evaluate();
                sets.Add(args);
            }

            var orderedSets     = sets.OrderBy(s => s.Errors.Count);
            var noErrorsMatches = sets.OrderBy(s => s.Errors.Count).TakeWhile(e => e.Errors.Count == 0).ToArray();
            var result          = noErrorsMatches.Any()
                ? noErrorsMatches.FirstOrDefault(args => IsMatch(args, fn.Overloads[args.OverloadIndex].Parameters))
                : null;

            // Optimistically pick the best available.
            return(result ?? orderedSets.FirstOrDefault());
        }
        /// <summary>
        /// Constructs parameter strings that include parameter name, type and default value
        /// like 'x: int' or 'a = None'. Returns collection of parameter strings and
        /// the respective lengths of names for rendering in bold (as current parameter).
        /// </summary>
        private string[] GetFunctionParameters(IPythonFunctionType ft, out int[] parameterNameLengths, int overloadIndex = 0)
        {
            var o    = ft.Overloads[overloadIndex]; // TODO: display all?
            var skip = ft.IsStatic || ft.IsUnbound ? 0 : 1;

            var parameters = new string[o.Parameters.Count - skip];

            parameterNameLengths = new int[o.Parameters.Count - skip];
            for (var i = skip; i < o.Parameters.Count; i++)
            {
                string paramString;
                var    p = o.Parameters[i];
                if (!string.IsNullOrEmpty(p.DefaultValueString))
                {
                    paramString = $"{p.Name}={p.DefaultValueString}";
                }
                else
                {
                    paramString = p.Type.IsUnknown() ? p.Name : $"{p.Name}: {p.Type.Name}";
                }
                parameters[i - skip]           = paramString;
                parameterNameLengths[i - skip] = p.Name.Length;
            }
            return(parameters);
        }
示例#3
0
        private string GetFunctionHoverString(IPythonFunctionType ft, IPythonType self, int overloadIndex = 0)
        {
            var sigString     = GetSignatureString(ft, self, overloadIndex);
            var decTypeString = ft.DeclaringType != null ? $"{ft.DeclaringType.Name}." : string.Empty;
            var funcDoc       = !string.IsNullOrEmpty(ft.Documentation) ? $"\n---\n{ft.MarkdownDoc()}" : string.Empty;

            return($"```\n{decTypeString}{sigString}\n```{funcDoc}");
        }
示例#4
0
        public string GetSignatureString(IPythonFunctionType ft, IPythonType self, int overloadIndex = 0)
        {
            var o = ft.Overloads[overloadIndex];

            var parms      = GetFunctionParameters(ft);
            var parmString = string.Join(", ", parms);
            var returnDoc  = o.GetReturnDocumentation(self);
            var annString  = string.IsNullOrEmpty(returnDoc) ? string.Empty : $" -> {returnDoc}";

            return($"{ft.Name}({parmString}){annString}");
        }
示例#5
0
        private IEnumerable <string> GetFunctionParameters(IPythonFunctionType ft, int overloadIndex = 0)
        {
            var o    = ft.Overloads[overloadIndex]; // TODO: display all?
            var skip = ft.IsStatic || ft.IsUnbound ? 0 : 1;

            return(o.Parameters.Skip(skip).Select(p => {
                if (!string.IsNullOrEmpty(p.DefaultValueString))
                {
                    return $"{p.Name}={p.DefaultValueString}";
                }
                return p.Type.IsUnknown() ? p.Name : $"{p.Name}: {p.Type.Name}";
            }));
        }
        private void CheckValidFunction(IPythonFunctionType function, IReadOnlyList <IParameterInfo> parameters)
        {
            // Don't give diagnostics on functions defined in metaclasses
            if (_self.IsMetaclass())
            {
                return;
            }

            // Static methods don't need any diagnostics
            if (function.IsStatic)
            {
                return;
            }

            // Lambdas never get a self/cls argument.
            if (function.IsLambda())
            {
                return;
            }

            // Error in parameters, don't lint
            if (FunctionDefinition.Body == null)
            {
                return;
            }

            // Otherwise, functions defined in classes must have at least one argument
            if (parameters.IsNullOrEmpty())
            {
                var funcLoc = Eval.GetLocation(FunctionDefinition.NameExpression);
                ReportFunctionParams(Resources.NoMethodArgument, ErrorCodes.NoMethodArgument, funcLoc);
                return;
            }

            var param    = parameters[0].Name;
            var paramLoc = Eval.GetLocation(FunctionDefinition.Parameters[0]);

            // If it is a class method check for cls
            if (function.IsClassMethod && !param.Equals("cls"))
            {
                ReportFunctionParams(Resources.NoClsArgument, ErrorCodes.NoClsArgument, paramLoc);
            }

            // If it is a method check for self
            if (!function.IsClassMethod && !param.Equals("self"))
            {
                ReportFunctionParams(Resources.NoSelfArgument, ErrorCodes.NoSelfArgument, paramLoc);
            }
        }
示例#7
0
        public NamedTuple(IPythonModule declaringModule) : base(BuiltinTypeId.Tuple, declaringModule)
        {
            var interpreter = DeclaringModule.Interpreter;

            var fn = new PythonFunctionType("__init__", new Location(declaringModule), this, "NamedTuple");
            var o  = new PythonFunctionOverload(fn, new Location(DeclaringModule));

            o.SetParameters(new List <ParameterInfo> {
                new ParameterInfo("self", this, ParameterKind.Normal, this),
                new ParameterInfo("name", interpreter.GetBuiltinType(BuiltinTypeId.Str), ParameterKind.Normal, null),
                new ParameterInfo("members", interpreter.GetBuiltinType(BuiltinTypeId.List), ParameterKind.Normal, null)
            });
            fn.AddOverload(o);
            _constructor = fn;
        }
 private void LoadFunctionDependencyModules(IPythonFunctionType fn)
 {
     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);
     }
 }
示例#9
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 TypeVar(IPythonModule declaringModule) : base(BuiltinTypeId.Type, declaringModule)
        {
            var interpreter = DeclaringModule.Interpreter;

            var fn = new PythonFunctionType("__init__", new Location(declaringModule), this, "TypeVar");
            var o  = new PythonFunctionOverload(fn, new Location(DeclaringModule));

            var boolType = interpreter.GetBuiltinType(BuiltinTypeId.Bool);

            o.SetParameters(new List <ParameterInfo> {
                new ParameterInfo("self", this, ParameterKind.Normal, this),
                new ParameterInfo("name", interpreter.GetBuiltinType(BuiltinTypeId.Str), ParameterKind.Normal, null),
                new ParameterInfo("constraints", interpreter.GetBuiltinType(BuiltinTypeId.Str), ParameterKind.List, null),
                new ParameterInfo("bound", interpreter.GetBuiltinType(BuiltinTypeId.Type), ParameterKind.KeywordOnly, new PythonConstant(null, interpreter.GetBuiltinType(BuiltinTypeId.None))),
                new ParameterInfo("covariant", boolType, ParameterKind.KeywordOnly, new PythonConstant(false, boolType)),
                new ParameterInfo("contravariant", boolType, ParameterKind.KeywordOnly, new PythonConstant(false, boolType))
            });
            fn.AddOverload(o);
            _constructor = fn;
        }
        public string GetSignatureString(IPythonFunctionType ft, IPythonType self, out IndexSpan[] parameterSpans, int overloadIndex = 0, string name = null)
        {
            var o = ft.Overloads[overloadIndex];

            var parameterStrings = GetFunctionParameters(ft, out var parameterNameLengths);
            var returnDoc        = o.GetReturnDocumentation(self);
            var annString        = string.IsNullOrEmpty(returnDoc) ? string.Empty : $" -> {returnDoc}";

            // Calculate parameter spans
            parameterSpans = new IndexSpan[parameterStrings.Length];
            name           = name ?? ft.Name;
            var offset = name.Length + 1;

            for (var i = 0; i < parameterStrings.Length; i++)
            {
                parameterSpans[i] = IndexSpan.FromBounds(offset, offset + parameterNameLengths[i]);
                offset           += parameterStrings[i].Length + 2; // name,<space>
            }

            var combinedParameterString = string.Join(", ", parameterStrings);

            return($"{name}({combinedParameterString}){annString}");
        }
        private IMember TryEvaluateWithArguments(IPythonFunctionType fn, IArgumentSet args)
        {
            var name    = fn.DeclaringType != null ? $"{fn.DeclaringModule.Name}.{fn.Name}" : fn.Name;
            var argHash = args
                          .Arguments
                          .Select(a => a.Name.GetHashCode() ^ 397 * (a.Value?.GetHashCode() ?? 0))
                          .Aggregate(0, (current, d) => 31 * current ^ d);
            var key = fn.DeclaringModule.Name.GetHashCode() ^ name.GetHashCode() ^ (397 * argHash);

            if (_argEvalCache.TryGetValue(key, out var result))
            {
                return(result);
            }

            var fd     = fn.FunctionDefinition;
            var module = fn.DeclaringModule;

            // Attempt to evaluate with specific arguments but prevent recursion.
            result = UnknownType;
            if (fd != null && !_callEvalStack.Contains(fd))
            {
                using (OpenScope(module, fd.Parent, out _)) {
                    _callEvalStack.Push(fd);
                    try {
                        // TODO: cache results per function + argument set?
                        var eval = new FunctionCallEvaluator(module, fd, this);
                        result = eval.EvaluateCall(args);
                    } finally {
                        _callEvalStack.Pop();
                    }
                }
            }

            _argEvalCache[key] = result;
            return(result);
        }
示例#13
0
        /// <summary>
        /// Creates set of arguments for a function call based on the call expression
        /// and the function signature. The result contains expressions
        /// for arguments, but not actual values. <see cref="Evaluate"/> on how to
        /// get values for actual parameters.
        /// </summary>
        /// <param name="fn">Function type.</param>
        /// <param name="overloadIndex">Function overload to call.</param>
        /// <param name="instance">Type instance the function is bound to. For derived classes it is different from the declared type.</param>
        /// <param name="callExpr">Call expression that invokes the function.</param>
        /// <param name="module">Module that contains the call expression.</param>
        /// <param name="eval">Evaluator that can calculate values of arguments from their respective expressions.</param>
        public ArgumentSet(IPythonFunctionType fn, int overloadIndex, IPythonInstance instance, CallExpression callExpr, IPythonModule module, IExpressionEvaluator eval)
        {
            Eval            = eval;
            OverloadIndex   = overloadIndex;
            DeclaringModule = fn.DeclaringModule;

            var overload = fn.Overloads[overloadIndex];
            var fd       = overload.FunctionDefinition;

            if (fd == null || fn.IsSpecialized)
            {
                // Typically specialized function, like TypeVar() that does not actually have AST definition.
                // Make the arguments from the call expression. If argument does not have name,
                // try using name from the function definition based on the argument position.
                _arguments = new List <Argument>();
                for (var i = 0; i < callExpr.Args.Count; i++)
                {
                    var name = callExpr.Args[i].Name;
                    if (string.IsNullOrEmpty(name))
                    {
                        name = fd != null && i < fd.Parameters.Length ? fd.Parameters[i].Name : null;
                    }
                    name = name ?? $"arg{i}";
                    var parameter = fd != null && i < fd.Parameters.Length ? fd.Parameters[i] : null;
                    _arguments.Add(new Argument(name, ParameterKind.Normal, callExpr.Args[i].Expression, null, parameter));
                }
                return;
            }

            if (callExpr == null)
            {
                // Typically invoked by specialization code without call expression in the code.
                // Caller usually does not care about arguments.
                _evaluated = true;
                return;
            }
            var callLocation = callExpr.GetLocation(module);

            // https://www.python.org/dev/peps/pep-3102/#id5
            // For each formal parameter, there is a slot which will be used to contain
            // the value of the argument assigned to that parameter. Slots which have
            // had values assigned to them are marked as 'filled'.Slots which have
            // no value assigned to them yet are considered 'empty'.

            var slots = fd.Parameters.Select(p => new Argument(p, p)).ToArray();
            // Locate sequence argument, if any
            var sa = slots.Where(s => s.Kind == ParameterKind.List).ToArray();

            if (sa.Length > 1)
            {
                // Error should have been reported at the function definition location by the parser.
                return;
            }

            var da = slots.Where(s => s.Kind == ParameterKind.Dictionary).ToArray();

            if (da.Length > 1)
            {
                // Error should have been reported at the function definition location by the parser.
                return;
            }

            _listArgument = sa.Length == 1 && sa[0].Name.Length > 0 ? new ListArg(sa[0].Name, sa[0].ValueExpression, sa[0].Location) : null;
            _dictArgument = da.Length == 1 ? new DictArg(da[0].Name, da[0].ValueExpression, da[0].Location) : null;

            // Class methods
            var formalParamIndex = 0;

            if (fn.DeclaringType != null && fn.HasClassFirstArgument() && slots.Length > 0)
            {
                slots[0].Value = instance != null?instance.GetPythonType() : fn.DeclaringType;

                formalParamIndex++;
            }

            try {
                // Positional arguments
                var callParamIndex = 0;
                for (; callParamIndex < callExpr.Args.Count; callParamIndex++, formalParamIndex++)
                {
                    var arg = callExpr.Args[callParamIndex];

                    if (!string.IsNullOrEmpty(arg.Name) && !arg.Name.StartsWithOrdinal("**"))
                    {
                        // Keyword argument. Done with positionals.
                        break;
                    }

                    if (formalParamIndex >= fd.Parameters.Length)
                    {
                        // We ran out of formal parameters and yet haven't seen
                        // any sequence or dictionary ones. This looks like an error.
                        _errors.Add(new DiagnosticsEntry(Resources.Analysis_TooManyFunctionArguments, arg.GetLocation(module).Span,
                                                         ErrorCodes.TooManyFunctionArguments, Severity.Warning, DiagnosticSource.Analysis));
                        return;
                    }

                    var formalParam = fd.Parameters[formalParamIndex];
                    if (formalParam.IsList)
                    {
                        if (string.IsNullOrEmpty(formalParam.Name))
                        {
                            // If the next unfilled slot is a vararg slot, and it does not have a name, then it is an error.
                            _errors.Add(new DiagnosticsEntry(Resources.Analysis_TooManyPositionalArgumentBeforeStar, arg.GetLocation(module).Span,
                                                             ErrorCodes.TooManyPositionalArgumentsBeforeStar, Severity.Warning, DiagnosticSource.Analysis));
                            return;
                        }

                        // If the next unfilled slot is a vararg slot then all remaining
                        // non-keyword arguments are placed into the vararg slot.
                        if (_listArgument == null)
                        {
                            _errors.Add(new DiagnosticsEntry(Resources.Analysis_TooManyFunctionArguments, arg.GetLocation(module).Span,
                                                             ErrorCodes.TooManyFunctionArguments, Severity.Warning, DiagnosticSource.Analysis));
                            return;
                        }

                        for (; callParamIndex < callExpr.Args.Count; callParamIndex++)
                        {
                            arg = callExpr.Args[callParamIndex];
                            if (!string.IsNullOrEmpty(arg.Name))
                            {
                                // Keyword argument. Done here.
                                break;
                            }

                            _listArgument._Expressions.Add(arg.Expression);
                        }

                        break; // Sequence or dictionary parameter found. Done here.
                    }

                    if (formalParam.IsDictionary)
                    {
                        // Next slot is a dictionary slot, but we have positional arguments still.
                        _errors.Add(new DiagnosticsEntry(Resources.Analysis_TooManyPositionalArgumentBeforeStar, arg.GetLocation(module).Span,
                                                         ErrorCodes.TooManyPositionalArgumentsBeforeStar, Severity.Warning, DiagnosticSource.Analysis));
                        return;
                    }

                    // Regular parameter
                    slots[formalParamIndex].ValueExpression = arg.Expression;
                }

                // Keyword arguments
                for (; callParamIndex < callExpr.Args.Count; callParamIndex++)
                {
                    var arg = callExpr.Args[callParamIndex];

                    if (string.IsNullOrEmpty(arg.Name))
                    {
                        _errors.Add(new DiagnosticsEntry(Resources.Analysis_PositionalArgumentAfterKeyword, arg.GetLocation(module).Span,
                                                         ErrorCodes.PositionalArgumentAfterKeyword, Severity.Warning, DiagnosticSource.Analysis));
                        return;
                    }

                    var nvp = slots.FirstOrDefault(s => s.Name.EqualsOrdinal(arg.Name));
                    if (nvp == null)
                    {
                        // 'def f(a, b)' and then 'f(0, c=1)'. Per spec:
                        // if there is a 'keyword dictionary' argument, the argument is added
                        // to the dictionary using the keyword name as the dictionary key,
                        // unless there is already an entry with that key, in which case it is an error.
                        if (_dictArgument == null)
                        {
                            _errors.Add(new DiagnosticsEntry(Resources.Analysis_UnknownParameterName, arg.GetLocation(module).Span,
                                                             ErrorCodes.UnknownParameterName, Severity.Warning, DiagnosticSource.Analysis));
                            return;
                        }

                        if (_dictArgument.Arguments.ContainsKey(arg.Name))
                        {
                            _errors.Add(new DiagnosticsEntry(Resources.Analysis_ParameterAlreadySpecified.FormatUI(arg.Name), arg.GetLocation(module).Span,
                                                             ErrorCodes.ParameterAlreadySpecified, Severity.Warning, DiagnosticSource.Analysis));
                            return;
                        }

                        _dictArgument._Expressions[arg.Name] = arg.Expression;
                        continue;
                    }

                    if (nvp.ValueExpression != null || nvp.Value != null)
                    {
                        // Slot is already filled.
                        _errors.Add(new DiagnosticsEntry(Resources.Analysis_ParameterAlreadySpecified.FormatUI(arg.Name), arg.GetLocation(module).Span,
                                                         ErrorCodes.ParameterAlreadySpecified, Severity.Warning, DiagnosticSource.Analysis));
                        return;
                    }

                    // OK keyword parameter
                    nvp.ValueExpression = arg.Expression;
                }

                // We went through all positionals and keywords.
                // For each remaining empty slot: if there is a default value for that slot,
                // then fill the slot with the default value. If there is no default value,
                // then it is an error.
                foreach (var slot in slots.Where(s => s.Kind != ParameterKind.List && s.Kind != ParameterKind.Dictionary && s.Value == null))
                {
                    if (slot.ValueExpression == null)
                    {
                        var parameter = fd.Parameters.First(p => p.Name == slot.Name);
                        if (parameter.DefaultValue == null)
                        {
                            // TODO: parameter is not assigned and has no default value.
                            _errors.Add(new DiagnosticsEntry(Resources.Analysis_ParameterMissing.FormatUI(slot.Name), callLocation.Span,
                                                             ErrorCodes.ParameterMissing, Severity.Warning, DiagnosticSource.Analysis));
                        }
                        // Note that parameter default value expression is from the function definition AST
                        // while actual argument values are from the calling file AST.
                        slot.ValueExpression = parameter.DefaultValue;
                        slot.ValueIsDefault  = true;
                    }
                }
            } finally {
                // Optimistically return what we gathered, even if there are errors.
                _arguments = slots.Where(s => s.Kind != ParameterKind.List && s.Kind != ParameterKind.Dictionary).ToList();
            }
        }
示例#14
0
 public ArgumentSet(IPythonFunctionType fn, int overloadIndex, IPythonInstance instance, CallExpression callExpr, ExpressionEval eval) :
     this(fn, overloadIndex, instance, callExpr, eval.Module, eval)
 {
 }
示例#15
0
 public PythonInstanceIterator(IMember instance, IPythonInterpreter interpreter)
     : base(new PythonIteratorType(BuiltinTypeId.SetIterator, interpreter))
 {
     __next__ = instance.GetPythonType().GetMember(@"__next__") as IPythonFunctionType;
 }
 private bool EvaluateFunctionBody(IPythonFunctionType fn)
 => fn.DeclaringModule.ModuleType != ModuleType.Library;
示例#17
0
 public static bool IsLambda(this IPythonFunctionType f) => f.Name == "<lambda>";
 public string GetSignatureString(IPythonFunctionType ft, IPythonType self, out (IndexSpan, IParameterInfo)[] parameterSpans, int overloadIndex = 0, string funcName = null, bool noReturn = false)
        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);
        }
示例#20
0
 public PythonUnboundMethod(IPythonFunctionType function) : base(function, function.DeclaringModule)
 {
     Function = function;
 }
示例#21
0
 public static PythonFunctionAssertions Should(this IPythonFunctionType f) => new PythonFunctionAssertions(f);
示例#22
0
        private static FunctionModel GetFunctionModel(IDocumentAnalysis analysis, IVariable v, IPythonFunctionType f)
        {
            if (v.Source == VariableSource.Import && !f.DeclaringModule.Equals(analysis.Document) && !f.DeclaringModule.Equals(analysis.Document.Stub))
            {
                // It may be that the function is from a child module via import.
                // For example, a number of functions in 'os' are imported from 'nt' on Windows via
                // star import. Their stubs, however, come from 'os' stub. The function then have declaring
                // module as 'nt' rather than 'os' and 'nt' does not have a stub. In this case use function
                // model like if function was declared in 'os'.
                return(new FunctionModel(f));
            }

            if (f.DeclaringModule.Equals(analysis.Document) || f.DeclaringModule.Equals(analysis.Document.Stub))
            {
                return(new FunctionModel(f));
            }
            return(null);
        }
示例#23
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);
        }
示例#24
0
 public static bool IsBound(this IPythonFunctionType f)
 => f.DeclaringType != null && f.MemberType == PythonMemberType.Method;
        }                          // For de-serializer from JSON

        public FunctionModel(IPythonFunctionType func, IServiceContainer services) : base(func, services)
        {
            Overloads = func.Overloads.Select(s => FromOverload(s, services)).ToArray();
        }
示例#26
0
 public FunctionModel(IPythonFunctionType func) : base(func)
 {
     Overloads = func.Overloads.Select(FromOverload).ToArray();
 }
示例#27
0
 public static IDisposable OpenScope(this IExpressionEvaluator eval, IPythonFunctionType ft)
 => eval.OpenScope(ft.DeclaringModule, ft.FunctionDefinition);