in src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs [231:349]
private bool TryGetValueFromBuiltinBinaryOp(PythonOperator op, BuiltinTypeId left, BuiltinTypeId right, bool is3x, out IMember member) {
if (op.IsComparison()) {
// All builtins compare to bool.
member = Interpreter.GetBuiltinType(BuiltinTypeId.Bool);
return true;
}
member = UnknownType;
switch (op) {
case PythonOperator.MatMultiply:
// No builtins implement this operator.
return true;
case PythonOperator.BitwiseAnd:
case PythonOperator.BitwiseOr:
case PythonOperator.Xor:
switch (left) {
case BuiltinTypeId.Bool when right == BuiltinTypeId.Bool:
member = Interpreter.GetBuiltinType(BuiltinTypeId.Bool);
return true;
case BuiltinTypeId.Bool when right == BuiltinTypeId.Int:
case BuiltinTypeId.Int when right == BuiltinTypeId.Bool:
case BuiltinTypeId.Int when right == BuiltinTypeId.Int:
member = Interpreter.GetBuiltinType(BuiltinTypeId.Int);
return true;
case BuiltinTypeId.Long when right == BuiltinTypeId.Long:
case BuiltinTypeId.Long when right == BuiltinTypeId.Int:
case BuiltinTypeId.Long when right == BuiltinTypeId.Bool:
case BuiltinTypeId.Bool when right == BuiltinTypeId.Long:
case BuiltinTypeId.Int when right == BuiltinTypeId.Long:
member = Interpreter.GetBuiltinType(BuiltinTypeId.Long);
return true;
}
// All other combinations of these bitwise operaton on builtin types fail.
return true;
}
// At this point, @ & | ^ are all handled and do not need to be considered.
if (CoalesceComplex(left, right)) {
switch (op) {
case PythonOperator.Add:
case PythonOperator.Multiply:
case PythonOperator.Power:
case PythonOperator.Subtract:
case PythonOperator.Divide:
case PythonOperator.TrueDivide:
case PythonOperator.FloorDivide when !is3x:
member = Interpreter.GetBuiltinType(BuiltinTypeId.Complex);
return true;
case PythonOperator.FloorDivide when is3x:
// Complex numbers cannot be floordiv'd in Python 3.
return true;
}
}
if (IsStringLike(left)) {
member = HandleStringLike(op, left, right);
return true;
}
if (IsStringLike(right)) {
member = HandleStringLike(op, right, left);
return true;
}
// All string-like cases have been handled.
// If a complex value made it to here, then it wasn't coalesced or used in a string format; bail.
if (left == BuiltinTypeId.Complex || right == BuiltinTypeId.Complex) {
return true;
}
switch (op) {
case PythonOperator.TrueDivide:
member = Interpreter.GetBuiltinType(BuiltinTypeId.Float);
return true;
case PythonOperator.LeftShift:
case PythonOperator.RightShift:
if (IsIntegerLike(left) && IsIntegerLike(right)) {
if (left == BuiltinTypeId.Long || right == BuiltinTypeId.Long) {
member = Interpreter.GetBuiltinType(BuiltinTypeId.Long);
} else {
member = Interpreter.GetBuiltinType(BuiltinTypeId.Int);
}
return true;
}
// If they aren't integer-like, then they can't be shifted.
return true;
case PythonOperator.Add:
case PythonOperator.Divide:
case PythonOperator.FloorDivide:
case PythonOperator.Mod:
case PythonOperator.Power:
case PythonOperator.Subtract:
if (IsIntegerLike(left) && IsIntegerLike(right)) {
if (left == BuiltinTypeId.Long || right == BuiltinTypeId.Long) {
member = Interpreter.GetBuiltinType(BuiltinTypeId.Long);
} else {
member = Interpreter.GetBuiltinType(BuiltinTypeId.Int);
}
return true;
} else if (left == BuiltinTypeId.Float || right == BuiltinTypeId.Float) {
member = Interpreter.GetBuiltinType(BuiltinTypeId.Float);
return true;
}
break;
}
return false;
}