Skip to content

Commit a3081c5

Browse files
Merge pull request RustPython#1336 from RustPython/comprehension-scope
Add symboltable scope for comprehensions.
2 parents 6217e7e + b36bbfa commit a3081c5

File tree

3 files changed

+52
-12
lines changed

3 files changed

+52
-12
lines changed

compiler/src/compile.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,6 +1782,7 @@ impl<O: OutputStream> Compiler<O> {
17821782
line_number,
17831783
name.clone(),
17841784
));
1785+
self.enter_scope();
17851786

17861787
// Create empty object of proper type:
17871788
match kind {
@@ -1891,6 +1892,9 @@ impl<O: OutputStream> Compiler<O> {
18911892
// Fetch code for listcomp function:
18921893
let code = self.pop_code_object();
18931894

1895+
// Pop scope
1896+
self.leave_scope();
1897+
18941898
// List comprehension code:
18951899
self.emit(Instruction::LoadConst {
18961900
value: bytecode::Constant::Code {

compiler/src/symboltable.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,23 @@ impl SymbolTableBuilder {
591591
self.scan_expressions(elements, context)?;
592592
}
593593
Comprehension { kind, generators } => {
594+
// Comprehensions are compiled as functions, so create a scope for them:
595+
let scope_name = match **kind {
596+
ast::ComprehensionKind::GeneratorExpression { .. } => "genexpr",
597+
ast::ComprehensionKind::List { .. } => "listcomp",
598+
ast::ComprehensionKind::Set { .. } => "setcomp",
599+
ast::ComprehensionKind::Dict { .. } => "dictcomp",
600+
};
601+
602+
self.enter_scope(
603+
scope_name,
604+
SymbolTableType::Function,
605+
expression.location.row(),
606+
);
607+
608+
// Register the passed argument to the generator function as the name ".0"
609+
self.register_name(".0", SymbolUsage::Parameter)?;
610+
594611
match **kind {
595612
ast::ComprehensionKind::GeneratorExpression { ref element }
596613
| ast::ComprehensionKind::List { ref element }
@@ -603,13 +620,25 @@ impl SymbolTableBuilder {
603620
}
604621
}
605622

623+
let mut is_first_generator = true;
606624
for generator in generators {
607625
self.scan_expression(&generator.target, &ExpressionContext::Store)?;
608-
self.scan_expression(&generator.iter, &ExpressionContext::Load)?;
626+
if is_first_generator {
627+
is_first_generator = false;
628+
} else {
629+
self.scan_expression(&generator.iter, &ExpressionContext::Load)?;
630+
}
631+
609632
for if_expr in &generator.ifs {
610633
self.scan_expression(if_expr, &ExpressionContext::Load)?;
611634
}
612635
}
636+
637+
self.leave_scope();
638+
639+
// The first iterable is passed as an argument into the created function:
640+
assert!(!generators.is_empty());
641+
self.scan_expression(&generators[0].iter, &ExpressionContext::Load)?;
613642
}
614643
Call {
615644
function,

vm/src/stdlib/ast.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -456,18 +456,25 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
456456
let py_generators = map_ast(comprehension_to_ast, vm, generators)?;
457457

458458
match kind.deref() {
459-
ast::ComprehensionKind::GeneratorExpression { .. } => {
460-
node!(vm, GeneratorExp, {generators => py_generators})
461-
}
462-
ast::ComprehensionKind::List { .. } => {
463-
node!(vm, ListComp, {generators => py_generators})
464-
}
465-
ast::ComprehensionKind::Set { .. } => {
466-
node!(vm, SetComp, {generators => py_generators})
467-
}
468-
ast::ComprehensionKind::Dict { .. } => {
469-
node!(vm, DictComp, {generators => py_generators})
459+
ast::ComprehensionKind::GeneratorExpression { element } => {
460+
node!(vm, GeneratorExp, {
461+
elt => expression_to_ast(vm, element)?,
462+
generators => py_generators
463+
})
470464
}
465+
ast::ComprehensionKind::List { element } => node!(vm, ListComp, {
466+
elt => expression_to_ast(vm, element)?,
467+
generators => py_generators
468+
}),
469+
ast::ComprehensionKind::Set { element } => node!(vm, SetComp, {
470+
elt => expression_to_ast(vm, element)?,
471+
generators => py_generators
472+
}),
473+
ast::ComprehensionKind::Dict { key, value } => node!(vm, DictComp, {
474+
key => expression_to_ast(vm, key)?,
475+
value => expression_to_ast(vm, value)?,
476+
generators => py_generators
477+
}),
471478
}
472479
}
473480
Await { value } => {

0 commit comments

Comments
 (0)