Beispiel #1
0
        private IPythonType TryDetermineReturnValue()
        {
            var annotationType = Eval.GetTypeFromAnnotation(FunctionDefinition.ReturnAnnotation);

            if (!annotationType.IsUnknown())
            {
                // Annotations are typically types while actually functions return
                // instances unless specifically annotated to a type such as Type[T].
                // TODO: try constructing argument set from types. Consider Tuple[_T1, _T2] where _T1 = TypeVar('_T1', str, bytes)
                var t = annotationType.CreateInstance(ArgumentSet.Empty(FunctionDefinition.ReturnAnnotation, Eval));
                // If instance could not be created, such as when return type is List[T] and
                // type of T is not yet known, just use the type.
                var instance = t.IsUnknown() ? (IMember)annotationType : t;
                _overload.SetReturnValue(instance, true); _overload.SetReturnValue(instance, true);
            }
            else
            {
                // Check if function is a generator
                var suite     = FunctionDefinition.Body as SuiteStatement;
                var yieldExpr = suite?.Statements.OfType <ExpressionStatement>().Select(s => s.Expression as YieldExpression).ExcludeDefault().FirstOrDefault();
                if (yieldExpr != null)
                {
                    // Function return is an iterator
                    var yieldValue  = Eval.GetValueFromExpression(yieldExpr.Expression) ?? Eval.UnknownType;
                    var returnValue = new PythonGenerator(Eval.Interpreter, yieldValue);
                    _overload.SetReturnValue(returnValue, true);
                }
            }
            return(annotationType);
        }
        private void TryAddBase(List <IPythonType> bases, Arg arg)
        {
            // We cheat slightly and treat base classes as annotations.
            var b = Eval.GetTypeFromAnnotation(arg.Expression);

            if (b != null)
            {
                var t = b.GetPythonType();
                bases.Add(t);
                t.AddReference(Eval.GetLocationOfName(arg.Expression));
            }
        }
Beispiel #3
0
        public override void Evaluate()
        {
            var stub = SymbolTable.ReplacedByStubs.Contains(Target) ||
                       _function.DeclaringModule.ModuleType == ModuleType.Stub ||
                       Module.ModuleType == ModuleType.Specialized;

            using (Eval.OpenScope(_function.DeclaringModule, FunctionDefinition, out _)) {
                // Process annotations.
                var annotationType = Eval.GetTypeFromAnnotation(FunctionDefinition.ReturnAnnotation);
                if (!annotationType.IsUnknown())
                {
                    // Annotations are typically types while actually functions return
                    // instances unless specifically annotated to a type such as Type[T].
                    var instance = annotationType.CreateInstance(annotationType.Name, ArgumentSet.Empty);
                    _overload.SetReturnValue(instance, true);
                }
                else
                {
                    // Check if function is a generator
                    var suite     = FunctionDefinition.Body as SuiteStatement;
                    var yieldExpr = suite?.Statements.OfType <ExpressionStatement>().Select(s => s.Expression as YieldExpression).ExcludeDefault().FirstOrDefault();
                    if (yieldExpr != null)
                    {
                        // Function return is an iterator
                        var yieldValue  = Eval.GetValueFromExpression(yieldExpr.Expression) ?? Eval.UnknownType;
                        var returnValue = new PythonGenerator(Eval.Interpreter, yieldValue);
                        _overload.SetReturnValue(returnValue, true);
                    }
                }

                DeclareParameters(!stub);

                // Do process body of constructors since they may be declaring
                // variables that are later used to determine return type of other
                // methods and properties.
                var ctor = _function.Name.EqualsOrdinal("__init__") || _function.Name.EqualsOrdinal("__new__");
                if (ctor || annotationType.IsUnknown() || Module.ModuleType == ModuleType.User)
                {
                    // Return type from the annotation is sufficient for libraries and stubs, no need to walk the body.
                    FunctionDefinition.Body?.Walk(this);
                    // For libraries remove declared local function variables to free up some memory.
                    var optionsProvider = Eval.Services.GetService <IAnalysisOptionsProvider>();
                    if (Module.ModuleType != ModuleType.User && optionsProvider?.Options.KeepLibraryLocalVariables != true)
                    {
                        ((VariableCollection)Eval.CurrentScope.Variables).Clear();
                    }
                }
            }
            Result = _function;
        }
        public void HandleAnnotatedExpression(ExpressionWithAnnotation expr, IMember value)
        {
            if (expr?.Annotation == null)
            {
                return;
            }

            var variableType = Eval.GetTypeFromAnnotation(expr.Annotation);

            // If value is null, then this is a pure declaration like
            //   x: List[str]
            // without a value. If value is provided, then this is
            //   x: List[str] = [...]
            HandleTypedVariable(variableType, value, expr.Expression);
        }
        public void EvaluateClass()
        {
            // Open class scope chain
            using (Eval.OpenScope(Module, _classDef, out var outerScope)) {
                var instance = Eval.GetInScope(_classDef.Name, outerScope);
                if (!(instance?.GetPythonType() is PythonClassType classInfo))
                {
                    if (instance != null)
                    {
                        // TODO: warning that variable is already declared of a different type.
                    }
                    return;
                }

                // Evaluate inner classes, if any
                EvaluateInnerClasses(_classDef);

                _class = classInfo;
                // Set bases to the class.
                var bases = new List <IPythonType>();
                foreach (var a in _classDef.Bases.Where(a => string.IsNullOrEmpty(a.Name)))
                {
                    // We cheat slightly and treat base classes as annotations.
                    var b = Eval.GetTypeFromAnnotation(a.Expression);
                    if (b != null)
                    {
                        var t = b.GetPythonType();
                        bases.Add(t);
                        t.AddReference(Eval.GetLocationOfName(a.Expression));
                    }
                }
                _class.SetBases(bases);

                // Declare __class__ variable in the scope.
                Eval.DeclareVariable("__class__", _class, VariableSource.Declaration);

                ProcessClassBody();
            }
        }
