Compare commits

...

1 Commits

Author SHA1 Message Date
David Peter
80b3e2b0d9 [red-knot] Completely hide unreachable symbols 2025-04-09 12:33:11 +02:00
3 changed files with 3 additions and 52 deletions

View File

@@ -654,7 +654,7 @@ def f(cond: bool) -> str:
reveal_type(x) # revealed: Literal["before"]
return "a"
x = "after-return"
reveal_type(x) # revealed: Never
reveal_type(x) # revealed: Unknown
else:
x = "else"
return reveal_type(x) # revealed: Literal["else"]

View File

@@ -244,6 +244,8 @@ def outer():
x = 1
def inner():
# TODO
# error: [unresolved-reference]
reveal_type(x) # revealed: Unknown
while True:
pass
@@ -443,12 +445,8 @@ def _():
class C: ...
return
# TODO
# error: [invalid-type-form] "Variable of type `Never` is not allowed in a type expression"
c: C = C()
# TODO
# error: [invalid-base] "Invalid class base with type `Never` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
class Sub(C): ...
```

View File

@@ -679,53 +679,6 @@ fn symbol_from_bindings_impl<'db>(
visibility_constraints.evaluate(db, predicates, visibility_constraint);
if static_visibility.is_always_false() {
// We found a binding that we have statically determined to not be visible from
// the use of the symbol that we are investigating. There are three interesting
// cases to consider:
//
// ```py
// def f1():
// if False:
// x = 1
// use(x)
//
// def f2():
// y = 1
// return
// use(y)
//
// def f3(flag: bool):
// z = 1
// if flag:
// z = 2
// return
// use(z)
// ```
//
// In the first case, there is a single binding for `x`, and due to the statically
// known `False` condition, it is not visible at the use of `x`. However, we *can*
// see/reach the start of the scope from `use(x)`. This means that `x` is unbound
// and we should return `None`.
//
// In the second case, `y` is also not visible at the use of `y`, but here, we can
// not see/reach the start of the scope. There is only one path of control flow,
// and it passes through that binding of `y` (which we can not see). This implies
// that we are in an unreachable section of code. We return `Never` in order to
// silence the `unresolve-reference` diagnostic that would otherwise be emitted at
// the use of `y`.
//
// In the third case, we have two bindings for `z`. The first one is visible, so we
// consider the case that we now encounter the second binding `z = 2`, which is not
// visible due to the early return. We *also* can not see the start of the scope
// from `use(z)` because both paths of control flow pass through a binding of `z`.
// The `z = 1` binding is visible, and so we are *not* in an unreachable section of
// code. However, it is still okay to return `Never` in this case, because we will
// union the types of all bindings, and `Never` will be eliminated automatically.
if unbound_visibility.is_always_false() {
// The scope-start is not visible
return Some(Type::Never);
}
return None;
}