diff --git a/crates/ty_python_semantic/resources/mdtest/directives/assert_type.md b/crates/ty_python_semantic/resources/mdtest/directives/assert_type.md index 840e8ce4b1..7f99251017 100644 --- a/crates/ty_python_semantic/resources/mdtest/directives/assert_type.md +++ b/crates/ty_python_semantic/resources/mdtest/directives/assert_type.md @@ -7,10 +7,11 @@ ```py from typing_extensions import assert_type -def _(x: int): +def _(x: int, y: bool): assert_type(x, int) # fine assert_type(x, str) # error: [type-assertion-failure] assert_type(assert_type(x, int), int) + assert_type(y, int) # error: [type-assertion-failure] ``` ## Narrowing diff --git a/crates/ty_python_semantic/resources/mdtest/snapshots/assert_type.md_-_`assert_type`_-_Basic_(c507788da2659ec9).snap b/crates/ty_python_semantic/resources/mdtest/snapshots/assert_type.md_-_`assert_type`_-_Basic_(c507788da2659ec9).snap index 42b1ad283f..e9118a57cb 100644 --- a/crates/ty_python_semantic/resources/mdtest/snapshots/assert_type.md_-_`assert_type`_-_Basic_(c507788da2659ec9).snap +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/assert_type.md_-_`assert_type`_-_Basic_(c507788da2659ec9).snap @@ -14,10 +14,11 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/directives/assert_type.m ``` 1 | from typing_extensions import assert_type 2 | -3 | def _(x: int): +3 | def _(x: int, y: bool): 4 | assert_type(x, int) # fine 5 | assert_type(x, str) # error: [type-assertion-failure] 6 | assert_type(assert_type(x, int), int) +7 | assert_type(y, int) # error: [type-assertion-failure] ``` # Diagnostics @@ -26,15 +27,32 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/directives/assert_type.m error[type-assertion-failure]: Argument does not have asserted type `str` --> src/mdtest_snippet.py:5:5 | -3 | def _(x: int): +3 | def _(x: int, y: bool): 4 | assert_type(x, int) # fine 5 | assert_type(x, str) # error: [type-assertion-failure] | ^^^^^^^^^^^^-^^^^^^ | | - | Inferred type of argument is `int` + | Inferred type is `int` 6 | assert_type(assert_type(x, int), int) +7 | assert_type(y, int) # error: [type-assertion-failure] | info: `str` and `int` are not equivalent types info: rule `type-assertion-failure` is enabled by default ``` + +``` +error[type-assertion-failure]: Argument does not have asserted type `int` + --> src/mdtest_snippet.py:7:5 + | +5 | assert_type(x, str) # error: [type-assertion-failure] +6 | assert_type(assert_type(x, int), int) +7 | assert_type(y, int) # error: [type-assertion-failure] + | ^^^^^^^^^^^^-^^^^^^ + | | + | Inferred type is `bool` + | +info: `bool` is a subtype of `int`, but they are not equivalent +info: rule `type-assertion-failure` is enabled by default + +``` diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs index f8537c27a7..0fba3aecd8 100644 --- a/crates/ty_python_semantic/src/types/function.rs +++ b/crates/ty_python_semantic/src/types/function.rs @@ -1483,17 +1483,22 @@ impl KnownFunction { diagnostic.annotate( Annotation::secondary(context.span(&call_expression.arguments.args[0])) - .message(format_args!( - "Inferred type of argument is `{}`", - actual_ty.display(db), - )), + .message(format_args!("Inferred type is `{}`", actual_ty.display(db),)), ); - diagnostic.info(format_args!( - "`{asserted_type}` and `{inferred_type}` are not equivalent types", - asserted_type = asserted_ty.display(db), - inferred_type = actual_ty.display(db), - )); + if actual_ty.is_subtype_of(db, *asserted_ty) { + diagnostic.info(format_args!( + "`{inferred_type}` is a subtype of `{asserted_type}`, but they are not equivalent", + asserted_type = asserted_ty.display(db), + inferred_type = actual_ty.display(db), + )); + } else { + diagnostic.info(format_args!( + "`{asserted_type}` and `{inferred_type}` are not equivalent types", + asserted_type = asserted_ty.display(db), + inferred_type = actual_ty.display(db), + )); + } diagnostic.set_concise_message(format_args!( "Type `{}` does not match asserted type `{}`",