mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-18 19:41:34 +00:00
[ty] name is parameter and global is a syntax error (#21312)
Co-authored-by: Alex Waygood <alex.waygood@gmail.com> Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
This commit is contained in:
parent
8599c7e5b3
commit
8529d79a70
6 changed files with 194 additions and 18 deletions
|
|
@ -376,3 +376,41 @@ for x in range(42):
|
|||
break # error: [invalid-syntax]
|
||||
continue # error: [invalid-syntax]
|
||||
```
|
||||
|
||||
## name is parameter and global
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
```py
|
||||
a = None
|
||||
|
||||
def f(a):
|
||||
global a # error: [invalid-syntax]
|
||||
|
||||
def g(a):
|
||||
if True:
|
||||
global a # error: [invalid-syntax]
|
||||
|
||||
def h(a):
|
||||
def inner():
|
||||
global a
|
||||
|
||||
def i(a):
|
||||
try:
|
||||
global a # error: [invalid-syntax]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def f(a):
|
||||
a = 1
|
||||
global a # error: [invalid-syntax]
|
||||
|
||||
def f(a):
|
||||
a = 1
|
||||
a = 2
|
||||
global a # error: [invalid-syntax]
|
||||
|
||||
def f(a):
|
||||
class Inner:
|
||||
global a # ok
|
||||
```
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: semantic_syntax_errors.md - Semantic syntax error diagnostics - name is parameter and global
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | a = None
|
||||
2 |
|
||||
3 | def f(a):
|
||||
4 | global a # error: [invalid-syntax]
|
||||
5 |
|
||||
6 | def g(a):
|
||||
7 | if True:
|
||||
8 | global a # error: [invalid-syntax]
|
||||
9 |
|
||||
10 | def h(a):
|
||||
11 | def inner():
|
||||
12 | global a
|
||||
13 |
|
||||
14 | def i(a):
|
||||
15 | try:
|
||||
16 | global a # error: [invalid-syntax]
|
||||
17 | except Exception:
|
||||
18 | pass
|
||||
19 |
|
||||
20 | def f(a):
|
||||
21 | a = 1
|
||||
22 | global a # error: [invalid-syntax]
|
||||
23 |
|
||||
24 | def f(a):
|
||||
25 | a = 1
|
||||
26 | a = 2
|
||||
27 | global a # error: [invalid-syntax]
|
||||
28 |
|
||||
29 | def f(a):
|
||||
30 | class Inner:
|
||||
31 | global a # ok
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-syntax]: name `a` is parameter and global
|
||||
--> src/mdtest_snippet.py:4:12
|
||||
|
|
||||
3 | def f(a):
|
||||
4 | global a # error: [invalid-syntax]
|
||||
| ^
|
||||
5 |
|
||||
6 | def g(a):
|
||||
|
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-syntax]: name `a` is parameter and global
|
||||
--> src/mdtest_snippet.py:8:16
|
||||
|
|
||||
6 | def g(a):
|
||||
7 | if True:
|
||||
8 | global a # error: [invalid-syntax]
|
||||
| ^
|
||||
9 |
|
||||
10 | def h(a):
|
||||
|
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-syntax]: name `a` is parameter and global
|
||||
--> src/mdtest_snippet.py:16:16
|
||||
|
|
||||
14 | def i(a):
|
||||
15 | try:
|
||||
16 | global a # error: [invalid-syntax]
|
||||
| ^
|
||||
17 | except Exception:
|
||||
18 | pass
|
||||
|
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-syntax]: name `a` is parameter and global
|
||||
--> src/mdtest_snippet.py:22:12
|
||||
|
|
||||
20 | def f(a):
|
||||
21 | a = 1
|
||||
22 | global a # error: [invalid-syntax]
|
||||
| ^
|
||||
23 |
|
||||
24 | def f(a):
|
||||
|
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-syntax]: name `a` is parameter and global
|
||||
--> src/mdtest_snippet.py:27:12
|
||||
|
|
||||
25 | a = 1
|
||||
26 | a = 2
|
||||
27 | global a # error: [invalid-syntax]
|
||||
| ^
|
||||
28 |
|
||||
29 | def f(a):
|
||||
|
|
||||
|
||||
```
|
||||
|
|
@ -1165,6 +1165,9 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
}
|
||||
if let Some(vararg) = parameters.vararg.as_ref() {
|
||||
let symbol = self.add_symbol(vararg.name.id().clone());
|
||||
self.current_place_table_mut()
|
||||
.symbol_mut(symbol)
|
||||
.mark_parameter();
|
||||
self.add_definition(
|
||||
symbol.into(),
|
||||
DefinitionNodeRef::VariadicPositionalParameter(vararg),
|
||||
|
|
@ -1172,6 +1175,9 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
}
|
||||
if let Some(kwarg) = parameters.kwarg.as_ref() {
|
||||
let symbol = self.add_symbol(kwarg.name.id().clone());
|
||||
self.current_place_table_mut()
|
||||
.symbol_mut(symbol)
|
||||
.mark_parameter();
|
||||
self.add_definition(
|
||||
symbol.into(),
|
||||
DefinitionNodeRef::VariadicKeywordParameter(kwarg),
|
||||
|
|
@ -1184,6 +1190,10 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
|
||||
let definition = self.add_definition(symbol.into(), parameter);
|
||||
|
||||
self.current_place_table_mut()
|
||||
.symbol_mut(symbol)
|
||||
.mark_parameter();
|
||||
|
||||
// Insert a mapping from the inner Parameter node to the same definition. This
|
||||
// ensures that calling `HasType::inferred_type` on the inner parameter returns
|
||||
// a valid type (and doesn't panic)
|
||||
|
|
@ -2248,7 +2258,9 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
let symbol_id = self.add_symbol(name.id.clone());
|
||||
let symbol = self.current_place_table().symbol(symbol_id);
|
||||
// Check whether the variable has already been accessed in this scope.
|
||||
if symbol.is_bound() || symbol.is_declared() || symbol.is_used() {
|
||||
if (symbol.is_bound() || symbol.is_declared() || symbol.is_used())
|
||||
&& !symbol.is_parameter()
|
||||
{
|
||||
self.report_semantic_error(SemanticSyntaxError {
|
||||
kind: SemanticSyntaxErrorKind::LoadBeforeGlobalDeclaration {
|
||||
name: name.to_string(),
|
||||
|
|
@ -2892,8 +2904,12 @@ impl SemanticSyntaxContext for SemanticIndexBuilder<'_, '_> {
|
|||
fn in_loop_context(&self) -> bool {
|
||||
self.current_scope_info().current_loop.is_some()
|
||||
}
|
||||
fn is_bound_parameter(&self, _name: &str) -> bool {
|
||||
false
|
||||
|
||||
fn is_bound_parameter(&self, name: &str) -> bool {
|
||||
self.scopes[self.current_scope()]
|
||||
.node()
|
||||
.as_function()
|
||||
.is_some_and(|func| func.node(self.module).parameters.includes(name))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ bitflags! {
|
|||
const MARKED_NONLOCAL = 1 << 4;
|
||||
/// true if the symbol is assigned more than once, or if it is assigned even though it is already in use
|
||||
const IS_REASSIGNED = 1 << 5;
|
||||
const IS_PARAMETER = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +117,10 @@ impl Symbol {
|
|||
self.flags.contains(SymbolFlags::IS_REASSIGNED)
|
||||
}
|
||||
|
||||
pub(crate) fn is_parameter(&self) -> bool {
|
||||
self.flags.contains(SymbolFlags::IS_PARAMETER)
|
||||
}
|
||||
|
||||
pub(super) fn mark_global(&mut self) {
|
||||
self.insert_flags(SymbolFlags::MARKED_GLOBAL);
|
||||
}
|
||||
|
|
@ -140,6 +145,10 @@ impl Symbol {
|
|||
self.insert_flags(SymbolFlags::IS_DECLARED);
|
||||
}
|
||||
|
||||
pub(super) fn mark_parameter(&mut self) {
|
||||
self.insert_flags(SymbolFlags::IS_PARAMETER);
|
||||
}
|
||||
|
||||
fn insert_flags(&mut self, flags: SymbolFlags) {
|
||||
self.flags.insert(flags);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue