Пример #1
0
        public override IMember GetMember(string name)
        {
            lock (MembersLock) {
                if (Members.TryGetValue(name, out var member))
                {
                    return(member);
                }
            }

            // Special case names that we want to add to our own Members dict
            var is3x = DeclaringModule.Interpreter.LanguageVersion.Is3x();

            switch (name)
            {
            case "__mro__":
            case "mro":
                return(is3x ? PythonCollectionType.CreateList(DeclaringModule, Mro) : UnknownType as IMember);

            case "__dict__":
                return(is3x ? DeclaringModule.Interpreter.GetBuiltinType(BuiltinTypeId.Dict) : UnknownType);

            case @"__weakref__":
                return(is3x ? DeclaringModule.Interpreter.GetBuiltinType(BuiltinTypeId.Object) : UnknownType);
            }

            using (_memberGuard.Push(this, out var reentered)) {
                if (!reentered)
                {
                    return(Mro.Skip(1).Select(c => c.GetMember(name)).ExcludeDefault().FirstOrDefault());
                }
                return(null);
            }
        }
Пример #2
0
        public override IMember GetMember(string name)
        {
            IMember member;

            lock (_lock) {
                if (Members.TryGetValue(name, out member))
                {
                    return(member);
                }

                // Special case names that we want to add to our own Members dict
                switch (name)
                {
                case "__mro__":
                    member = AddMember(name, PythonCollectionType.CreateList(DeclaringModule.Interpreter, LocationInfo.Empty, Mro), true);
                    return(member);
                }
            }
            if (Push())
            {
                try {
                    foreach (var m in Mro.Reverse())
                    {
                        if (m == this)
                        {
                            return(member);
                        }
                        member = member ?? m.GetMember(name);
                    }
                } finally {
                    Pop();
                }
            }
            return(null);
        }
Пример #3
0
        // Constructor call
        public override IMember CreateInstance(IArgumentSet args)
        {
            var builtins = DeclaringModule.Interpreter.ModuleResolution.BuiltinsModule;

            // Specializations
            switch (Name)
            {
            case "list":
                return(PythonCollectionType.CreateList(builtins, args));

            case "dict": {
                // self, then contents
                var contents = args.Values <IMember>().Skip(1).FirstOrDefault();
                return(new PythonDictionary(builtins, contents));
            }

            case "tuple": {
                var contents = args.Values <IMember>();
                return(PythonCollectionType.CreateTuple(builtins, contents));
            }
            }

            // Metaclasses return type, not instance.
            if (Bases.MaybeEnumerate().Any(b => b.Name == "type" && b.DeclaringModule.ModuleType == ModuleType.Builtins))
            {
                return(this);
            }

            return(new PythonInstance(this));
        }
Пример #4
0
        internal static void DeclareParametersInScope(this IArgumentSet args, ExpressionEval eval)
        {
            if (eval == null)
            {
                return;
            }

            // 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.

            foreach (var a in args.Arguments)
            {
                if (a.Value is IMember m && !string.IsNullOrEmpty(a.Name))
                {
                    eval.DeclareVariable(a.Name, m, VariableSource.Declaration, a.Location);
                }
            }

            if (args.ListArgument != null && !string.IsNullOrEmpty(args.ListArgument.Name))
            {
                var type = new PythonCollectionType(null, BuiltinTypeId.List, eval.Interpreter, false);
                var list = new PythonCollection(type, args.ListArgument.Values);
                eval.DeclareVariable(args.ListArgument.Name, list, VariableSource.Declaration, args.ListArgument.Location);
            }

            if (args.DictionaryArgument != null)
            {
                foreach (var kvp in args.DictionaryArgument.Arguments)
                {
                    eval.DeclareVariable(kvp.Key, kvp.Value, VariableSource.Declaration, args.DictionaryArgument.Location);
                }
            }
        }
        private IMember GetValueFromTuple(TupleExpression expression)
        {
            var contents = new List <IMember>();

            foreach (var item in expression.Items)
            {
                var value = GetValueFromExpression(item) ?? UnknownType;
                contents.Add(value);
            }
            return(PythonCollectionType.CreateTuple(Module.Interpreter, GetLoc(expression), contents));
        }
        public IMember GetValueFromSet(SetExpression expression)
        {
            var contents = new List <IMember>();

            foreach (var item in expression.Items)
            {
                var value = GetValueFromExpression(item) ?? UnknownType;
                contents.Add(value);
            }
            return(PythonCollectionType.CreateSet(Interpreter, GetLoc(expression), contents));
        }
