Skip to content

Commit df56e96

Browse files
Merge 137b350 into 37cdd61
2 parents 37cdd61 + 137b350 commit df56e96

4 files changed

Lines changed: 39 additions & 7 deletions

File tree

crates/ty_python_semantic/resources/mdtest/attributes.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -623,8 +623,6 @@ class C:
623623
self.c = c
624624
if False:
625625
def set_e(self, e: str) -> None:
626-
# TODO: Should not emit this diagnostic
627-
# error: [unresolved-attribute]
628626
self.e = e
629627

630628
# TODO: this would ideally be `Unknown | Literal[1]`

crates/ty_python_semantic/resources/mdtest/function/return_type.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,14 @@ elif TYPE_CHECKING:
187187
def j() -> str: ...
188188

189189
else:
190-
def j_() -> str: ... # error: [empty-body]
190+
def j():
191+
raise NotImplementedError
191192

192193
if False:
193194
pass
194195
elif not TYPE_CHECKING:
195-
def k_() -> str: ... # error: [empty-body]
196+
def k() -> str:
197+
raise NotImplementedError
196198

197199
else:
198200
def k() -> str: ...
@@ -224,19 +226,22 @@ if typing.TYPE_CHECKING:
224226
def o() -> str: ...
225227

226228
if not typing.TYPE_CHECKING:
227-
def p() -> str: ... # error: [empty-body]
229+
def p() -> str:
230+
raise NotImplementedError
228231

229232
if compat.sub.sub.TYPE_CHECKING:
230233
def q() -> str: ...
231234

232235
if not compat.sub.sub.TYPE_CHECKING:
233-
def r() -> str: ... # error: [empty-body]
236+
def r() -> str:
237+
raise NotImplementedError
234238

235239
if t.TYPE_CHECKING:
236240
def s() -> str: ...
237241

238242
if not t.TYPE_CHECKING:
239-
def t() -> str: ... # error: [empty-body]
243+
def t() -> str:
244+
raise NotImplementedError
240245
```
241246

242247
## Conditional return type

crates/ty_python_semantic/resources/mdtest/unreachable.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,29 @@ if False:
464464
print(x)
465465
```
466466

467+
This also applies to deferred annotations on Python 3.14+, which are resolved from the perspective
468+
of the end of the scope, which may not be part of the unreachable section.
469+
470+
```toml
471+
[environment]
472+
python-version = "3.14"
473+
```
474+
475+
```py
476+
from typing import TYPE_CHECKING
477+
478+
class NonCallable:
479+
pass
480+
481+
if not TYPE_CHECKING:
482+
def _(non_callable: NonCallable):
483+
non_callable()
484+
485+
if False:
486+
def _(non_callable: NonCallable):
487+
non_callable()
488+
```
489+
467490
### Type annotations
468491

469492
Silencing of diagnostics also works for type annotations, even if they are stringified:

crates/ty_python_semantic/src/types/context.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,12 @@ impl<'db, 'ctx> LintDiagnosticGuardBuilder<'db, 'ctx> {
442442
if ctx.is_in_multi_inference() {
443443
return None;
444444
}
445+
// Nested scopes in statically unreachable branches should not produce body diagnostics.
446+
if !semantic_index(ctx.db, ctx.file)
447+
.is_scope_reachable(ctx.db, ctx.scope.file_scope_id(ctx.db))
448+
{
449+
return None;
450+
}
445451

446452
Some((severity, source))
447453
}

0 commit comments

Comments
 (0)