Beispiel #6
0
        private void DeclareParameters(bool declareVariables)
        {
            // For class method no need to add extra parameters, but first parameter type should be the class.
            // For static and unbound methods do not add or set anything.
            // For regular bound methods add first parameter and set it to the class.

            var parameters = new List <ParameterInfo>();
            var skip       = 0;

            if (_self != null && _function.HasClassFirstArgument())
            {
                var p0 = FunctionDefinition.Parameters.FirstOrDefault();
                if (p0 != null && !string.IsNullOrEmpty(p0.Name))
                {
                    // Actual parameter type will be determined when method is invoked.
                    // The reason is that if method might be called on a derived class.
                    // Declare self or cls in this scope.
                    if (declareVariables)
                    {
                        Eval.DeclareVariable(p0.Name, new PythonInstance(_self), VariableSource.Declaration, p0.NameExpression);
                    }
                    // Set parameter info.
                    var pi = new ParameterInfo(Ast, p0, _self, null, false);
                    parameters.Add(pi);
                    skip++;
                }
            }

            // Declare parameters in scope
            IMember defaultValue = null;

            for (var i = skip; i < FunctionDefinition.Parameters.Length; i++)
            {
                var isGeneric = false;
                var p         = FunctionDefinition.Parameters[i];
                if (!string.IsNullOrEmpty(p.Name))
                {
                    IPythonType paramType = null;
                    if (p.DefaultValue != null)
                    {
                        defaultValue = Eval.GetValueFromExpression(p.DefaultValue);
                        // If parameter has default value, look for the annotation locally first
                        // since outer type may be getting redefined. Consider 's = None; def f(s: s = 123): ...
                        paramType = Eval.GetTypeFromAnnotation(p.Annotation, out isGeneric, LookupOptions.Local | LookupOptions.Builtins);
                        // Default value of None does not mean the parameter is None, just says it can be missing.
                        defaultValue = defaultValue.IsUnknown() || defaultValue.IsOfType(BuiltinTypeId.NoneType) ? null : defaultValue;
                        if (paramType == null && defaultValue != null)
                        {
                            paramType = defaultValue.GetPythonType();
                        }
                    }
                    // If all else fails, look up globally.
                    paramType = paramType ?? Eval.GetTypeFromAnnotation(p.Annotation, out isGeneric) ?? Eval.UnknownType;
                    var pi = new ParameterInfo(Ast, p, paramType, defaultValue, isGeneric);
                    if (declareVariables)
                    {
                        DeclareParameter(p, pi);
                    }
                    parameters.Add(pi);
                }
            }
            _overload.SetParameters(parameters);
        }