Пример #7
0
        public IMember GetValueFromSet(SetExpression expression)
        {
            var contents = new List <IMember>();

            foreach (var item in expression.Items.Take(MaxCollectionSize))
            {
                var value = GetValueFromExpression(item) ?? UnknownType;
                contents.Add(value);
            }
            return(PythonCollectionType.CreateSet(Interpreter, contents, exact: expression.Items.Count <= MaxCollectionSize));
        }
        public static IMember Range(IPythonModule module, IPythonFunctionOverload overload, LocationInfo location, IArgumentSet argSet)
        {
            var args = argSet.Values <IMember>();

            if (args.Count > 0)
            {
                var type = new PythonCollectionType(null, BuiltinTypeId.List, module.Interpreter, false);
                return(new PythonCollection(type, location, new[] { args[0] }));
            }
            return(null);
        }
        public static IMember Range(IPythonModule module, IPythonFunctionOverload overload, IArgumentSet argSet, IndexSpan indexSpan)
        {
            var args = argSet.Values <IMember>();

            if (args.Count > 0)
            {
                var type = new PythonCollectionType(BuiltinTypeId.List, module.Interpreter.ModuleResolution.BuiltinsModule, false);
                return(new PythonCollection(type, new[] { args[0] }));
            }
            return(null);
        }
Пример #10
0
        public IMember GetValueFromList(ListExpression expression, LookupOptions lookupOptions = LookupOptions.Normal)
        {
            var contents = new List <IMember>();

            foreach (var item in expression.Items.Take(MaxCollectionSize))
            {
                var value = GetValueFromExpression(item, lookupOptions) ?? UnknownType;
                contents.Add(value);
            }
            return(PythonCollectionType.CreateList(Module, contents, exact: expression.Items.Count <= MaxCollectionSize));
        }
Пример #11
0
        private IMember GetValueFromTuple(TupleExpression expression)
        {
            var contents = new List <IMember>();

            foreach (var item in expression.Items.Take(MaxCollectionSize))
            {
                var value = GetValueFromExpression(item) ?? UnknownType;
                contents.Add(value);
            }
            return(PythonCollectionType.CreateTuple(Module, contents, exact: expression.Items.Count <= MaxCollectionSize));
        }
        private async Task <IMember> GetValueFromTupleAsync(TupleExpression expression, CancellationToken cancellationToken = default)
        {
            var contents = new List <IMember>();

            foreach (var item in expression.Items)
            {
                var value = await GetValueFromExpressionAsync(item, cancellationToken) ?? UnknownType;

                contents.Add(value);
            }
            return(PythonCollectionType.CreateTuple(Module.Interpreter, GetLoc(expression), contents));
        }
Пример #13
0
        private void HandleAllAppendExtend(CallExpression node)
        {
            if (!(node.Target is MemberExpression me))
            {
                return;
            }

            if (!IsHandleableAll(me.Target))
            {
                return;
            }

            if (node.Args.Count == 0)
            {
                return;
            }

            var arg = node.Args[0].Expression;
            var v   = Eval.GetValueFromExpression(arg);

            if (v == null)
            {
                _allIsUsable = false;
                return;
            }

            IPythonCollection values = null;

            switch (me.Name)
            {
            case "append":
                values = PythonCollectionType.CreateList(Module.Interpreter, Eval.GetLoc(arg), new List <IMember>()
                {
                    v
                }, exact: true);
                break;

            case "extend":
                values = v as IPythonCollection;
                break;
            }

            if (values == null)
            {
                _allIsUsable = false;
                return;
            }

            ExtendAll(node, values);
        }
