Skip to content

Commit 69efc7f

Browse files
committed
Compile type annotations on function.
1 parent 0000551 commit 69efc7f

File tree

4 files changed

+58
-4
lines changed

4 files changed

+58
-4
lines changed

tests/snippets/type_hints.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
# See also: https://github.com/RustPython/RustPython/issues/587
33

4-
def curry(foo: int) -> float:
5-
return foo * 3.1415926 * 2
4+
def curry(foo: int, bla=2) -> float:
5+
return foo * 3.1415926 * bla
66

77
assert curry(2) > 10

vm/src/bytecode.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub struct CodeObject {
3131
bitflags! {
3232
pub struct FunctionOpArg: u8 {
3333
const HAS_DEFAULTS = 0x01;
34+
const HAS_ANNOTATIONS = 0x04;
3435
}
3536
}
3637

vm/src/compile.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,15 +589,15 @@ impl Compiler {
589589
args: &ast::Parameters,
590590
body: &[ast::LocatedStatement],
591591
decorator_list: &[ast::Expression],
592-
_returns: &Option<ast::Expression>, // TODO: use type hint somehow..
592+
returns: &Option<ast::Expression>, // TODO: use type hint somehow..
593593
) -> Result<(), CompileError> {
594594
// Create bytecode for this function:
595595
// remember to restore self.in_loop to the original after the function is compiled
596596
let was_in_loop = self.in_loop;
597597
let was_in_function_def = self.in_function_def;
598598
self.in_loop = false;
599599
self.in_function_def = true;
600-
let flags = self.enter_function(name, args)?;
600+
let mut flags = self.enter_function(name, args)?;
601601
self.compile_statements(body)?;
602602

603603
// Emit None at end:
@@ -608,6 +608,43 @@ impl Compiler {
608608
let code = self.pop_code_object();
609609

610610
self.prepare_decorators(decorator_list)?;
611+
612+
// Prepare type annotations:
613+
let mut num_annotations = 0;
614+
615+
// Return annotation:
616+
if let Some(annotation) = returns {
617+
// key:
618+
self.emit(Instruction::LoadConst {
619+
value: bytecode::Constant::String {
620+
value: "returns".to_string(),
621+
},
622+
});
623+
// value:
624+
self.compile_expression(annotation)?;
625+
num_annotations += 1;
626+
}
627+
628+
for arg in args.args.iter() {
629+
if let Some(annotation) = &arg.annotation {
630+
self.emit(Instruction::LoadConst {
631+
value: bytecode::Constant::String {
632+
value: arg.arg.to_string(),
633+
},
634+
});
635+
self.compile_expression(&annotation)?;
636+
num_annotations += 1;
637+
}
638+
}
639+
640+
if num_annotations > 0 {
641+
flags |= bytecode::FunctionOpArg::HAS_ANNOTATIONS;
642+
self.emit(Instruction::BuildMap {
643+
size: num_annotations,
644+
unpack: false,
645+
});
646+
}
647+
611648
self.emit(Instruction::LoadConst {
612649
value: bytecode::Constant::Code {
613650
code: Box::new(code),

vm/src/frame.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,15 +447,31 @@ impl Frame {
447447
bytecode::Instruction::MakeFunction { flags } => {
448448
let _qualified_name = self.pop_value();
449449
let code_obj = self.pop_value();
450+
451+
let _annotations = if flags.contains(bytecode::FunctionOpArg::HAS_ANNOTATIONS) {
452+
self.pop_value()
453+
} else {
454+
vm.new_dict()
455+
};
456+
450457
let defaults = if flags.contains(bytecode::FunctionOpArg::HAS_DEFAULTS) {
451458
self.pop_value()
452459
} else {
453460
vm.get_none()
454461
};
462+
455463
// pop argc arguments
456464
// argument: name, args, globals
457465
let scope = self.scope.clone();
458466
let obj = vm.ctx.new_function(code_obj, scope, defaults);
467+
468+
let annotation_repr = vm.to_pystr(&_annotations)?;
469+
470+
warn!(
471+
"Type annotation must be stored in attribute! {:?}",
472+
annotation_repr
473+
);
474+
// TODO: use annotations with set_attr here!
459475
self.push_value(obj);
460476
Ok(None)
461477
}

0 commit comments

Comments
 (0)