diff --git a/vm/src/frame.rs b/vm/src/frame.rs index a72ed6a76..e8276d1c8 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -129,6 +129,8 @@ pub trait NameProtocol { fn store_name(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef); fn delete_name(&self, vm: &VirtualMachine, name: &str); fn load_cell(&self, vm: &VirtualMachine, name: &str) -> Option; + fn load_global(&self, vm: &VirtualMachine, name: &str) -> Option; + fn store_global(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef); } impl NameProtocol for Scope { @@ -162,6 +164,14 @@ impl NameProtocol for Scope { fn delete_name(&self, vm: &VirtualMachine, key: &str) { self.get_locals().del_item(key, vm).unwrap(); } + + fn load_global(&self, vm: &VirtualMachine, name: &str) -> Option { + self.globals.get_item_option(name, vm).unwrap() + } + + fn store_global(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef) { + self.globals.set_item(name, value, vm).unwrap(); + } } #[derive(Clone, Debug)] @@ -994,12 +1004,12 @@ impl Frame { &self, vm: &VirtualMachine, name: &str, - scope: &bytecode::NameScope, + name_scope: &bytecode::NameScope, ) -> FrameResult { let obj = self.pop_value(); - match scope { + match name_scope { bytecode::NameScope::Global => { - self.scope.globals.set_item(name, obj, vm)?; + self.scope.store_global(vm, name, obj); } bytecode::NameScope::Local => { self.scope.store_name(&vm, name, obj); @@ -1017,19 +1027,21 @@ impl Frame { &self, vm: &VirtualMachine, name: &str, - scope: &bytecode::NameScope, + name_scope: &bytecode::NameScope, ) -> FrameResult { - let value = match scope { - bytecode::NameScope::Global => self.scope.globals.get_item(name, vm)?, - bytecode::NameScope::Local => match self.scope.load_name(&vm, name) { - Some(value) => value, - None => { - let name_error_type = vm.ctx.exceptions.name_error.clone(); - let msg = format!("name '{}' is not defined", name); - let name_error = vm.new_exception(name_error_type, msg); - return Err(name_error); - } - }, + let optional_value = match name_scope { + bytecode::NameScope::Global => self.scope.load_global(vm, name), + bytecode::NameScope::Local => self.scope.load_name(&vm, name), + }; + + let value = match optional_value { + Some(value) => value, + None => { + let name_error_type = vm.ctx.exceptions.name_error.clone(); + let msg = format!("name '{}' is not defined", name); + let name_error = vm.new_exception(name_error_type, msg); + return Err(name_error); + } }; self.push_value(value); diff --git a/vm/src/symboltable.rs b/vm/src/symboltable.rs index 2d6b49884..d7f30c870 100644 --- a/vm/src/symboltable.rs +++ b/vm/src/symboltable.rs @@ -111,6 +111,17 @@ impl SymbolTableBuilder { } fn scan_parameter(&mut self, parameter: &ast::Parameter) -> SymbolTableResult { + self.register_name(¶meter.arg, SymbolRole::Assigned) + } + + fn scan_parameters_annotations(&mut self, parameters: &[ast::Parameter]) -> SymbolTableResult { + for parameter in parameters { + self.scan_parameter_annotation(parameter)?; + } + Ok(()) + } + + fn scan_parameter_annotation(&mut self, parameter: &ast::Parameter) -> SymbolTableResult { if let Some(annotation) = ¶meter.annotation { self.scan_expression(&annotation)?; } @@ -394,7 +405,19 @@ impl SymbolTableBuilder { } } + // Annotations are scanned in outer scope: + self.scan_parameters_annotations(&args.args)?; + self.scan_parameters_annotations(&args.kwonlyargs)?; + if let ast::Varargs::Named(name) = &args.vararg { + self.scan_parameter_annotation(name)?; + } + if let ast::Varargs::Named(name) = &args.kwarg { + self.scan_parameter_annotation(name)?; + } + self.enter_scope(); + + // Fill scope with parameter names: self.scan_parameters(&args.args)?; self.scan_parameters(&args.kwonlyargs)?; if let ast::Varargs::Named(name) = &args.vararg {