Пример #14
0
        private void ExtendAll(Node location, IPythonCollection values)
        {
            Eval.LookupNameInScopes(AllVariableName, out var scope, LookupOptions.Global);
            if (scope == null)
            {
                return;
            }

            var all    = scope.Variables[AllVariableName]?.Value as IPythonCollection;
            var list   = PythonCollectionType.CreateConcatenatedList(Module.Interpreter, all, values);
            var source = list.IsGeneric() ? VariableSource.Generic : VariableSource.Declaration;

            Eval.DeclareVariable(AllVariableName, list, source, location);
        }
Пример #15
0
        private IEnumerable <IPythonType> CreateBases(ClassModel cm, ModuleFactory mf, IGlobalScope gs)
        {
            var ntBases = cm.NamedTupleBases
                          .Select(ntb => MemberFactory.CreateMember(ntb, ModuleFactory, GlobalScope, _cls))
                          .OfType <IPythonType>()
                          .ToArray();

            var is3x       = mf.Module.Interpreter.LanguageVersion.Is3x();
            var basesNames = cm.Bases.Select(b => is3x && b == "object" ? null : b).ExcludeDefault().ToArray();
            var bases      = basesNames.Select(mf.ConstructType).ExcludeDefault().Concat(ntBases).ToArray();

            // Make sure base types are realized
            foreach (var b in bases.OfType <PythonLazyClassType>())
            {
                b.EnsureContent();
            }

            if (cm.GenericBaseParameters.Length > 0)
            {
                // Generic class. Need to reconstruct generic base so code can then
                // create specific types off the generic class.
                var genericBase = bases.OfType <IGenericType>().FirstOrDefault(b => b.Name == "Generic");
                if (genericBase != null)
                {
                    var typeVars = cm.GenericBaseParameters.Select(n => gs.Variables[n]?.Value).OfType <IGenericTypeParameter>().ToArray();
                    //Debug.Assert(typeVars.Length > 0, "Class generic type parameters were not defined in the module during restore");
                    if (typeVars.Length > 0)
                    {
                        var genericWithParameters = genericBase.CreateSpecificType(new ArgumentSet(typeVars, null, null));
                        if (genericWithParameters != null)
                        {
                            bases = bases.Except(Enumerable.Repeat(genericBase, 1)).Concat(Enumerable.Repeat(genericWithParameters, 1)).ToArray();
                        }
                    }
                }
                else
                {
                    Debug.Fail("Generic class does not have generic base.");
                }
            }

            if (bases.Length > 0)
            {
                _cls.AddMember("__base__", bases[0], true);
            }
            _cls.AddMember("__bases__", PythonCollectionType.CreateList(DeclaringModule.Interpreter.ModuleResolution.BuiltinsModule, bases), true);
            return(bases);
        }
Пример #16
0
        private void ExtendAll(Node declNode, IReadOnlyList <IMember> values)
        {
            Eval.LookupNameInScopes(AllVariableName, out var scope, LookupOptions.Normal);
            if (scope == null)
            {
                return;
            }

            var loc = Eval.GetLoc(declNode);

            var allContents = (scope.Variables[AllVariableName].Value as IPythonCollection)?.Contents;

            var list   = PythonCollectionType.CreateConcatenatedList(Module.Interpreter, loc, allContents, values);
            var source = list.IsGeneric() ? VariableSource.Generic : VariableSource.Declaration;

            Eval.DeclareVariable(AllVariableName, list, source, loc);
        }
        public override IMember GetMember(string name)
        {
            IMember member;

            lock (_lock) {
                if (Members.TryGetValue(name, out member))
                {
                    return(member);
                }

                // Special case names that we want to add to our own Members dict
                var is3x = DeclaringModule.Interpreter.LanguageVersion.Is3x();
                switch (name)
                {
                case "__mro__":
                case "mro":
                    return(is3x ? PythonCollectionType.CreateList(DeclaringModule.Interpreter, LocationInfo.Empty, Mro) : UnknownType);

                case "__dict__":
                    return(is3x ? DeclaringModule.Interpreter.GetBuiltinType(BuiltinTypeId.Dict) : UnknownType);

                case @"__weakref__":
                    return(is3x ? DeclaringModule.Interpreter.GetBuiltinType(BuiltinTypeId.Object) : UnknownType);
                }
            }
            if (Push(this))
            {
                try {
                    foreach (var m in Mro.Reverse())
                    {
                        if (m == this)
                        {
                            return(member);
                        }
                        member = member ?? m.GetMember(name);
                    }
                } finally {
                    Pop();
                }
            }
            return(null);
        }
