X Tutup
Skip to content

Commit 99862cd

Browse files
committed
ast
1 parent 8b548d0 commit 99862cd

File tree

12 files changed

+103
-71
lines changed

12 files changed

+103
-71
lines changed

Lib/test/test_ast/test_ast.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2185,7 +2185,6 @@ def test_with(self):
21852185
i = ast.withitem(ast.Constant(3), ast.Name("x", ast.Load()))
21862186
self.stmt(ast.With([i], [p]), "must have Store context")
21872187

2188-
@unittest.expectedFailure # TODO: RUSTPYTHON; ValueError not raised
21892188
def test_raise(self):
21902189
r = ast.Raise(None, ast.Constant(3))
21912190
self.stmt(r, "Raise with cause but no exception")
@@ -2194,7 +2193,6 @@ def test_raise(self):
21942193
r = ast.Raise(ast.Constant(4), ast.Name("x", ast.Store()))
21952194
self.stmt(r, "must have Load context")
21962195

2197-
@unittest.expectedFailure # TODO: RUSTPYTHON; ValueError not raised
21982196
def test_try(self):
21992197
p = ast.Pass()
22002198
t = ast.Try([], [], [], [p])
@@ -2215,7 +2213,6 @@ def test_try(self):
22152213
t = ast.Try([p], e, [p], [ast.Expr(ast.Name("x", ast.Store()))])
22162214
self.stmt(t, "must have Load context")
22172215

2218-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: ValueError not raised
22192216
def test_try_star(self):
22202217
p = ast.Pass()
22212218
t = ast.TryStar([], [], [], [p])
@@ -2246,7 +2243,6 @@ def test_assert(self):
22462243
def test_import(self):
22472244
self.stmt(ast.Import([]), "empty names on Import")
22482245

2249-
@unittest.expectedFailure # TODO: RUSTPYTHON; OverflowError: Python int too large to convert to Rust u32
22502246
def test_importfrom(self):
22512247
imp = ast.ImportFrom(None, [ast.alias("x", None)], -42)
22522248
self.stmt(imp, "Negative ImportFrom level")

Lib/test/test_builtin.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,6 @@ def test_exec_globals(self):
900900
self.assertRaises(TypeError,
901901
exec, code, {'__builtins__': 123})
902902

903-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: NameError not raised by exec
904903
def test_exec_globals_frozen(self):
905904
class frozendict_error(Exception):
906905
pass
@@ -933,7 +932,6 @@ def __setitem__(self, key, value):
933932
self.assertRaises(frozendict_error,
934933
exec, code, namespace)
935934

936-
@unittest.expectedFailure # TODO: RUSTPYTHON; NameError: name 'superglobal' is not defined
937935
def test_exec_globals_error_on_get(self):
938936
# custom `globals` or `builtins` can raise errors on item access
939937
class setonlyerror(Exception):
@@ -953,7 +951,6 @@ def __getitem__(self, key):
953951
self.assertRaises(setonlyerror, exec, code,
954952
{'__builtins__': setonlydict({'superglobal': 1})})
955953

956-
@unittest.expectedFailure # TODO: RUSTPYTHON; NameError: name 'superglobal' is not defined
957954
def test_exec_globals_dict_subclass(self):
958955
class customdict(dict): # this one should not do anything fancy
959956
pass
@@ -965,7 +962,6 @@ class customdict(dict): # this one should not do anything fancy
965962
self.assertRaisesRegex(NameError, "name 'superglobal' is not defined",
966963
exec, code, {'__builtins__': customdict()})
967964

968-
@unittest.expectedFailure # TODO: RUSTPYTHON; NameError: name 'superglobal' is not defined
969965
def test_eval_builtins_mapping(self):
970966
code = compile("superglobal", "test", "eval")
971967
# works correctly

Lib/test/test_funcattrs.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,6 @@ def test___globals__(self):
7676
self.cannot_set_attr(self.b, '__globals__', 2,
7777
(AttributeError, TypeError))
7878

