@@ -249,24 +249,56 @@ mod builtins {
249249 #[ derive( FromArgs ) ]
250250 struct ScopeArgs {
251251 #[ pyarg( any, default ) ]
252- globals : Option < PyDictRef > ,
252+ globals : Option < PyObjectRef > ,
253253 #[ pyarg( any, default ) ]
254254 locals : Option < ArgMapping > ,
255255 }
256256
257257 impl ScopeArgs {
258- fn make_scope ( self , vm : & VirtualMachine ) -> PyResult < crate :: scope:: Scope > {
258+ fn make_scope (
259+ self ,
260+ vm : & VirtualMachine ,
261+ func_name : & ' static str ,
262+ ) -> PyResult < crate :: scope:: Scope > {
263+ fn validate_globals_dict (
264+ globals : & PyObjectRef ,
265+ vm : & VirtualMachine ,
266+ func_name : & ' static str ,
267+ ) -> PyResult < ( ) > {
268+ if !globals. fast_isinstance ( vm. ctx . types . dict_type ) {
269+ return Err ( match func_name {
270+ "eval" => {
271+ let is_mapping = crate :: protocol:: PyMapping :: check ( globals) ;
272+ vm. new_type_error ( if is_mapping {
273+ "globals must be a real dict; try eval(expr, {}, mapping)"
274+ . to_owned ( )
275+ } else {
276+ "globals must be a dict" . to_owned ( )
277+ } )
278+ }
279+ "exec" => vm. new_type_error ( format ! (
280+ "exec() globals must be a dict, not {}" ,
281+ globals. class( ) . name( )
282+ ) ) ,
283+ _ => vm. new_type_error ( "globals must be a dict" . to_owned ( ) ) ,
284+ } ) ;
285+ }
286+ Ok ( ( ) )
287+ }
288+
259289 let ( globals, locals) = match self . globals {
260290 Some ( globals) => {
291+ validate_globals_dict ( & globals, vm, func_name) ?;
292+
293+ let globals = PyDictRef :: try_from_object ( vm, globals) ?;
261294 if !globals. contains_key ( identifier ! ( vm, __builtins__) , vm) {
262295 let builtins_dict = vm. builtins . dict ( ) . into ( ) ;
263296 globals. set_item ( identifier ! ( vm, __builtins__) , builtins_dict, vm) ?;
264297 }
265298 (
266299 globals. clone ( ) ,
267- self . locals . unwrap_or_else ( || {
268- ArgMapping :: try_from_object ( vm, globals. into ( ) ) . unwrap ( )
269- } ) ,
300+ self . locals
301+ . unwrap_or_else ( || ArgMapping :: from_dict_exact ( globals. clone ( ) ) ) ,
270302 )
271303 }
272304 None => (
@@ -290,6 +322,8 @@ mod builtins {
290322 scope : ScopeArgs ,
291323 vm : & VirtualMachine ,
292324 ) -> PyResult {
325+ let scope = scope. make_scope ( vm, "eval" ) ?;
326+
293327 // source as string
294328 let code = match source {
295329 Either :: A ( either) => {
@@ -323,18 +357,17 @@ mod builtins {
323357 scope : ScopeArgs ,
324358 vm : & VirtualMachine ,
325359 ) -> PyResult {
360+ let scope = scope. make_scope ( vm, "exec" ) ?;
326361 run_code ( vm, source, scope, crate :: compiler:: Mode :: Exec , "exec" )
327362 }
328363
329364 fn run_code (
330365 vm : & VirtualMachine ,
331366 source : Either < PyStrRef , PyRef < crate :: builtins:: PyCode > > ,
332- scope : ScopeArgs ,
367+ scope : crate :: scope :: Scope ,
333368 #[ allow( unused_variables) ] mode : crate :: compiler:: Mode ,
334369 func : & str ,
335370 ) -> PyResult {
336- let scope = scope. make_scope ( vm) ?;
337-
338371 // Determine code object:
339372 let code_obj = match source {
340373 #[ cfg( feature = "rustpython-compiler" ) ]
0 commit comments