Пример #18
0
        /// <summary>
        /// Sets class bases. If scope is provided, detects loops in base classes and removes them.
        /// </summary>
        /// <param name="bases">List of base types.</param>
        /// <param name="currentScope">Current scope to look up base types.
        /// Can be null if class is restored from database, in which case
        /// there is no need to try and disambiguate bases.</param>
        internal void SetBases(IEnumerable <IPythonType> bases, IScope currentScope = null)
        {
            if (_bases != null)
            {
                return; // Already set
            }

            // Consider
            //    from X import A
            //    class A(A): ...
            bases = DisambiguateBases(bases, currentScope).ToArray();

            // For Python 3+ attach object as a base class by default except for the object class itself.
            if (DeclaringModule.Interpreter.LanguageVersion.Is3x() && DeclaringModule.ModuleType != ModuleType.Builtins)
            {
                var objectType = DeclaringModule.Interpreter.GetBuiltinType(BuiltinTypeId.Object);
                // During processing of builtins module some types may not be available yet.
                // Specialization will attach proper base at the end.
                Debug.Assert(!objectType.IsUnknown());
                if (!bases.Any(b => objectType.Equals(b)))
                {
                    bases = bases.Concat(Enumerable.Repeat(objectType, 1));
                }
            }

            _bases = bases.ToList();
            if (_bases.Count > 0)
            {
                AddMember("__base__", _bases[0], true);
            }
            // Invalidate MRO
            _mro = null;
            DecideGeneric();

            if (DeclaringModule is BuiltinsPythonModule)
            {
                // TODO: If necessary, we can set __bases__ on builtins when the module is fully analyzed.
                return;
            }

            AddMember("__bases__", PythonCollectionType.CreateList(DeclaringModule.Interpreter.ModuleResolution.BuiltinsModule, _bases), true);
        }
Пример #19
0
        public IMember GetValueFromComprehension(Comprehension node)
        {
            var oldVariables = CurrentScope.Variables.OfType <Variable>().ToDictionary(k => k.Name, v => v);

            try {
                ProcessComprehension(node);

                // TODO: Evaluate comprehensions to produce exact contents, if possible.
                switch (node)
                {
                case ListComprehension lc:
                    var v1 = GetValueFromExpression(lc.Item) ?? UnknownType;
                    return(PythonCollectionType.CreateList(Module, new[] { v1 }));

                case SetComprehension sc:
                    var v2 = GetValueFromExpression(sc.Item) ?? UnknownType;
                    return(PythonCollectionType.CreateSet(Module, new[] { v2 }));

                case DictionaryComprehension dc:
                    var k = GetValueFromExpression(dc.Key) ?? UnknownType;
                    var v = GetValueFromExpression(dc.Value) ?? UnknownType;
                    return(new PythonDictionary(new PythonDictionaryType(Interpreter.ModuleResolution.BuiltinsModule), new Dictionary <IMember, IMember> {
                        { k, v }
                    }));
                }

                return(UnknownType);
            } finally {
                // Remove temporary variables since this is assignment and the right hand
                // side comprehension does not leak internal variables into the scope.
                var newVariables = CurrentScope.Variables.ToDictionary(k => k.Name, v => v);
                var variables    = (VariableCollection)CurrentScope.Variables;
                foreach (var kvp in newVariables)
                {
                    if (!oldVariables.ContainsKey(kvp.Key))
                    {
                        variables.RemoveVariable(kvp.Key);
                    }
                }
            }
        }