79-
# TODO: RUSTPYTHON
80-
@unittest.expectedFailure
8179
def test___builtins__(self):
8280
self.assertIs(self.b.__builtins__, __builtins__)
8381
self.cannot_set_attr(self.b, '__builtins__', 2,

crates/vm/src/builtins/frame.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl Frame {
4242
}
4343

4444
#[pygetset]
45-
fn f_builtins(&self) -> PyDictRef {
45+
fn f_builtins(&self) -> PyObjectRef {
4646
self.builtins.clone()
4747
}
4848

crates/vm/src/builtins/function.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl PyFunction {
130130
let builtins = globals.get_item("__builtins__", vm).unwrap_or_else(|_| {
131131
// If not in globals, inherit from current execution context
132132
if let Some(frame) = vm.current_frame() {
133-
frame.builtins.clone().into()
133+
frame.builtins.clone()
134134
} else {
135135
vm.builtins.dict().into()
136136
}
@@ -515,7 +515,7 @@ impl Py<PyFunction> {
515515
let frame = Frame::new(
516516
code.clone(),
517517
Scope::new(Some(locals), self.globals.clone()),
518-
vm.builtins.dict(),
518+
self.builtins.clone(),
519519
self.closure.as_ref().map_or(&[], |c| c.as_slice()),
520520
Some(self.to_owned().into()),
521521
vm,

crates/vm/src/frame.rs

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub struct Frame {
7272
pub(crate) cells_frees: Box<[PyCellRef]>,
7373
pub locals: ArgMapping,
7474
pub globals: PyDictRef,
75-
pub builtins: PyDictRef,
75+
pub builtins: PyObjectRef,
7676

7777
// on feature=threading, this is a duplicate of FrameState.lasti, but it's faster to do an
7878
// atomic store than it is to do a fetch_add, for every instruction executed
@@ -137,7 +137,7 @@ impl Frame {
137137
pub(crate) fn new(
138138
code: PyRef<PyCode>,
139139
scope: Scope,
140-
builtins: PyDictRef,
140+
builtins: PyObjectRef,
141141
closure: &[PyCellRef],
142142
func_obj: Option<PyObjectRef>,
143143
vm: &VirtualMachine,
@@ -352,7 +352,7 @@ struct ExecutingFrame<'a> {
352352
cells_frees: &'a [PyCellRef],
353353
locals: &'a ArgMapping,
354354
globals: &'a PyDictRef,
355-
builtins: &'a PyDictRef,
355+
builtins: &'a PyObjectRef,
356356
object: &'a Py<Frame>,
357357
lasti: &'a Lasti,
358358
state: &'a mut FrameState,
@@ -1207,7 +1207,31 @@ impl ExecutingFrame<'_> {
12071207
Instruction::LoadAttr { idx } => self.load_attr(vm, idx.get(arg)),
12081208
Instruction::LoadSuperAttr { arg: idx } => self.load_super_attr(vm, idx.get(arg)),
12091209
Instruction::LoadBuildClass => {
1210-
self.push_value(vm.builtins.get_attr(identifier!(vm, __build_class__), vm)?);
1210+
let build_class =
1211+
if let Some(builtins_dict) = self.builtins.downcast_ref::<PyDict>() {
1212+
builtins_dict
1213+
.get_item_opt(identifier!(vm, __build_class__), vm)?
1214+
.ok_or_else(|| {
1215+
vm.new_name_error(
1216+
"__build_class__ not found".to_owned(),
1217+
identifier!(vm, __build_class__).to_owned(),
1218+
)
1219+
})?
1220+
} else {
1221+
self.builtins
1222+
.get_item(identifier!(vm, __build_class__), vm)
1223+
.map_err(|e| {
1224+
if e.fast_isinstance(vm.ctx.exceptions.key_error) {
1225+
vm.new_name_error(
1226+
"__build_class__ not found".to_owned(),
1227+
identifier!(vm, __build_class__).to_owned(),
1228+
)
1229+
} else {
1230+
e
1231+
}
1232+
})?
1233+
};
1234+
self.push_value(build_class);
12111235
Ok(None)
12121236
}
12131237
Instruction::LoadLocals => {
@@ -2124,11 +2148,26 @@ impl ExecutingFrame<'_> {
21242148

21252149
#[inline]
21262150
fn load_global_or_builtin(&self, name: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
2127-
self.globals
2128-
.get_chain(self.builtins, name, vm)?
2129-
.ok_or_else(|| {
2130-
vm.new_name_error(format!("name '{name}' is not defined"), name.to_owned())
2151+
if let Some(builtins_dict) = self.builtins.downcast_ref::<PyDict>() {
2152+
// Fast path: builtins is a dict
2153+
self.globals
2154+
.get_chain(builtins_dict, name, vm)?
2155+
.ok_or_else(|| {
2156+
vm.new_name_error(format!("name '{name}' is not defined"), name.to_owned())
2157+
})
2158+
} else {
2159+
// Slow path: builtins is not a dict, use generic __getitem__
2160+
if let Some(value) = self.globals.get_item_opt(name, vm)? {
2161+
return Ok(value);
2162+
}
2163+
self.builtins.get_item(name, vm).map_err(|e| {
2164+
if e.fast_isinstance(vm.ctx.exceptions.key_error) {
2165+
vm.new_name_error(format!("name '{name}' is not defined"), name.to_owned())
2166+
} else {
2167+
e
2168+
}
21312169
})
2170+
}
21322171
}
21332172

21342173
#[cfg_attr(feature = "flame-it", flame("Frame"))]

crates/vm/src/stdlib/ast/statement.rs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -206,17 +206,6 @@ impl Node for ast::StmtFunctionDef {
206206
let _cls = _object.class();
207207
let is_async = _cls.is(pyast::NodeStmtAsyncFunctionDef::static_type());
208208
let range = range_from_object(_vm, source_file, _object.clone(), "FunctionDef")?;
209-
let mut body: Vec<ast::Stmt> = Node::ast_from_object(
210-
_vm,
211-
source_file,
212-
get_node_field(_vm, &_object, "body", "FunctionDef")?,
213-
)?;
214-
if body.is_empty() {
215-
body.push(ast::Stmt::Pass(ast::StmtPass {
216-
node_index: Default::default(),
217-
range,
218-
}));
219-
}
220209
Ok(Self {
221210
node_index: Default::default(),
222211
name: Node::ast_from_object(
@@ -229,7 +218,11 @@ impl Node for ast::StmtFunctionDef {
229218
source_file,
230219
get_node_field(_vm, &_object, "args", "FunctionDef")?,
231220
)?,
232-
body,
221+
body: Node::ast_from_object(
222+
_vm,
223+
source_file,
224+
get_node_field(_vm, &_object, "body", "FunctionDef")?,
225+
)?,
233226
decorator_list: Node::ast_from_object(
234227
_vm,
235228
source_file,
@@ -1119,9 +1112,7 @@ impl Node for ast::StmtImportFrom {
11191112
let int: PyRef<PyInt> = obj.try_into_value(vm)?;
11201113
let value: i64 = int.try_to_primitive(vm)?;
11211114
if value < 0 {
1122-
return Err(vm.new_value_error(
1123-
"Negative ImportFrom level".to_owned(),
1124-
));
1115+
return Err(vm.new_value_error("Negative ImportFrom level".to_owned()));
11251116
}
11261117
u32::try_from(value).map_err(|_| {
11271118
vm.new_overflow_error("ImportFrom level out of range".to_owned())

crates/vm/src/stdlib/ast/string.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -589,11 +589,21 @@ fn ruff_tstring_element_to_template_str_part(
589589
format_spec,
590590
node_index: _,
591591
}) => {
592-
let expr_source =
593-
tstring_interpolation_expr_str(source_file, range, expression.range());
594-
let expr_str = debug_text
595-
.map(|dt| dt.leading.to_string() + &expr_source + &dt.trailing)
596-
.unwrap_or(expr_source);
592+
let expr_range =
593+
extend_expr_range_with_wrapping_parens(source_file, range, expression.range())
594+
.unwrap_or_else(|| expression.range());
595+
let expr_str = if let Some(debug_text) = debug_text {
596+
let expr_source = source_file.slice(expr_range);
597+
let mut expr_with_debug = String::with_capacity(
598+
debug_text.leading.len() + expr_source.len() + debug_text.trailing.len(),
599+
);
600+
expr_with_debug.push_str(&debug_text.leading);
601+
expr_with_debug.push_str(expr_source);
602+
expr_with_debug.push_str(&debug_text.trailing);
603+
strip_interpolation_expr(&expr_with_debug)
604+
} else {
605+
tstring_interpolation_expr_str(source_file, range, expr_range)
606+
};
597607
TemplateStrPart::Interpolation(TStringInterpolation {
598608
value: expression,
599609
str: expr_str,
@@ -610,12 +620,9 @@ fn tstring_interpolation_expr_str(
610620
interpolation_range: TextRange,
611621
expr_range: TextRange,
612622
) -> String {
613-
let expr_range = extend_expr_range_with_wrapping_parens(
614-
source_file,
615-
interpolation_range,
616-
expr_range,
617-
)
618-
.unwrap_or(expr_range);
623+
let expr_range =
624+
extend_expr_range_with_wrapping_parens(source_file, interpolation_range, expr_range)
625+
.unwrap_or(expr_range);
619626
let start = interpolation_range.start() + TextSize::from(1);
620627
let start = if start > expr_range.end() {
621628
expr_range.start()

crates/vm/src/stdlib/ast/validate.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,7 @@ fn validate_expr(vm: &VirtualMachine, expr: &ast::Expr, ctx: ast::ExprContext) -
342342
match expr {
343343
ast::Expr::BoolOp(op) => {
344344
if op.values.len() < 2 {
345-
return Err(vm.new_value_error(
346-
"BoolOp with less than 2 values".to_owned(),
347-
));
345+
return Err(vm.new_value_error("BoolOp with less than 2 values".to_owned()));
348346
}
349347
validate_exprs(vm, &op.values, ast::ExprContext::Load, false)
350348
}
@@ -521,9 +519,7 @@ fn validate_stmt(vm: &VirtualMachine, stmt: &ast::Stmt) -> PyResult<()> {
521519
}
522520
ast::Stmt::AnnAssign(assign) => {
523521
if assign.simple && !matches!(&*assign.target, ast::Expr::Name(_)) {
524-
return Err(
525-
vm.new_type_error("AnnAssign with simple non-Name target".to_owned())
526-
);
522+
return Err(vm.new_type_error("AnnAssign with simple non-Name target".to_owned()));
527523
}
528524
validate_expr(vm, &assign.target, ast::ExprContext::Store)?;
529525
if let Some(value) = &assign.value {
@@ -596,9 +592,7 @@ fn validate_stmt(vm: &VirtualMachine, stmt: &ast::Stmt) -> PyResult<()> {
596592
validate_expr(vm, cause, ast::ExprContext::Load)?;
597593
}
598594
} else if raise.cause.is_some() {
599-
return Err(
600-
vm.new_value_error("Raise with cause but no exception".to_owned())
601-
);
595+
return Err(vm.new_value_error("Raise with cause but no exception".to_owned()));
602596
}
603597
Ok(())
604598
}
@@ -611,9 +605,9 @@ fn validate_stmt(vm: &VirtualMachine, stmt: &ast::Stmt) -> PyResult<()> {
611605
)));
612606
}
613607
if try_stmt.handlers.is_empty() && !try_stmt.orelse.is_empty() {
614-
return Err(vm.new_value_error(format!(
615-
"{owner} has orelse but no except handlers"
616-
)));
608+
return Err(
609+
vm.new_value_error(format!("{owner} has orelse but no except handlers"))
610+
);
617611
}
618612
for handler in &try_stmt.handlers {
619613
let ast::ExceptHandler::ExceptHandler(handler) = handler;

crates/vm/src/suggestion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub fn offer_suggestions(exc: &Py<PyBaseException>, vm: &VirtualMachine) -> Opti
6868
return Some(suggestions);
6969
};
7070

71-
let builtins: Vec<_> = tb.frame.builtins.as_object().try_to_value(vm).ok()?;
71+
let builtins: Vec<_> = tb.frame.builtins.try_to_value(vm).ok()?;
7272
calculate_suggestions(builtins.iter(), &name)
7373
} else {
7474
None

0 commit comments

Comments
 (0)
X Tutup