Skip to content

Commit a5affaa

Browse files
committed
Inital support for generics, including testcase!
1 parent 08d4d3b commit a5affaa

File tree

15 files changed

+456
-66
lines changed

15 files changed

+456
-66
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
**/.gradle/*
66
**/build/*
77
**/.kotlin/*
8+
library/bin/**
89

910
# Files generated by Tester.py
1011
**/*.generated

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ public object Core {
129129
return value?.toString() ?: "null"
130130
}
131131

132+
@JvmStatic
133+
public fun len(str: String): Int {
134+
// Return the length of the string in characters (code points, not bytes)
135+
return str.length
136+
}
137+
132138
@JvmStatic
133139
public fun eq(value1: Any?, value2: Any?): Boolean {
134140
// 1. Identity and Null checks

shim-metadata-gen/core.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@
111111
"descriptor": "(Ljava/lang/Object;Ljava/lang/Object;)Z",
112112
"is_static": true
113113
},
114+
"len": {
115+
"descriptor": "(Ljava/lang/String;)I",
116+
"is_static": true
117+
},
114118
"panic_fmt": {
115119
"descriptor": "(Ljava/lang/Object;)V",
116120
"is_static": true

src/lib.rs

Lines changed: 128 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ impl CodegenBackend for MyBackend {
142142
let mut closures_to_lower: std::collections::HashSet<rustc_hir::def_id::DefId> =
143143
std::collections::HashSet::new();
144144

145+
// Track monomorphized function instances to lower and avoid duplicates by name
146+
let mut fn_instances_to_lower: Vec<(rustc_middle::ty::Instance<'_>, String)> = Vec::new();
147+
let mut seen_fn_names: std::collections::HashSet<String> = std::collections::HashSet::new();
148+
use rustc_middle::ty::TypingEnv;
149+
145150
// Iterate through all items in the crate and find functions
146151
let module_items = tcx.hir_crate_items(());
147152

@@ -156,6 +161,21 @@ impl CodegenBackend for MyBackend {
156161
} = item.kind
157162
{
158163
let def_id = item_id.owner_id.to_def_id();
164+
165+
// Skip directly lowering generic functions; collect concrete instantiations instead
166+
let generics = tcx.generics_of(def_id);
167+
if !generics.own_params.is_empty() {
168+
breadcrumbs::log!(
169+
breadcrumbs::LogLevel::Info,
170+
"backend",
171+
format!(
172+
"Skipping direct lowering of generic function {} (DefId: {:?}); will lower its monomorphized instances",
173+
i, def_id
174+
)
175+
);
176+
continue;
177+
}
178+
159179
let instance = rustc_middle::ty::Instance::mono(tcx, def_id);
160180
let mut mir = tcx.optimized_mir(instance.def_id()).clone(); // Clone the MIR
161181

@@ -170,17 +190,13 @@ impl CodegenBackend for MyBackend {
170190
for mentioned in mentioned_items.iter() {
171191
// Check if this mentioned item is a closure
172192
if let rustc_middle::mir::MentionedItem::Fn(fn_ty) = &mentioned.node {
173-
if let rustc_middle::ty::TyKind::FnDef(_fn_def_id, fn_args) =
174-
fn_ty.kind()
193+
if let rustc_middle::ty::TyKind::FnDef(fn_def_id, fn_args) = fn_ty.kind()
175194
{
176195
// Check the first argument to see if it's a closure type
196+
let mut is_closure = false;
177197
if let Some(first_arg) = fn_args.get(0) {
178198
if let Some(ty) = first_arg.as_type() {
179-
if let rustc_middle::ty::TyKind::Closure(
180-
closure_def_id,
181-
_,
182-
) = ty.kind()
183-
{
199+
if let rustc_middle::ty::TyKind::Closure(closure_def_id, _,) = ty.kind() {
184200
breadcrumbs::log!(
185201
breadcrumbs::LogLevel::Info,
186202
"closure-discovery",
@@ -190,6 +206,45 @@ impl CodegenBackend for MyBackend {
190206
)
191207
);
192208
closures_to_lower.insert(*closure_def_id);
209+
is_closure = true;
210+
}
211+
}
212+
}
213+
if !is_closure {
214+
// Non-closure function reference; enqueue monomorphized instance
215+
let typing_env = TypingEnv::fully_monomorphized();
216+
// Only lower functions defined in this crate
217+
if fn_def_id.is_local() {
218+
let instance = rustc_middle::ty::Instance::expect_resolve(
219+
tcx,
220+
typing_env,
221+
*fn_def_id,
222+
*fn_args,
223+
rustc_span::DUMMY_SP,
224+
);
225+
// Skip virtual trait method calls (handled via trait objects at runtime)
226+
if let rustc_middle::ty::InstanceKind::Virtual(_, _) = instance.def {
227+
breadcrumbs::log!(
228+
breadcrumbs::LogLevel::Info,
229+
"backend",
230+
format!("Skipping virtual instance: {:?}", instance)
231+
);
232+
continue;
233+
}
234+
// Skip trait method implementations (already lowered by impl block code with Type_method naming)
235+
if let Some(assoc_item) = tcx.opt_associated_item(*fn_def_id) {
236+
if assoc_item.trait_item_def_id().is_some() {
237+
breadcrumbs::log!(
238+
breadcrumbs::LogLevel::Info,
239+
"backend",
240+
format!("Skipping trait impl method: {:?}", fn_def_id)
241+
);
242+
continue;
243+
}
244+
}
245+
let name = lower1::naming::mono_fn_name_from_instance(tcx, instance);
246+
if seen_fn_names.insert(name.clone()) {
247+
fn_instances_to_lower.push((instance, name));
193248
}
194249
}
195250
}
@@ -262,6 +317,20 @@ impl CodegenBackend for MyBackend {
262317
let i = item.to_ident(tcx).to_string();
263318
let def_id = item.owner_id.to_def_id();
264319

320+
// Skip direct lowering of generic methods; rely on monomorphized uses
321+
let generics = tcx.generics_of(def_id);
322+
if !generics.own_params.is_empty() {
323+
breadcrumbs::log!(
324+
breadcrumbs::LogLevel::Info,
325+
"backend",
326+
format!(
327+
"Skipping direct lowering of generic impl method {} (DefId: {:?})",
328+
i, def_id
329+
)
330+
);
331+
continue;
332+
}
333+
265334
let instance = rustc_middle::ty::Instance::mono(tcx, def_id);
266335
let mut mir = tcx.optimized_mir(instance.def_id()).clone(); // Clone the MIR
267336

@@ -277,9 +346,8 @@ impl CodegenBackend for MyBackend {
277346
if let Some(mentioned_items) = &mir.mentioned_items {
278347
for mentioned in mentioned_items.iter() {
279348
if let rustc_middle::mir::MentionedItem::Fn(fn_ty) = &mentioned.node {
280-
if let rustc_middle::ty::TyKind::FnDef(_fn_def_id, fn_args) =
281-
fn_ty.kind()
282-
{
349+
if let rustc_middle::ty::TyKind::FnDef(fn_def_id, fn_args) = fn_ty.kind() {
350+
let mut is_closure = false;
283351
if let Some(first_arg) = fn_args.get(0) {
284352
if let Some(ty) = first_arg.as_type() {
285353
if let rustc_middle::ty::TyKind::Closure(
@@ -296,6 +364,43 @@ impl CodegenBackend for MyBackend {
296364
)
297365
);
298366
closures_to_lower.insert(*closure_def_id);
367+
is_closure = true;
368+
}
369+
}
370+
}
371+
if !is_closure {
372+
let typing_env = TypingEnv::fully_monomorphized();
373+
if fn_def_id.is_local() {
374+
let instance = rustc_middle::ty::Instance::expect_resolve(
375+
tcx,
376+
typing_env,
377+
*fn_def_id,
378+
*fn_args,
379+
rustc_span::DUMMY_SP,
380+
);
381+
// Skip virtual trait method calls (handled via trait objects at runtime)
382+
if let rustc_middle::ty::InstanceKind::Virtual(_, _) = instance.def {
383+
breadcrumbs::log!(
384+
breadcrumbs::LogLevel::Info,
385+
"backend",
386+
format!("Skipping virtual instance: {:?}", instance)
387+
);
388+
continue;
389+
}
390+
// Skip trait method implementations (already lowered by impl block code with Type_method naming)
391+
if let Some(assoc_item) = tcx.opt_associated_item(*fn_def_id) {
392+
if assoc_item.trait_item_def_id().is_some() {
393+
breadcrumbs::log!(
394+
breadcrumbs::LogLevel::Info,
395+
"backend",
396+
format!("Skipping trait impl method: {:?}", fn_def_id)
397+
);
398+
continue;
399+
}
400+
}
401+
let name = lower1::naming::mono_fn_name_from_instance(tcx, instance);
402+
if seen_fn_names.insert(name.clone()) {
403+
fn_instances_to_lower.push((instance, name));
299404
}
300405
}
301406
}
@@ -703,6 +808,19 @@ impl CodegenBackend for MyBackend {
703808
}
704809
}
705810

811+
// Lower all discovered monomorphized function instances
812+
for (instance, name) in fn_instances_to_lower {
813+
let mut mir = tcx.instance_mir(instance.def).clone();
814+
breadcrumbs::log!(
815+
breadcrumbs::LogLevel::Info,
816+
"mir-lowering",
817+
format!("--- Lowering monomorphized function instance: {} ---", name)
818+
);
819+
let (oomir_function, data_types) = lower1::mir_to_oomir(tcx, instance, &mut mir, Some(name.clone()));
820+
oomir_module.functions.insert(name, oomir_function);
821+
oomir_module.merge_data_types(&data_types);
822+
}
823+
706824
// Now lower all discovered closures
707825
breadcrumbs::log!(
708826
breadcrumbs::LogLevel::Info,

src/lower1.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ mod control_flow;
2121
pub mod operand;
2222
pub mod place;
2323
pub mod types;
24+
pub mod naming;
2425

2526
pub use closures::{ClosureCallInfo, extract_closure_info, generate_closure_function_name};
2627

@@ -40,19 +41,29 @@ pub fn mir_to_oomir<'tcx>(
4041
use rustc_middle::ty::TyKind;
4142

4243
// Get a function name from the instance or use the provided override.
43-
// Closures don't have proper item names, so we must use an override for them.
44-
let fn_name = fn_name_override.unwrap_or_else(|| tcx.item_name(instance.def_id()).to_string());
44+
// Prefer monomorphized naming to disambiguate generic instantiations.
45+
let fn_name = fn_name_override
46+
.unwrap_or_else(|| naming::mono_fn_name_from_instance(tcx, instance));
4547

4648
// Extract function signature
4749
// Closures require special handling - we must use as_closure().sig() instead of fn_sig()
48-
let instance_ty = tcx.type_of(instance.def_id()).skip_binder();
50+
// Instantiate the function's item type with this instance's generic args, so
51+
// generic functions get concrete param/return types.
52+
let instance_ty = tcx
53+
.type_of(instance.def_id())
54+
.instantiate(tcx, instance.args);
4955
let (params_ty, return_ty) = match instance_ty.kind() {
5056
TyKind::Closure(_def_id, args) => {
5157
let sig = args.as_closure().sig();
5258
(sig.inputs(), sig.output())
5359
}
60+
TyKind::FnDef(def_id, _args) => {
61+
// For FnDef, compute the signature from the instantiated item type
62+
let mir_sig = instance_ty.fn_sig(tcx);
63+
(mir_sig.inputs(), mir_sig.output())
64+
}
5465
_ => {
55-
// Regular function - use fn_sig()
66+
// Regular function pointer or other callable types
5667
let mir_sig = instance_ty.fn_sig(tcx);
5768
(mir_sig.inputs(), mir_sig.output())
5869
}
@@ -102,6 +113,7 @@ pub fn mir_to_oomir<'tcx>(
102113
bb,
103114
bb_data,
104115
tcx,
116+
instance,
105117
&mir_cloned,
106118
&return_oomir_ty,
107119
&mut basic_blocks,

0 commit comments

Comments
 (0)