Пример #20
0
        internal void SetBases(IPythonInterpreter interpreter, IEnumerable <IPythonType> bases)
        {
            lock (_lock) {
                if (Bases != null)
                {
                    return; // Already set
                }

                Bases = bases.MaybeEnumerate().ToArray();
                if (Bases.Count > 0)
                {
                    AddMember("__base__", Bases[0], true);
                }

                if (!(DeclaringModule is BuiltinsPythonModule))
                {
                    // TODO: If necessary, we can set __bases__ on builtins when the module is fully analyzed.
                    AddMember("__bases__", PythonCollectionType.CreateList(DeclaringModule.Interpreter, LocationInfo.Empty, Bases), true);
                }
            }
        }
        // Constructor call
        public override IMember CreateInstance(string typeName, IArgumentSet args)
        {
            // Specializations
            switch (typeName)
            {
            case "list":
                return(PythonCollectionType.CreateList(DeclaringModule.Interpreter, args));

            case "dict": {
                // self, then contents
                var contents = args.Values <IMember>().Skip(1).FirstOrDefault();
                return(new PythonDictionary(DeclaringModule.Interpreter, contents));
            }

            case "tuple": {
                var contents = args.Values <IMember>();
                return(PythonCollectionType.CreateTuple(DeclaringModule.Interpreter, contents));
            }
            }
            return(new PythonInstance(this));
        }
        internal void SetBases(IEnumerable <IPythonType> bases)
        {
            lock (_lock) {
                if (_bases != null)
                {
                    return; // Already set
                }

                bases = bases != null?bases.Where(b => !b.GetPythonType().IsUnknown()).ToArray() : Array.Empty <IPythonType>();

                // For Python 3+ attach object as a base class by default except for the object class itself.
                if (DeclaringModule.Interpreter.LanguageVersion.Is3x() && DeclaringModule.ModuleType != ModuleType.Builtins)
                {
                    var objectType = DeclaringModule.Interpreter.GetBuiltinType(BuiltinTypeId.Object);
                    // During processing of builtins module some types may not be available yet.
                    // Specialization will attach proper base at the end.
                    Debug.Assert(!objectType.IsUnknown());
                    if (!bases.Any(b => objectType.Equals(b)))
                    {
                        bases = bases.Concat(Enumerable.Repeat(objectType, 1));
                    }
                }

                _bases = bases.ToList();
                if (_bases.Count > 0)
                {
                    AddMember("__base__", _bases[0], true);
                }
                // Invalidate MRO
                _mro = null;
                if (DeclaringModule is BuiltinsPythonModule)
                {
                    // TODO: If necessary, we can set __bases__ on builtins when the module is fully analyzed.
                    return;
                }

                AddMember("__bases__", PythonCollectionType.CreateList(DeclaringModule.Interpreter, LocationInfo.Empty, _bases), true);
            }
        }
        public override IMember GetMember(string name)
        {
            // Push/Pop should be lock protected.
            if (Members.TryGetValue(name, out var member))
            {
                return(member);
            }

            // Special case names that we want to add to our own Members dict
            var is3x = DeclaringModule.Interpreter.LanguageVersion.Is3x();

            switch (name)
            {
            case "__mro__":
            case "mro":
                return(is3x ? PythonCollectionType.CreateList(DeclaringModule.Interpreter, Mro) : UnknownType as IMember);

            case "__dict__":
                return(is3x ? DeclaringModule.Interpreter.GetBuiltinType(BuiltinTypeId.Dict) : UnknownType);

            case @"__weakref__":
                return(is3x ? DeclaringModule.Interpreter.GetBuiltinType(BuiltinTypeId.Object) : UnknownType);
            }

            using (_memberGuard.Push(this, out var reentered)) {
                if (!reentered)
                {
                    foreach (var m in Mro.Reverse())
                    {
                        if (m == this)
                        {
                            return(member);
                        }
                        member = member ?? m.GetMember(name);
                    }
                }
                return(null);
            }
        }
Пример #24
0
        // Constructor call
        public override IPythonInstance CreateInstance(IArgumentSet args)
        {
            var builtins = DeclaringModule.Interpreter.ModuleResolution.BuiltinsModule;

            // Specializations
            switch (Name)
            {
            case "list":
                return(PythonCollectionType.CreateList(builtins, args));

            case "dict": {
                // self, then contents
                var contents = args.Values <IMember>().Skip(1).FirstOrDefault();
                return(new PythonDictionary(builtins, contents));
            }

            case "tuple": {
                var contents = args.Values <IMember>();
                return(PythonCollectionType.CreateTuple(builtins, contents));
            }
            }
            return(new PythonInstance(this));
        }
