Skip to content

Commit b3eae35

Browse files
committed
Add support for functions returning a mutable reference, add and update tests to verify this.
1 parent fac04c1 commit b3eae35

File tree

11 files changed

+490
-340
lines changed

11 files changed

+490
-340
lines changed

library/src/main/kotlin/org/rustlang/core/Core.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,4 +635,21 @@ public fun core_slice_u8_starts_with(value: Any, prefix: Any): Boolean {
635635
// if the compared prefix is identical.
636636
return 0
637637
}
638+
639+
@JvmStatic
640+
public fun core_num_u32_saturating_sub(a: Long, b: Long): Long {
641+
val result = a - b
642+
return if (result < 0L) 0L else result
643+
}
644+
645+
@JvmStatic
646+
public fun std_intrinsics_saturating_sub_u32(a: Long, b: Long): Long {
647+
val result = a - b
648+
return if (result < 0L) 0L else result
649+
}
650+
651+
@JvmStatic
652+
public fun u32_min(a: Long, b: Long): Long {
653+
return if (a < b) a else b
654+
}
638655
}

shim-metadata-gen/core.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
"descriptor": "([Ljava/lang/String;)Ljava/lang/String;",
4848
"is_static": true
4949
},
50+
"core_num_u32_saturating_sub": {
51+
"descriptor": "(JJ)J",
52+
"is_static": true
53+
},
5054
"core_panicking_panic": {
5155
"descriptor": "(Ljava/lang/String;)V",
5256
"is_static": true
@@ -123,6 +127,10 @@
123127
"descriptor": "(Ljava/lang/Object;Ljava/lang/Object;)Z",
124128
"is_static": true
125129
},
130+
"std_intrinsics_saturating_sub_u32": {
131+
"descriptor": "(JJ)J",
132+
"is_static": true
133+
},
126134
"std_intrinsics_size_of_val_u8": {
127135
"descriptor": "(Ljava/lang/Object;)J",
128136
"is_static": true
@@ -139,6 +147,10 @@
139147
"descriptor": "(Ljava/lang/Object;)Ljava/lang/String;",
140148
"is_static": true
141149
},
150+
"u32_min": {
151+
"descriptor": "(JJ)J",
152+
"is_static": true
153+
},
142154
"u8_8_eq": {
143155
"descriptor": "(Ljava/lang/Object;Ljava/lang/Object;)Z",
144156
"is_static": true

src/lib.rs

Lines changed: 98 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -550,82 +550,111 @@ impl CodegenBackend for MyBackend {
550550

551551
let mut bbs = HashMap::new();
552552

553-
let mut to_call_invokevirtual_on = "_1".to_string();
553+
// Determine if this impl item is an instance method (has self receiver of this class)
554+
let is_instance_method = match oomir_function.signature.params.first() {
555+
Some(Type::Class(name)) => *name == ident,
556+
Some(Type::MutableReference(box Type::Class(name))) => *name == ident,
557+
_ => false,
558+
};
554559

555-
if let oomir::Operand::Variable { ty, .. } = &args[0] {
556-
// &mut self
557-
if ty
558-
== &oomir::Type::MutableReference(Box::new(oomir::Type::Class(
559-
ident.clone(),
560-
)))
561-
{
562-
instructions.push(oomir::Instruction::Cast {
563-
op: Operand::Variable {
564-
name: "_1".into(),
565-
ty: Type::MutableReference(Box::new(Type::Class(
566-
ident.clone(),
567-
))),
568-
},
569-
ty: Type::Class(ident.clone()),
570-
dest: "_1_mutderef".into(),
571-
});
572-
to_call_invokevirtual_on = "_1_mutderef".to_string();
573-
} else if *ty != oomir::Type::Class(ident.clone()) {
574-
instructions.push(oomir::Instruction::ConstructObject {
575-
dest: "_1_instance".into(),
576-
class_name: ident.clone(),
577-
});
578-
to_call_invokevirtual_on = "_1_instance".into();
560+
if is_instance_method {
561+
let mut to_call_invokevirtual_on = "_1".to_string();
562+
// args[0] exists because it's an instance method
563+
if let oomir::Operand::Variable { ty, .. } = &args[0] {
564+
// &mut self
565+
if ty
566+
== &oomir::Type::MutableReference(Box::new(oomir::Type::Class(
567+
ident.clone(),
568+
)))
569+
{
570+
instructions.push(oomir::Instruction::Cast {
571+
op: Operand::Variable {
572+
name: "_1".into(),
573+
ty: Type::MutableReference(Box::new(Type::Class(
574+
ident.clone(),
575+
))),
576+
},
577+
ty: Type::Class(ident.clone()),
578+
dest: "_1_mutderef".into(),
579+
});
580+
to_call_invokevirtual_on = "_1_mutderef".to_string();
581+
} else if *ty != oomir::Type::Class(ident.clone()) {
582+
instructions.push(oomir::Instruction::ConstructObject {
583+
dest: "_1_instance".into(),
584+
class_name: ident.clone(),
585+
});
586+
to_call_invokevirtual_on = "_1_instance".into();
587+
}
579588
}
580-
}
581589

582-
instructions.extend(vec![
583-
oomir::Instruction::InvokeVirtual {
584-
operand: Operand::Variable {
585-
name: to_call_invokevirtual_on,
586-
ty: Type::Class(ident.clone()),
587-
},
588-
class_name: ident.to_string(),
589-
method_name: i.to_string(),
590-
method_ty: oomir_function.signature.clone(),
591-
args,
592-
dest: if has_return {
593-
Some("dest".into())
594-
} else {
595-
None
590+
instructions.extend(vec![
591+
oomir::Instruction::InvokeVirtual {
592+
operand: Operand::Variable {
593+
name: to_call_invokevirtual_on,
594+
ty: Type::Class(ident.clone()),
595+
},
596+
class_name: ident.to_string(),
597+
method_name: i.to_string(),
598+
method_ty: oomir_function.signature.clone(),
599+
args,
600+
dest: if has_return {
601+
Some("dest".into())
602+
} else {
603+
None
604+
},
596605
},
597-
},
598-
oomir::Instruction::Return {
599-
operand: if has_return {
600-
Some(Operand::Variable {
601-
name: "dest".into(),
602-
ty: *oomir_function.signature.ret.clone(),
603-
})
604-
} else {
605-
None
606+
oomir::Instruction::Return {
607+
operand: if has_return {
608+
Some(Operand::Variable {
609+
name: "dest".into(),
610+
ty: *oomir_function.signature.ret.clone(),
611+
})
612+
} else {
613+
None
614+
},
606615
},
607-
},
608-
]);
616+
]);
617+
} else {
618+
// Associated function (no self receiver): no wrapper needed.
619+
// Insert the lowered function directly as a top-level function named Type_method.
620+
// Keep a clone for class metadata below with the original method name.
621+
let method_impl_for_class = oomir_function.clone();
622+
623+
let mut top_level_func = oomir_function.clone();
624+
top_level_func.name = i2.clone();
625+
oomir_module
626+
.functions
627+
.insert(i2.clone(), top_level_func);
628+
629+
// For associated functions, skip creating a wrapper basic block.
630+
// We'll still register the method on the class using `method_impl_for_class` below.
631+
632+
// Replace oomir_function with the clone intended for class metadata for the remaining code.
633+
oomir_function = method_impl_for_class;
634+
}
609635

610-
// insert a wrapper function for the trait method - calling InvokeVirtual on the class to call the actual method
611-
bbs.insert(
612-
"bb0".into(),
613-
oomir::BasicBlock {
614-
instructions,
615-
label: "bb0".to_string(),
616-
},
617-
);
618-
oomir_module.functions.insert(
619-
i2.clone(),
620-
Function {
621-
name: i2,
622-
signature: helper_sig,
623-
body: CodeBlock {
624-
entry: "bb0".into(),
625-
basic_blocks: bbs,
636+
// For instance methods, insert the wrapper; associated methods skipped above
637+
if is_instance_method {
638+
// insert a wrapper function for the method - calling InvokeVirtual on the class to call the actual method
639+
bbs.insert(
640+
"bb0".into(),
641+
oomir::BasicBlock {
642+
instructions,
643+
label: "bb0".to_string(),
626644
},
627-
},
628-
);
645+
);
646+
oomir_module.functions.insert(
647+
i2.clone(),
648+
Function {
649+
name: i2,
650+
signature: helper_sig,
651+
body: CodeBlock {
652+
entry: "bb0".into(),
653+
basic_blocks: bbs,
654+
},
655+
},
656+
);
657+
}
629658

630659
oomir_module.merge_data_types(&oomir_result.1);
631660

src/lower1/control_flow.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,28 @@ pub fn convert_basic_block<'tcx>(
328328
(super::naming::mono_fn_name_from_call_operand(func, tcx).unwrap(), false)
329329
}
330330
} else {
331-
// Not a trait method, use monomorphized name
332-
(super::naming::mono_fn_name_from_call_operand(func, tcx).unwrap(), false)
331+
// Inherent impl method (not a trait method): use Type_method naming to disambiguate
332+
// Determine the impl's self type via the parent DefId of the method
333+
let parent_def_id = tcx.parent(*def_id);
334+
let self_ty = tcx.type_of(parent_def_id).skip_binder();
335+
let class_ty = super::types::ty_to_oomir_type(self_ty, tcx, &mut Default::default());
336+
let class_name = match class_ty {
337+
oomir::Type::Class(name) => name,
338+
oomir::Type::Reference(box oomir::Type::Class(name)) => name,
339+
oomir::Type::MutableReference(box oomir::Type::Class(name)) => name,
340+
other => format!("{:?}", other),
341+
};
342+
let method_name = tcx.item_name(*def_id).to_string();
343+
let full_name = format!("{}_{}", class_name, method_name);
344+
breadcrumbs::log!(
345+
breadcrumbs::LogLevel::Info,
346+
"mir-lowering",
347+
format!(
348+
"Inherent impl method call resolved to name: {} (parent={:?})",
349+
full_name, parent_def_id
350+
)
351+
);
352+
(full_name, false)
333353
}
334354
} else {
335355
// Not an associated item, use monomorphized name

0 commit comments

Comments
 (0)