Skip to content

Commit 488d9a5

Browse files
committed
Merge branch 'master' into joey/int-any
2 parents f9ab272 + ac65215 commit 488d9a5

File tree

8 files changed

+71
-48
lines changed

8 files changed

+71
-48
lines changed

tests/snippets/bools.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
assert bool(1) == True
1717
assert bool({}) == False
1818

19+
assert bool(NotImplemented) == True
20+
assert bool(...) == True
21+
1922
if not 1:
2023
raise BaseException
2124

vm/src/frame.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -580,18 +580,15 @@ impl Frame {
580580
}
581581
bytecode::Instruction::PrintExpr => {
582582
let expr = self.pop_value();
583-
match expr.payload {
584-
PyObjectPayload::None => (),
585-
_ => {
586-
let repr = vm.to_repr(&expr)?;
587-
builtins::builtin_print(
588-
vm,
589-
PyFuncArgs {
590-
args: vec![repr],
591-
kwargs: vec![],
592-
},
593-
)?;
594-
}
583+
if !expr.is(&vm.get_none()) {
584+
let repr = vm.to_repr(&expr)?;
585+
builtins::builtin_print(
586+
vm,
587+
PyFuncArgs {
588+
args: vec![repr],
589+
kwargs: vec![],
590+
},
591+
)?;
595592
}
596593
Ok(None)
597594
}

vm/src/obj/objbool.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl IntoPyObject for bool {
1717
}
1818
}
1919

