Skip to content

Commit 1e79d06

Browse files
authored
Merge pull request RustPython#2190 from minoring/nonlocal-incompatibility
Fix nonlocal incompatibility
2 parents 435d364 + e24a723 commit 1e79d06

File tree

2 files changed

+50
-39
lines changed

2 files changed

+50
-39
lines changed

Lib/test/test_grammar.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,14 +1161,13 @@ def test_global(self):
11611161
global a, b
11621162
global one, two, three, four, five, six, seven, eight, nine, ten
11631163

1164-
# TODO: RUSTPYTHON
1165-
# def test_nonlocal(self):
1166-
# # 'nonlocal' NAME (',' NAME)*
1167-
# x = 0
1168-
# y = 0
1169-
# def f():
1170-
# nonlocal x
1171-
# nonlocal x, y
1164+
def test_nonlocal(self):
1165+
# 'nonlocal' NAME (',' NAME)*
1166+
x = 0
1167+
y = 0
1168+
def f():
1169+
nonlocal x
1170+
nonlocal x, y
11721171

11731172
def test_assert(self):
11741173
# assertTruestmt: 'assert' test [',' test]

compiler/src/symboltable.rs

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -951,13 +951,11 @@ impl SymbolTableBuilder {
951951
let table = self.tables.last_mut().unwrap();
952952
let location = Default::default();
953953

954-
// Some checks:
955-
let containing = table.symbols.contains_key(name);
956-
if containing {
954+
// Some checks for the symbol that present on this scope level:
955+
if let Some(symbol) = table.symbols.get(name) {
957956
// Role already set..
958957
match role {
959958
SymbolUsage::Global => {
960-
let symbol = table.symbols.get(name).unwrap();
961959
if let SymbolScope::Global = symbol.scope {
962960
// Ok
963961
} else {
@@ -968,32 +966,53 @@ impl SymbolTableBuilder {
968966
}
969967
}
970968
SymbolUsage::Nonlocal => {
969+
if symbol.is_parameter {
970+
return Err(SymbolTableError {
971+
error: format!("name '{}' is parameter and nonlocal", name),
972+
location,
973+
});
974+
}
975+
if symbol.is_referenced {
976+
return Err(SymbolTableError {
977+
error: format!("name '{}' is used prior to nonlocal declaration", name),
978+
location,
979+
});
980+
}
981+
if symbol.is_annotated {
982+
return Err(SymbolTableError {
983+
error: format!("annotated name '{}' can't be nonlocal", name),
984+
location,
985+
});
986+
}
987+
if symbol.is_assigned {
988+
return Err(SymbolTableError {
989+
error: format!(
990+
"name '{}' is assigned to before nonlocal declaration",
991+
name
992+
),
993+
location,
994+
});
995+
}
996+
}
997+
_ => {
998+
// Ok?
999+
}
1000+
}
1001+
} else {
1002+
// The symbol does not present on this scope level.
1003+
// Some checks to insert new symbol into symbol table:
1004+
match role {
1005+
SymbolUsage::Nonlocal if scope_depth < 2 => {
9711006
return Err(SymbolTableError {
972-
error: format!("name '{}' is used prior to nonlocal declaration", name),
1007+
error: format!("cannot define nonlocal '{}' at top level.", name),
9731008
location,
9741009
})
9751010
}
9761011
_ => {
977-
// Ok?
1012+
// Ok!
9781013
}
9791014
}
980-
}
981-
982-
// Some more checks:
983-
match role {
984-
SymbolUsage::Nonlocal if scope_depth < 2 => {
985-
return Err(SymbolTableError {
986-
error: format!("cannot define nonlocal '{}' at top level.", name),
987-
location,
988-
})
989-
}
990-
_ => {
991-
// Ok!
992-
}
993-
}
994-
995-
// Insert symbol when required:
996-
if !containing {
1015+
// Insert symbol when required:
9971016
let symbol = Symbol::new(name);
9981017
table.symbols.insert(name.to_owned(), symbol);
9991018
}
@@ -1002,14 +1021,7 @@ impl SymbolTableBuilder {
10021021
let symbol = table.symbols.get_mut(name).unwrap();
10031022
match role {
10041023
SymbolUsage::Nonlocal => {
1005-
if let SymbolScope::Unknown = symbol.scope {
1006-
symbol.scope = SymbolScope::Nonlocal;
1007-
} else {
1008-
return Err(SymbolTableError {
1009-
error: format!("Symbol {} scope cannot be set to nonlocal, since its scope was already determined otherwise.", name),
1010-
location,
1011-
});
1012-
}
1024+
symbol.scope = SymbolScope::Nonlocal;
10131025
}
10141026
SymbolUsage::Imported => {
10151027
symbol.is_assigned = true;

0 commit comments

Comments
 (0)