Пример #25
0
 public static IMember List(IPythonInterpreter interpreter, IPythonFunctionOverload overload, LocationInfo location, IReadOnlyList <IMember> args)
 => PythonCollectionType.CreateList(interpreter, location, args);
Пример #26
0
        private IMember GetValueFromBinaryOp(Expression expr)
        {
            if (expr is AndExpression)
            {
                return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));
            }

            if (expr is OrExpression orexp)
            {
                // Consider 'self.__params = types.MappingProxyType(params or {})'
                var leftSide = GetValueFromExpression(orexp.Left);
                if (!leftSide.IsUnknown())
                {
                    return(leftSide);
                }
                var rightSide = GetValueFromExpression(orexp.Right);
                return(rightSide.IsUnknown() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : rightSide);
            }

            if (!(expr is BinaryExpression binop) || binop.Left == null)
            {
                return(null);
            }

            // TODO: Specific parsing
            // TODO: warn about incompatible types like 'str' + 1
            switch (binop.Operator)
            {
            case PythonOperator.Equal:
            case PythonOperator.GreaterThan:
            case PythonOperator.GreaterThanOrEqual:
            case PythonOperator.In:
            case PythonOperator.Is:
            case PythonOperator.IsNot:
            case PythonOperator.LessThan:
            case PythonOperator.LessThanOrEqual:
            case PythonOperator.Not:
            case PythonOperator.NotEqual:
            case PythonOperator.NotIn:
                // Assume all of these return True/False
                return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));

            case PythonOperator.Divide:
            case PythonOperator.TrueDivide:
                if (Interpreter.LanguageVersion.Is3x())
                {
                    return(Interpreter.GetBuiltinType(BuiltinTypeId.Float));
                }

                break;
            }

            var left  = GetValueFromExpression(binop.Left) ?? UnknownType;
            var right = GetValueFromExpression(binop.Right) ?? UnknownType;


            var rightType = right.GetPythonType();

            if (rightType?.TypeId == BuiltinTypeId.Float)
            {
                return(right);
            }

            var leftType = left.GetPythonType();

            if (leftType?.TypeId == BuiltinTypeId.Float)
            {
                return(left);
            }

            if (rightType?.TypeId == BuiltinTypeId.Long)
            {
                return(right);
            }

            if (leftType?.TypeId == BuiltinTypeId.Long)
            {
                return(left);
            }

            if (binop.Operator == PythonOperator.Add &&
                leftType?.TypeId == BuiltinTypeId.List && rightType?.TypeId == BuiltinTypeId.List &&
                left is IPythonCollection lc && right is IPythonCollection rc)
            {
                return(PythonCollectionType.CreateConcatenatedList(Module.Interpreter, GetLoc(expr), lc, rc));
            }

            return(left.IsUnknown() ? right : left);
        }
 public static IMember List(IPythonInterpreter interpreter, IPythonFunctionOverload overload, LocationInfo location, IArgumentSet argSet)
 => PythonCollectionType.CreateList(interpreter, location, argSet);
 public static IMember List(IPythonInterpreter interpreter, IPythonFunctionOverload overload, IArgumentSet argSet, IndexSpan indexSpan)
 => PythonCollectionType.CreateList(interpreter.ModuleResolution.BuiltinsModule, argSet);
        private IMember GetValueFromBinaryOp(Expression expr, LookupOptions lookupOptions)
        {
            if (expr is AndExpression a)
            {
                GetValueFromExpression(a.Left, lookupOptions);
                GetValueFromExpression(a.Right, lookupOptions);
                return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));
            }

            if (expr is OrExpression orexp)
            {
                // Consider 'self.__params = types.MappingProxyType(params or {})'
                var leftSide = GetValueFromExpression(orexp.Left, lookupOptions);
                if (!leftSide.IsUnknown())
                {
                    return(leftSide);
                }
                var rightSide = GetValueFromExpression(orexp.Right, lookupOptions);
                return(rightSide.IsUnknown() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : rightSide);
            }

            if (!(expr is BinaryExpression binop) || binop.Left == null)
            {
                return(null);
            }

            var op = binop.Operator;

            var left  = GetValueFromExpression(binop.Left, lookupOptions) ?? UnknownType;
            var right = GetValueFromExpression(binop.Right, lookupOptions) ?? UnknownType;

            if (left.IsUnknown() && right.IsUnknown())
            {
                // Fast path for when nothing below will give any results.
                if (op.IsComparison())
                {
                    return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));
                }

                return(UnknownType);
            }

            var leftType  = left.GetPythonType();
            var rightType = right.GetPythonType();

            var leftTypeId  = leftType.TypeId;
            var rightTypeId = rightType.TypeId;

            if (op == PythonOperator.Add &&
                leftTypeId == rightTypeId &&
                left is IPythonCollection lc && right is IPythonCollection rc)
            {
                switch (leftTypeId)
                {
                case BuiltinTypeId.List:
                    return(PythonCollectionType.CreateConcatenatedList(Module, lc, rc));

                case BuiltinTypeId.Tuple:
                    return(PythonCollectionType.CreateConcatenatedTuple(Module, lc, rc));
                }
            }

            // Mod-style string formatting; don't bother looking at the right side.
            if (op == PythonOperator.Mod && (leftTypeId == BuiltinTypeId.Str || leftTypeId == BuiltinTypeId.Unicode))
            {
                return(Interpreter.GetBuiltinType(leftTypeId));
            }

            var leftIsSupported  = IsSupportedBinopBuiltin(leftTypeId);
            var rightIsSupported = IsSupportedBinopBuiltin(rightTypeId);

            if (leftIsSupported && rightIsSupported)
            {
                if (TryGetValueFromBuiltinBinaryOp(op, leftTypeId, rightTypeId, Interpreter.LanguageVersion.Is3x(), out var member))
                {
                    return(member);
                }
            }

            if (leftIsSupported)
            {
                IMember ret;

                if (op.IsComparison())
                {
                    // If the op is a comparison, and the thing on the left is the builtin,
                    // flip the operation and call it instead.
                    ret = CallOperator(op.InvertComparison(), right, rightType, left, leftType, expr, tryRight: false);
                }
                else
                {
                    ret = CallOperator(op, left, leftType, right, rightType, expr, tryLeft: false);
                }

                if (!ret.IsUnknown())
                {
                    return(ret);
                }

                return(op.IsComparison() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : left);
            }

            if (rightIsSupported)
            {
                // Try calling the function on the left side, otherwise just return right.
                var ret = CallOperator(op, left, leftType, right, rightType, expr, tryRight: false);

                if (!ret.IsUnknown())
                {
                    return(ret);
                }

                return(op.IsComparison() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : right);
            }

            var callRet = CallOperator(op, left, leftType, right, rightType, expr);

            if (!callRet.IsUnknown())
            {
                return(callRet);
            }

            if (op.IsComparison())
            {
                callRet = CallOperator(op.InvertComparison(), right, rightType, left, leftType, expr);

                if (!callRet.IsUnknown())
                {
                    return(callRet);
                }
            }

            // TODO: Specific parsing
            // TODO: warn about incompatible types like 'str' + 1
            switch (op)
            {
            case PythonOperator.Equal:
            case PythonOperator.GreaterThan:
            case PythonOperator.GreaterThanOrEqual:
            case PythonOperator.In:
            case PythonOperator.Is:
            case PythonOperator.IsNot:
            case PythonOperator.LessThan:
            case PythonOperator.LessThanOrEqual:
            case PythonOperator.Not:
            case PythonOperator.NotEqual:
            case PythonOperator.NotIn:
                // Assume all of these return True/False
                return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));

            case PythonOperator.Divide:
            case PythonOperator.TrueDivide:
                if (Interpreter.LanguageVersion.Is3x())
                {
                    return(Interpreter.GetBuiltinType(BuiltinTypeId.Float));
                }

                break;
            }

            return(left.IsUnknown() ? right : left);
        }
 private IPythonCollection CreateList(IReadOnlyList <IMember> items)
 => PythonCollectionType.CreateList(Type.DeclaringModule.Interpreter, items, false);