Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/infer/builder.rs (Rust)

Code before:

                if let Some(builder) = self.context.report_lint(&UNSUPPORTED_OPERATOR, binary) {
                    let mut diag = builder.into_diagnostic(format_args!(
                        "Operator `{op}` is unsupported between objects of type `{}` and `{}`",
                        left_ty.display(db),
                        right_ty.display(db)
                    ));

                    if op == &ast::Operator::BitOr
                        && (left_ty.is_subtype_of(db, KnownClass::Type.to_instance(db))
                            || right_ty.is_subtype_of(db, KnownClass::Type.to_instance(db)))
                        && Program::get(db).python_version(db) < PythonVersion::PY310
                    {
                        diag.info(
                            "Note that `X | Y` PEP 604 union syntax is only available in Python 3.10 and later",
                        );
                        add_inferred_python_version_hint_to_diagnostic(db, &mut diag, "resolving types");
                    }
                }
                Type::unknown()
            })
    }

    fn infer_binary_expression_type(
        &mut self,
        node: AnyNodeRef<'_>,
        mut emitted_division_by_zero_diagnostic: bool,
        left_ty: Type<'db>,
        right_ty: Type<'db>,
        op: ast::Operator,
    ) -> Option<Type<'db>> {
        // Check for division by zero; this doesn't change the inferred type for the expression, but
        // may emit a diagnostic
        if !emitted_division_by_zero_diagnostic
            && matches!(
                (op, right_ty),
                (
                    ast::Operator::Div | ast::Operator::FloorDiv | ast::Operator::Mod,
                    Type::IntLiteral(0) | Type::BooleanLiteral(false)
                )
            )
        {
            emitted_division_by_zero_diagnostic = self.check_division_by_zero(node, op, left_ty);
        }

        match (left_ty, right_ty, op) {
            (Type::Union(lhs_union), rhs, _) => lhs_union.try_map(self.db(), |lhs_element| {
                self.infer_binary_expression_type(
                    node,
                    emitted_division_by_zero_diagnostic,
                    *lhs_element,

Review comment (bug):
If returning here is correct, then pushing the constraint into `constraint_keys` immediately above this cannot have any effect, so should we remove that as well? (Removing it doesn't seem to fail any test.)

Why do we hit the `FoundConstraint` case in this situation in the first place? It's not clear to me where the "constraint" comes from.

Code after:
                    }
                }
            }

            PlaceAndQualifiers::from(Place::Undefined)
                // No nonlocal binding? Check the module's explicit globals.
                // Avoid infinite recursion if `self.scope` already is the module's global scope.
                .or_fall_back_to(db, || {
                    if file_scope_id.is_global() {
                        return Place::Undefined.into();
                    }

                    if !self.is_deferred() {
                        match self.index.enclosing_snapshot(
                            FileScopeId::global(),
                            place_expr,
                            file_scope_id,
                        ) {
                            EnclosingSnapshotResult::FoundConstraint(constraint) => {
                                constraint_keys.push((
                                    FileScopeId::global(),
                                    ConstraintKey::NarrowingConstraint(constraint),
                                ));
                                // Reaching here means that no bindings are found in any scope.
                                // Since `explicit_global_symbol` may return a cycle initial value, we return `Place::Undefined` here.
                                return Place::Undefined.into();
                            }
                            EnclosingSnapshotResult::FoundBindings(bindings) => {
                                let place = place_from_bindings(db, bindings).map_type(|ty| {
                                    self.narrow_place_with_applicable_constraints(
                                        place_expr,
                                        ty,
                                        &constraint_keys,
                                    )
                                });
                                constraint_keys.push((
                                    FileScopeId::global(),
                                    ConstraintKey::NestedScope(file_scope_id),
                                ));
                                return place.into();
                            }
                            // There are no visible bindings / constraint here.
                            EnclosingSnapshotResult::NotFound => {
                                return Place::Undefined.into();
                            }
                            EnclosingSnapshotResult::NoLongerInEagerContext => {}
                        }
                    }

                    let Some(symbol) = place_expr.as_symbol() else {
                        return Place::Undefined.into();