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

Code before:

                let value_ty = self.infer_expression(value, TypeContext::default());

                self.infer_subscript_type_expression_no_store(subscript, slice, value_ty)
            }

            ast::Expr::BinOp(binary) => {
                match binary.op {
                    // PEP-604 unions are okay, e.g., `int | str`
                    ast::Operator::BitOr => {
                        let left_ty = self.infer_type_expression(&binary.left);
                        let right_ty = self.infer_type_expression(&binary.right);
                        UnionType::from_elements_leave_aliases(self.db(), [left_ty, right_ty])
                    }
                    // anything else is an invalid annotation:
                    op => {
                        self.infer_binary_expression(binary, TypeContext::default());
                        if let Some(mut diag) = self.report_invalid_type_expression(
                            expression,
                            format_args!(
                                "Invalid binary operator `{}` in type annotation",
                                op.as_str()
                            ),
                        ) {
                            diag.info("Did you mean to use `|`?");
                        }
                        Type::unknown()
                    }
                }
            }

            // Avoid inferring the types of invalid type expressions that have been parsed from a
            // string annotation, as they are not present in the semantic index.
            _ if self.deferred_state.in_string_annotation() => Type::unknown(),

            // =====================================================================================
            // Forms which are invalid in the context of annotation expressions: we infer their
            // nested expressions as normal expressions, but the type of the top-level expression is
            // always `Type::unknown` in these cases.
            // =====================================================================================

            // TODO: add a subdiagnostic linking to type-expression grammar
            // and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
            ast::Expr::BytesLiteral(_) => {
                self.report_invalid_type_expression(
                    expression,
                    format_args!(
                        "Bytes literals are not allowed in this context in a type expression"
                    ),
                );
                Type::unknown()

Review comment (suggestion):
we don't have any tests for this subdiagnostic and I'm not convinced it's likely to be helpful. If a user has `int + str` in a type expression, I think it's very unclear what they meant; if they have `int - bool`, I think it's likely that they were trying to write a negation type rather than a union type; etc.

Code after:

                let value_ty = self.infer_expression(value, TypeContext::default());

                self.infer_subscript_type_expression_no_store(subscript, slice, value_ty)
            }

            ast::Expr::BinOp(binary) => {
                match binary.op {
                    // PEP-604 unions are okay, e.g., `int | str`
                    ast::Operator::BitOr => {
                        let left_ty = self.infer_type_expression(&binary.left);
                        let right_ty = self.infer_type_expression(&binary.right);
                        UnionType::from_elements_leave_aliases(self.db(), [left_ty, right_ty])
                    }
                    // anything else is an invalid annotation:
                    op => {
                        self.infer_binary_expression(binary, TypeContext::default());
                        self.report_invalid_type_expression(
                            expression,
                            format_args!(
                                "Invalid binary operator `{}` in type annotation",
                                op.as_str()
                            ),
                        );
                        Type::unknown()
                    }
                }
            }

            // Avoid inferring the types of invalid type expressions that have been parsed from a
            // string annotation, as they are not present in the semantic index.
            _ if self.deferred_state.in_string_annotation() => Type::unknown(),

            // =====================================================================================
            // Forms which are invalid in the context of annotation expressions: we infer their
            // nested expressions as normal expressions, but the type of the top-level expression is
            // always `Type::unknown` in these cases.
            // =====================================================================================

            // TODO: add a subdiagnostic linking to type-expression grammar
            // and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
            ast::Expr::BytesLiteral(_) => {
                self.report_invalid_type_expression(
                    expression,
                    format_args!(
                        "Bytes literals are not allowed in this context in a type expression"
                    ),
                );
                Type::unknown()
            }