20-
pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObjectRef> {
20+
pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
2121
if let Some(s) = obj.payload::<PyString>() {
2222
return Ok(!s.value.is_empty());
2323
}
@@ -32,7 +32,6 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObje
3232
}
3333
let result = match obj.payload {
3434
PyObjectPayload::Sequence { ref elements } => !elements.borrow().is_empty(),
35-
PyObjectPayload::None { .. } => false,
3635
_ => {
3736
if let Ok(f) = vm.get_method(obj.clone(), "__bool__") {
3837
let bool_res = vm.invoke(f, PyFuncArgs::default())?;

vm/src/obj/objnone.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub fn init(context: &PyContext) {
55
let none_type = &context.none.typ();
66
context.set_attr(&none_type, "__new__", context.new_rustfunc(none_new));
77
context.set_attr(&none_type, "__repr__", context.new_rustfunc(none_repr));
8+
context.set_attr(&none_type, "__bool__", context.new_rustfunc(none_bool));
89
}
910

1011
fn none_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -20,3 +21,8 @@ fn none_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
2021
arg_check!(vm, args, required = [(_zelf, Some(vm.ctx.none().typ()))]);
2122
Ok(vm.ctx.new_str("None".to_string()))
2223
}
24+
25+
fn none_bool(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
26+
arg_check!(vm, args, required = [(_zelf, Some(vm.ctx.none().typ()))]);
27+
Ok(vm.ctx.new_bool(false))
28+
}

vm/src/obj/objstr.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use super::objtype;
44
use crate::format::{FormatParseError, FormatPart, FormatString};
55
use crate::function::PyRef;
66
use crate::pyobject::{
7-
IntoPyObject, OptArg, PyContext, PyFuncArgs, PyIterable, PyObjectPayload, PyObjectPayload2,
8-
PyObjectRef, PyResult, TypeProtocol,
7+
IntoPyObject, OptionalArg, PyContext, PyFuncArgs, PyIterable, PyObjectPayload,
8+
PyObjectPayload2, PyObjectRef, PyResult, TypeProtocol,
99
};
1010
use crate::vm::VirtualMachine;
1111
use num_traits::ToPrimitive;
@@ -160,24 +160,24 @@ impl PyStringRef {
160160
fn endswith(
161161
self,
162162
suffix: PyStringRef,
163-
start: OptArg<usize>,
164-
end: OptArg<usize>,
163+
start: OptionalArg<usize>,
164+
end: OptionalArg<usize>,
165165
_vm: &mut VirtualMachine,
166166
) -> bool {
167-
let start = start.unwrap_or(0);
168-
let end = end.unwrap_or(self.value.len());
167+
let start = start.into_option().unwrap_or(0);
168+
let end = end.into_option().unwrap_or(self.value.len());
169169
self.value[start..end].ends_with(&suffix.value)
170170
}
171171

172172
fn startswith(
173173
self,
174174
prefix: PyStringRef,
175-
start: OptArg<usize>,
176-
end: OptArg<usize>,
175+
start: OptionalArg<usize>,
176+
end: OptionalArg<usize>,
177177
_vm: &mut VirtualMachine,
178178
) -> bool {
179-
let start = start.unwrap_or(0);
180-
let end = end.unwrap_or(self.value.len());
179+
let start = start.into_option().unwrap_or(0);
180+
let end = end.into_option().unwrap_or(self.value.len());
181181
self.value[start..end].starts_with(&prefix.value)
182182
}
183183

vm/src/pyobject.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ pub struct PyContext {
156156

157157
fn _nothing() -> PyObjectRef {
158158
PyObject {
159-
payload: PyObjectPayload::None,
159+
payload: PyObjectPayload::AnyRustValue {
160+
value: Box::new(()),
161+
},
160162
typ: None,
161163
}
162164
.into_ref()
@@ -224,14 +226,23 @@ impl PyContext {
224226
let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type, &dict_type);
225227

226228
let none = PyObject::new(
227-
PyObjectPayload::None,
229+
PyObjectPayload::AnyRustValue {
230+
value: Box::new(()),
231+
},
228232
create_type("NoneType", &type_type, &object_type, &dict_type),
229233
);
230234

231-
let ellipsis = PyObject::new(PyObjectPayload::None, ellipsis_type.clone());
235+
let ellipsis = PyObject::new(
236+
PyObjectPayload::AnyRustValue {
237+
value: Box::new(()),
238+
},
239+
ellipsis_type.clone(),
240+
);
232241

233242
let not_implemented = PyObject::new(
234-
PyObjectPayload::NotImplemented,
243+
PyObjectPayload::AnyRustValue {
244+
value: Box::new(()),
245+
},
235246
create_type("NotImplementedType", &type_type, &object_type, &dict_type),
236247
);
237248

@@ -1214,17 +1225,26 @@ where
12141225
}
12151226
}
12161227

1217-
pub struct OptArg<T>(Option<T>);
1228+
/// An argument that may or may not be provided by the caller.
1229+
///
1230+
/// This style of argument is not possible in pure Python.
1231+
pub enum OptionalArg<T> {
1232+
Present(T),
1233+
Missing,
1234+
}
12181235

1219-
impl<T> std::ops::Deref for OptArg<T> {
1220-
type Target = Option<T>;
1236+
use self::OptionalArg::*;
12211237

1222-
fn deref(&self) -> &Option<T> {
1223-
&self.0
1238+
impl<T> OptionalArg<T> {
1239+
pub fn into_option(self) -> Option<T> {
1240+
match self {
1241+
Present(value) => Some(value),
1242+
Missing => None,
1243+
}
12241244
}
12251245
}
12261246

1227-
impl<T> FromArgs for OptArg<T>
1247+
impl<T> FromArgs for OptionalArg<T>
12281248
where
12291249
T: TryFromObject,
12301250
{
@@ -1239,16 +1259,16 @@ where
12391259
where
12401260
I: Iterator<Item = PyArg>,
12411261
{
1242-
Ok(OptArg(if let Some(PyArg::Positional(_)) = args.peek() {
1262+
Ok(if let Some(PyArg::Positional(_)) = args.peek() {
12431263
let value = if let Some(PyArg::Positional(value)) = args.next() {
12441264
value
12451265
} else {
12461266
unreachable!()
12471267
};
1248-
Some(T::try_from_object(vm, value)?)
1268+
Present(T::try_from_object(vm, value)?)
12491269
} else {
1250-
None
1251-
}))
1270+
Missing
1271+
})
12521272
}
12531273
}
12541274

@@ -1499,8 +1519,6 @@ pub enum PyObjectPayload {
14991519
name: String,
15001520
scope: ScopeRef,
15011521
},
1502-
None,
1503-
NotImplemented,
15041522
Class {
15051523
name: String,
15061524
dict: RefCell<PyAttributes>,
@@ -1540,8 +1558,6 @@ impl fmt::Debug for PyObjectPayload {
15401558
ref object,
15411559
} => write!(f, "bound-method: {:?} of {:?}", function, object),
15421560
PyObjectPayload::Module { .. } => write!(f, "module"),
1543-
PyObjectPayload::None => write!(f, "None"),
1544-
PyObjectPayload::NotImplemented => write!(f, "NotImplemented"),
15451561
PyObjectPayload::Class { ref name, .. } => write!(f, "class {:?}", name),
15461562
PyObjectPayload::Instance { .. } => write!(f, "instance"),
15471563
PyObjectPayload::RustFunction { .. } => write!(f, "rust function"),

vm/src/stdlib/json.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::obj::{
1111
objtype,
1212
};
1313
use crate::pyobject::{
14-
create_type, DictProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult,
14+
create_type, DictProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult,
1515
TypeProtocol,
1616
};
1717
use crate::VirtualMachine;
@@ -69,7 +69,7 @@ impl<'s> serde::Serialize for PyObjectSerializer<'s> {
6969
map.serialize_entry(&key, &self.clone_with_object(&e.1))?;
7070
}
7171
map.end()
72-
} else if let PyObjectPayload::None = self.pyobject.payload {
72+
} else if self.pyobject.is(&self.vm.get_none()) {
7373
serializer.serialize_none()
7474
} else {
7575
Err(serde::ser::Error::custom(format!(

vm/src/vm.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,10 +444,12 @@ impl VirtualMachine {
444444
// Add missing positional arguments, if we have fewer positional arguments than the
445445
// function definition calls for
446446
if nargs < nexpected_args {
447-
let available_defaults = match defaults.payload {
448-
PyObjectPayload::Sequence { ref elements } => elements.borrow().clone(),
449-
PyObjectPayload::None => vec![],
450-
_ => panic!("function defaults not tuple or None"),
447+
let available_defaults = if defaults.is(&self.get_none()) {
448+
vec![]
449+
} else if let PyObjectPayload::Sequence { ref elements } = defaults.payload {
450+
elements.borrow().clone()
451+
} else {
452+
panic!("function defaults not tuple or None");
451453
};
452454

453455
// Given the number of defaults available, check all the arguments for which we

0 commit comments

Comments
 (0)