diff --git a/crates/red_knot/tests/cli.rs b/crates/red_knot/tests/cli.rs index 210063ae84..df8e21defb 100644 --- a/crates/red_knot/tests/cli.rs +++ b/crates/red_knot/tests/cli.rs @@ -274,13 +274,13 @@ fn configuration_rule_severity() -> anyhow::Result<()> { 4 | for a in range(0, int(y)): | - warning: lint:possibly-unresolved-reference + warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined --> /test.py:7:7 | 5 | x = a 6 | 7 | print(x) # possibly-unresolved-reference - | ^ Name `x` used when possibly not defined + | ^ | Found 2 diagnostics @@ -361,13 +361,13 @@ fn cli_rule_severity() -> anyhow::Result<()> { 6 | for a in range(0, int(y)): | - warning: lint:possibly-unresolved-reference + warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined --> /test.py:9:7 | 7 | x = a 8 | 9 | print(x) # possibly-unresolved-reference - | ^ Name `x` used when possibly not defined + | ^ | Found 3 diagnostics @@ -448,13 +448,13 @@ fn cli_rule_severity_precedence() -> anyhow::Result<()> { 4 | for a in range(0, int(y)): | - warning: lint:possibly-unresolved-reference + warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined --> /test.py:7:7 | 5 | x = a 6 | 7 | print(x) # possibly-unresolved-reference - | ^ Name `x` used when possibly not defined + | ^ | Found 2 diagnostics @@ -555,11 +555,11 @@ fn exit_code_only_warnings() -> anyhow::Result<()> { success: true exit_code: 0 ----- stdout ----- - warning: lint:unresolved-reference + warning: lint:unresolved-reference: Name `x` used when not defined --> /test.py:1:7 | 1 | print(x) # [unresolved-reference] - | ^ Name `x` used when not defined + | ^ | Found 1 diagnostic @@ -638,11 +638,11 @@ fn exit_code_no_errors_but_error_on_warning_is_true() -> anyhow::Result<()> { success: false exit_code: 1 ----- stdout ----- - warning: lint:unresolved-reference + warning: lint:unresolved-reference: Name `x` used when not defined --> /test.py:1:7 | 1 | print(x) # [unresolved-reference] - | ^ Name `x` used when not defined + | ^ | Found 1 diagnostic @@ -670,11 +670,11 @@ fn exit_code_no_errors_but_error_on_warning_is_enabled_in_configuration() -> any success: false exit_code: 1 ----- stdout ----- - warning: lint:unresolved-reference + warning: lint:unresolved-reference: Name `x` used when not defined --> /test.py:1:7 | 1 | print(x) # [unresolved-reference] - | ^ Name `x` used when not defined + | ^ | Found 1 diagnostic @@ -699,20 +699,20 @@ fn exit_code_both_warnings_and_errors() -> anyhow::Result<()> { success: false exit_code: 1 ----- stdout ----- - warning: lint:unresolved-reference + warning: lint:unresolved-reference: Name `x` used when not defined --> /test.py:2:7 | 2 | print(x) # [unresolved-reference] - | ^ Name `x` used when not defined + | ^ 3 | print(4[1]) # [non-subscriptable] | - error: lint:non-subscriptable + error: lint:non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method --> /test.py:3:7 | 2 | print(x) # [unresolved-reference] 3 | print(4[1]) # [non-subscriptable] - | ^ Cannot subscript object of type `Literal[4]` with no `__getitem__` method + | ^ | Found 2 diagnostics @@ -737,20 +737,20 @@ fn exit_code_both_warnings_and_errors_and_error_on_warning_is_true() -> anyhow:: success: false exit_code: 1 ----- stdout ----- - warning: lint:unresolved-reference + warning: lint:unresolved-reference: Name `x` used when not defined --> /test.py:2:7 | 2 | print(x) # [unresolved-reference] - | ^ Name `x` used when not defined + | ^ 3 | print(4[1]) # [non-subscriptable] | - error: lint:non-subscriptable + error: lint:non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method --> /test.py:3:7 | 2 | print(x) # [unresolved-reference] 3 | print(4[1]) # [non-subscriptable] - | ^ Cannot subscript object of type `Literal[4]` with no `__getitem__` method + | ^ | Found 2 diagnostics @@ -775,20 +775,20 @@ fn exit_code_exit_zero_is_true() -> anyhow::Result<()> { success: true exit_code: 0 ----- stdout ----- - warning: lint:unresolved-reference + warning: lint:unresolved-reference: Name `x` used when not defined --> /test.py:2:7 | 2 | print(x) # [unresolved-reference] - | ^ Name `x` used when not defined + | ^ 3 | print(4[1]) # [non-subscriptable] | - error: lint:non-subscriptable + error: lint:non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method --> /test.py:3:7 | 2 | print(x) # [unresolved-reference] 3 | print(4[1]) # [non-subscriptable] - | ^ Cannot subscript object of type `Literal[4]` with no `__getitem__` method + | ^ | Found 2 diagnostics @@ -844,13 +844,13 @@ fn user_configuration() -> anyhow::Result<()> { 4 | for a in range(0, int(y)): | - warning: lint:possibly-unresolved-reference + warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined --> /project/main.py:7:7 | 5 | x = a 6 | 7 | print(x) - | ^ Name `x` used when possibly not defined + | ^ | Found 2 diagnostics @@ -886,13 +886,13 @@ fn user_configuration() -> anyhow::Result<()> { 4 | for a in range(0, int(y)): | - error: lint:possibly-unresolved-reference + error: lint:possibly-unresolved-reference: Name `x` used when possibly not defined --> /project/main.py:7:7 | 5 | x = a 6 | 7 | print(x) - | ^ Name `x` used when possibly not defined + | ^ | Found 2 diagnostics diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/attribute_assignment.md_-_Attribute_assignment_-_Possibly-unbound_attributes.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/attribute_assignment.md_-_Attribute_assignment_-_Possibly-unbound_attributes.snap index 8bc9529169..9d98faf548 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/attribute_assignment.md_-_Attribute_assignment_-_Possibly-unbound_attributes.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/attribute_assignment.md_-_Attribute_assignment_-_Possibly-unbound_attributes.snap @@ -26,13 +26,13 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/attrib # Diagnostics ``` -warning: lint:possibly-unbound-attribute +warning: lint:possibly-unbound-attribute: Attribute `attr` on type `Literal[C]` is possibly unbound --> /src/mdtest_snippet.py:6:5 | 4 | attr: int = 0 5 | 6 | C.attr = 1 # error: [possibly-unbound-attribute] - | ^^^^^^ Attribute `attr` on type `Literal[C]` is possibly unbound + | ^^^^^^ 7 | 8 | instance = C() | @@ -40,12 +40,12 @@ warning: lint:possibly-unbound-attribute ``` ``` -warning: lint:possibly-unbound-attribute +warning: lint:possibly-unbound-attribute: Attribute `attr` on type `C` is possibly unbound --> /src/mdtest_snippet.py:9:5 | 8 | instance = C() 9 | instance.attr = 1 # error: [possibly-unbound-attribute] - | ^^^^^^^^^^^^^ Attribute `attr` on type `C` is possibly unbound + | ^^^^^^^^^^^^^ | ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_With_non-callable_iterator.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_With_non-callable_iterator.snap index 2fb989fd46..f85c26b823 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_With_non-callable_iterator.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_With_non-callable_iterator.snap @@ -45,13 +45,13 @@ error: lint:not-iterable ``` ``` -warning: lint:possibly-unresolved-reference +warning: lint:possibly-unresolved-reference: Name `x` used when possibly not defined --> /src/mdtest_snippet.py:16:17 | 14 | # revealed: Unknown 15 | # error: [possibly-unresolved-reference] 16 | reveal_type(x) - | ^ Name `x` used when possibly not defined + | ^ | ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_implicit_return_type.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_implicit_return_type.snap index e88e7a29a7..1b57002c77 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_implicit_return_type.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_implicit_return_type.snap @@ -56,12 +56,12 @@ error: lint:invalid-return-type: Return type does not match returned value ``` ``` -error: lint:invalid-return-type +error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int` --> /src/mdtest_snippet.py:7:22 | 6 | # error: [invalid-return-type] 7 | def f(cond: bool) -> int: - | ^^^ Function can implicitly return `None`, which is not assignable to return type `int` + | ^^^ 8 | if cond: 9 | return 1 | @@ -69,12 +69,12 @@ error: lint:invalid-return-type ``` ``` -error: lint:invalid-return-type +error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int` --> /src/mdtest_snippet.py:12:22 | 11 | # error: [invalid-return-type] 12 | def f(cond: bool) -> int: - | ^^^ Function can implicitly return `None`, which is not assignable to return type `int` + | ^^^ 13 | if cond: 14 | raise ValueError() | @@ -82,12 +82,12 @@ error: lint:invalid-return-type ``` ``` -error: lint:invalid-return-type +error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int` --> /src/mdtest_snippet.py:17:22 | 16 | # error: [invalid-return-type] 17 | def f(cond: bool) -> int: - | ^^^ Function can implicitly return `None`, which is not assignable to return type `int` + | ^^^ 18 | if cond: 19 | cond = False | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_return_type.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_return_type.snap index b54a9b6abb..c039791eae 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_return_type.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_return_type.snap @@ -35,12 +35,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/function/return_ty # Diagnostics ``` -error: lint:invalid-return-type +error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int` --> /src/mdtest_snippet.py:2:12 | 1 | # error: [invalid-return-type] 2 | def f() -> int: - | ^^^ Function can implicitly return `None`, which is not assignable to return type `int` + | ^^^ 3 | 1 | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_return_type_in_stub_file.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_return_type_in_stub_file.snap index 3514f85b6c..3c02500ae3 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_return_type_in_stub_file.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/return_type.md_-_Function_return_type_-_Invalid_return_type_in_stub_file.snap @@ -45,12 +45,12 @@ error: lint:invalid-return-type: Return type does not match returned value ``` ``` -error: lint:invalid-return-type +error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int` --> /src/mdtest_snippet.pyi:6:14 | 5 | # error: [invalid-return-type] 6 | def foo() -> int: - | ^^^ Function can implicitly return `None`, which is not assignable to return type `int` + | ^^^ 7 | print("...") 8 | ... | @@ -58,12 +58,12 @@ error: lint:invalid-return-type ``` ``` -error: lint:invalid-return-type +error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `int` --> /src/mdtest_snippet.pyi:11:14 | 10 | # error: [invalid-return-type] 11 | def foo() -> int: - | ^^^ Function can implicitly return `None`, which is not assignable to return type `int` + | ^^^ 12 | f"""{foo} is a function that ...""" 13 | ... | diff --git a/crates/red_knot_python_semantic/src/types/diagnostic.rs b/crates/red_knot_python_semantic/src/types/diagnostic.rs index f82eae4d0b..e35f19fea9 100644 --- a/crates/red_knot_python_semantic/src/types/diagnostic.rs +++ b/crates/red_knot_python_semantic/src/types/diagnostic.rs @@ -1075,14 +1075,13 @@ pub(super) fn report_index_out_of_bounds( length: usize, index: i64, ) { - context.report_lint_old( - &INDEX_OUT_OF_BOUNDS, - node, - format_args!( - "Index {index} is out of bounds for {kind} `{}` with length {length}", - tuple_ty.display(context.db()) - ), - ); + let Some(builder) = context.report_lint(&INDEX_OUT_OF_BOUNDS, node) else { + return; + }; + builder.into_diagnostic(format_args!( + "Index {index} is out of bounds for {kind} `{}` with length {length}", + tuple_ty.display(context.db()) + )); } /// Emit a diagnostic declaring that a type does not support subscripting. @@ -1092,22 +1091,20 @@ pub(super) fn report_non_subscriptable( non_subscriptable_ty: Type, method: &str, ) { - context.report_lint_old( - &NON_SUBSCRIPTABLE, - node, - format_args!( - "Cannot subscript object of type `{}` with no `{method}` method", - non_subscriptable_ty.display(context.db()) - ), - ); + let Some(builder) = context.report_lint(&NON_SUBSCRIPTABLE, node) else { + return; + }; + builder.into_diagnostic(format_args!( + "Cannot subscript object of type `{}` with no `{method}` method", + non_subscriptable_ty.display(context.db()) + )); } pub(super) fn report_slice_step_size_zero(context: &InferContext, node: AnyNodeRef) { - context.report_lint_old( - &ZERO_STEPSIZE_IN_SLICE, - node, - format_args!("Slice step size can not be zero"), - ); + let Some(builder) = context.report_lint(&ZERO_STEPSIZE_IN_SLICE, node) else { + return; + }; + builder.into_diagnostic("Slice step size can not be zero"); } fn report_invalid_assignment_with_message( @@ -1209,21 +1206,21 @@ pub(super) fn report_implicit_return_type( range: impl Ranged, expected_ty: Type, ) { - context.report_lint_old( - &INVALID_RETURN_TYPE, - range, - format_args!( - "Function can implicitly return `None`, which is not assignable to return type `{}`", - expected_ty.display(context.db()) - ), - ); + let Some(builder) = context.report_lint(&INVALID_RETURN_TYPE, range) else { + return; + }; + builder.into_diagnostic(format_args!( + "Function can implicitly return `None`, which is not assignable to return type `{}`", + expected_ty.display(context.db()) + )); } pub(super) fn report_invalid_type_checking_constant(context: &InferContext, node: AnyNodeRef) { - context.report_lint_old( - &INVALID_TYPE_CHECKING_CONSTANT, - node, - format_args!("The name TYPE_CHECKING is reserved for use as a flag; only False can be assigned to it.",), + let Some(builder) = context.report_lint(&INVALID_TYPE_CHECKING_CONSTANT, node) else { + return; + }; + builder.into_diagnostic( + "The name TYPE_CHECKING is reserved for use as a flag; only False can be assigned to it", ); } @@ -1231,13 +1228,12 @@ pub(super) fn report_possibly_unresolved_reference( context: &InferContext, expr_name_node: &ast::ExprName, ) { - let ast::ExprName { id, .. } = expr_name_node; + let Some(builder) = context.report_lint(&POSSIBLY_UNRESOLVED_REFERENCE, expr_name_node) else { + return; + }; - context.report_lint_old( - &POSSIBLY_UNRESOLVED_REFERENCE, - expr_name_node, - format_args!("Name `{id}` used when possibly not defined"), - ); + let ast::ExprName { id, .. } = expr_name_node; + builder.into_diagnostic(format_args!("Name `{id}` used when possibly not defined")); } pub(super) fn report_possibly_unbound_attribute( @@ -1246,93 +1242,86 @@ pub(super) fn report_possibly_unbound_attribute( attribute: &str, object_ty: Type, ) { - context.report_lint_old( - &POSSIBLY_UNBOUND_ATTRIBUTE, - target, - format_args!( - "Attribute `{attribute}` on type `{}` is possibly unbound", - object_ty.display(context.db()), - ), - ); + let Some(builder) = context.report_lint(&POSSIBLY_UNBOUND_ATTRIBUTE, target) else { + return; + }; + builder.into_diagnostic(format_args!( + "Attribute `{attribute}` on type `{}` is possibly unbound", + object_ty.display(context.db()), + )); } pub(super) fn report_unresolved_reference(context: &InferContext, expr_name_node: &ast::ExprName) { - let ast::ExprName { id, .. } = expr_name_node; + let Some(builder) = context.report_lint(&UNRESOLVED_REFERENCE, expr_name_node) else { + return; + }; - context.report_lint_old( - &UNRESOLVED_REFERENCE, - expr_name_node, - format_args!("Name `{id}` used when not defined"), - ); + let ast::ExprName { id, .. } = expr_name_node; + builder.into_diagnostic(format_args!("Name `{id}` used when not defined")); } pub(super) fn report_invalid_exception_caught(context: &InferContext, node: &ast::Expr, ty: Type) { - context.report_lint_old( - &INVALID_EXCEPTION_CAUGHT, - node, - format_args!( - "Cannot catch object of type `{}` in an exception handler \ + let Some(builder) = context.report_lint(&INVALID_EXCEPTION_CAUGHT, node) else { + return; + }; + builder.into_diagnostic(format_args!( + "Cannot catch object of type `{}` in an exception handler \ (must be a `BaseException` subclass or a tuple of `BaseException` subclasses)", - ty.display(context.db()) - ), - ); + ty.display(context.db()) + )); } pub(crate) fn report_invalid_exception_raised(context: &InferContext, node: &ast::Expr, ty: Type) { - context.report_lint_old( - &INVALID_RAISE, - node, - format_args!( - "Cannot raise object of type `{}` (must be a `BaseException` subclass or instance)", - ty.display(context.db()) - ), - ); + let Some(builder) = context.report_lint(&INVALID_RAISE, node) else { + return; + }; + builder.into_diagnostic(format_args!( + "Cannot raise object of type `{}` (must be a `BaseException` subclass or instance)", + ty.display(context.db()) + )); } pub(crate) fn report_invalid_exception_cause(context: &InferContext, node: &ast::Expr, ty: Type) { - context.report_lint_old( - &INVALID_RAISE, - node, - format_args!( - "Cannot use object of type `{}` as exception cause \ - (must be a `BaseException` subclass or instance or `None`)", - ty.display(context.db()) - ), - ); + let Some(builder) = context.report_lint(&INVALID_RAISE, node) else { + return; + }; + builder.into_diagnostic(format_args!( + "Cannot use object of type `{}` as exception cause \ + (must be a `BaseException` subclass or instance or `None`)", + ty.display(context.db()) + )); } pub(crate) fn report_base_with_incompatible_slots(context: &InferContext, node: &ast::Expr) { - context.report_lint_old( - &INCOMPATIBLE_SLOTS, - node, - format_args!("Class base has incompatible `__slots__`"), - ); + let Some(builder) = context.report_lint(&INCOMPATIBLE_SLOTS, node) else { + return; + }; + builder.into_diagnostic("Class base has incompatible `__slots__`"); } pub(crate) fn report_invalid_arguments_to_annotated( context: &InferContext, subscript: &ast::ExprSubscript, ) { - context.report_lint_old( - &INVALID_TYPE_FORM, - subscript, - format_args!( - "Special form `{}` expected at least 2 arguments (one type and at least one metadata element)", - KnownInstanceType::Annotated.repr(context.db()) - ), - ); + let Some(builder) = context.report_lint(&INVALID_TYPE_FORM, subscript) else { + return; + }; + builder.into_diagnostic(format_args!( + "Special form `{}` expected at least 2 arguments \ + (one type and at least one metadata element)", + KnownInstanceType::Annotated.repr(context.db()) + )); } pub(crate) fn report_invalid_arguments_to_callable( context: &InferContext, subscript: &ast::ExprSubscript, ) { - context.report_lint_old( - &INVALID_TYPE_FORM, - subscript, - format_args!( - "Special form `{}` expected exactly two arguments (parameter types and return type)", - KnownInstanceType::Callable.repr(context.db()) - ), - ); + let Some(builder) = context.report_lint(&INVALID_TYPE_FORM, subscript) else { + return; + }; + builder.into_diagnostic(format_args!( + "Special form `{}` expected exactly two arguments (parameter types and return type)", + KnownInstanceType::Callable.repr(context.db()) + )); }