Skip to content

Commit 5f32d2d

Browse files
authored
Merge pull request #612 from shiika-lang/method-tvar-ref
impl. method tvars
2 parents 6e1eca0 + d385ddb commit 5f32d2d

3 files changed

Lines changed: 91 additions & 18 deletions

File tree

lib/skc_async_experiment/src/mirgen.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,13 @@ impl<'a> Compiler<'a> {
146146
name: "self".to_string(),
147147
},
148148
);
149+
// Method type parameters are passed as additional Class arguments
150+
for typaram in &signature.typarams {
151+
params.push(mir::Param {
152+
ty: mir::Ty::raw("Class"),
153+
name: typaram.name.clone(),
154+
});
155+
}
149156
// Pass 1: collect cell vars before converting body
150157
self.lambda.cell_vars = if let SkMethodBody::Normal { exprs } = &method.body {
151158
lambda::collect_cell_vars(exprs)
@@ -321,9 +328,12 @@ impl<'a> Compiler<'a> {
321328
}
322329
HirExpressionBase::HirMethodTVarRef {
323330
typaram_ref,
324-
n_params: _,
331+
n_params,
325332
} => {
326-
todo!("Handle method tvar ref: {:?}", typaram_ref)
333+
// Method type parameters are passed as additional Class
334+
// arguments after self and explicit params.
335+
let idx = 1 + n_params + typaram_ref.idx;
336+
mir::Expr::arg_ref(idx, typaram_ref.name.clone(), mir::Ty::raw("Class"))
327337
}
328338
HirExpressionBase::HirLVarDecl {
329339
name,
@@ -374,6 +384,7 @@ impl<'a> Compiler<'a> {
374384
receiver_expr,
375385
method_fullname,
376386
arg_exprs,
387+
tyarg_exprs,
377388
is_virtual,
378389
..
379390
} => {
@@ -387,6 +398,9 @@ impl<'a> Compiler<'a> {
387398
.map(|e| e.ty.clone().into())
388399
.collect::<Vec<_>>();
389400
param_tys.insert(0, convert_ty(method_fullname.type_name.to_ty()));
401+
for _ in &tyarg_exprs {
402+
param_tys.push(mir::Ty::raw("Class"));
403+
}
390404
mir::FunTy::new(mir::Asyncness::Unknown, param_tys, expr.ty.clone().into())
391405
};
392406

@@ -423,6 +437,12 @@ impl<'a> Compiler<'a> {
423437
mir_receiver
424438
};
425439
mir_args.insert(0, receiver_for_call);
440+
for tyarg in tyarg_exprs {
441+
let mir_tyarg = self.convert_expr(tyarg);
442+
let casted =
443+
mir::Expr::cast(mir::CastType::Force(mir::Ty::raw("Class")), mir_tyarg);
444+
mir_args.push(casted);
445+
}
426446

427447
(mir::Expr::FunCall(Box::new(func_ref), mir_args), result_ty)
428448
}
@@ -432,6 +452,7 @@ impl<'a> Compiler<'a> {
432452
method_name,
433453
method_idx,
434454
arg_exprs,
455+
tyarg_exprs,
435456
..
436457
} => {
437458
let receiver_ty = receiver_expr.ty.clone();
@@ -444,6 +465,9 @@ impl<'a> Compiler<'a> {
444465
.map(|e| e.ty.clone().into())
445466
.collect::<Vec<_>>();
446467
param_tys.insert(0, convert_ty(receiver_ty));
468+
for _ in &tyarg_exprs {
469+
param_tys.push(mir::Ty::raw("Class"));
470+
}
447471
mir::FunTy::new(mir::Asyncness::Unknown, param_tys, expr.ty.clone().into())
448472
};
449473

@@ -461,6 +485,12 @@ impl<'a> Compiler<'a> {
461485
.map(|arg| self.convert_expr(arg))
462486
.collect();
463487
mir_args.insert(0, mir_receiver);
488+
for tyarg in tyarg_exprs {
489+
let mir_tyarg = self.convert_expr(tyarg);
490+
let casted =
491+
mir::Expr::cast(mir::CastType::Force(mir::Ty::raw("Class")), mir_tyarg);
492+
mir_args.push(casted);
493+
}
464494

465495
let result_ty = convert_ty(expr.ty.clone());
466496
(mir::Expr::FunCall(Box::new(func_ref), mir_args), result_ty)
@@ -833,6 +863,10 @@ fn build_fun_ty(sig: &MethodSignature) -> mir::FunTy {
833863
.map(|x| convert_ty(x.ty.clone()))
834864
.collect::<Vec<_>>();
835865
param_tys.insert(0, convert_ty(sig.fullname.type_name.to_ty()));
866+
// Method type parameters are passed as additional Class arguments.
867+
for _ in &sig.typarams {
868+
param_tys.push(mir::Ty::raw("Class"));
869+
}
836870
mir::FunTy::new(
837871
sig.asyncness.clone().into(),
838872
param_tys,

lib/skc_async_experiment/src/mirgen/lambda.rs

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::mir;
22
use crate::names::FunctionName;
33
use shiika_core::names::MethodFullname;
4-
use shiika_core::ty::TermTy;
4+
use shiika_core::ty::{TermTy, TyBody};
55
use skc_hir::visitor::{walk_expr, HirVisitor};
66
use skc_hir::{HirExpression, HirExpressionBase, HirLVars, MethodParam};
77
use skc_hir::{HirLambdaCapture, HirLambdaCaptureDetail};
@@ -102,22 +102,32 @@ pub fn build_fn_object(
102102
lambda_param_tys.extend(params.iter().map(|p| p.ty.clone().into()));
103103
let lambda_fun_ty = mir::FunTy::new(mir::Asyncness::Async, lambda_param_tys, ret_ty.into());
104104

105-
// Call Meta:FnN#new(Meta:FnN, Ptr, Ptr, Int) -> FnN
105+
// Call Meta:FnN#new(Meta:FnN, Ptr, Ptr, Int, [Class...]) -> FnN
106+
//
107+
// Per `signature_of_new`, `Meta:FnN#new` carries the class typarams of FnN
108+
// (e.g. `A1, R` for `Fn1<A1, R>`) as method typarams, and the mirgen pass
109+
// for method calls passes them as additional `Class` arguments after the
110+
// explicit ones. We must do the same here.
106111
let meta_fn_ty = fn_ty.meta_ty();
107112
let meta_erasure = meta_fn_ty.erasure();
113+
let tyarg_class_objs: Vec<mir::TypedExpr> = fn_ty
114+
.type_args()
115+
.iter()
116+
.map(build_class_obj_for_tyarg)
117+
.collect();
108118
let new_func_ref = {
109119
let new_func_name: FunctionName =
110120
MethodFullname::new(meta_erasure.to_type_fullname(), "new").into();
111-
let new_fun_ty = mir::FunTy::new(
112-
mir::Asyncness::Unknown,
113-
vec![
114-
meta_fn_ty.clone().into(),
115-
mir::Ty::Ptr,
116-
mir::Ty::Ptr,
117-
mir::Ty::raw("Int"),
118-
],
119-
fn_ty.clone().into(),
120-
);
121+
let mut param_tys = vec![
122+
meta_fn_ty.clone().into(),
123+
mir::Ty::Ptr,
124+
mir::Ty::Ptr,
125+
mir::Ty::raw("Int"),
126+
];
127+
for _ in &tyarg_class_objs {
128+
param_tys.push(mir::Ty::raw("Class"));
129+
}
130+
let new_fun_ty = mir::FunTy::new(mir::Asyncness::Unknown, param_tys, fn_ty.clone().into());
121131
mir::Expr::func_ref(new_func_name, new_fun_ty)
122132
};
123133
// Use base_type_name() for const ref too (e.g., "Fn1" instead of "Fn1<Int,Int>")
@@ -128,10 +138,28 @@ pub fn build_fn_object(
128138
let func_ptr_as_ptr = mir::Expr::cast(mir::CastType::Force(mir::Ty::Ptr), func_ptr);
129139

130140
let zero = mir::Expr::number(0);
131-
mir::Expr::fun_call(
132-
new_func_ref,
133-
vec![meta_fn_obj, func_ptr_as_ptr, captures_ptr, zero],
134-
)
141+
let mut args = vec![meta_fn_obj, func_ptr_as_ptr, captures_ptr, zero];
142+
args.extend(tyarg_class_objs);
143+
mir::Expr::fun_call(new_func_ref, args)
144+
}
145+
146+
/// Build the MIR expression for the `Class` object representing `t`,
147+
/// used as a method typaram argument for `Meta:FnN#new`.
148+
fn build_class_obj_for_tyarg(t: &TermTy) -> mir::TypedExpr {
149+
match &t.body {
150+
TyBody::TyRaw(_) => {
151+
if t.has_type_args() {
152+
todo!("lambda type arg with generic type: {:?}", t)
153+
}
154+
let meta_ty = t.meta_ty();
155+
let const_name = meta_ty.erasure().to_const_fullname();
156+
let cref = mir::Expr::const_ref(const_name, meta_ty.into());
157+
mir::Expr::cast(mir::CastType::Force(mir::Ty::raw("Class")), cref)
158+
}
159+
TyBody::TyPara(_) => {
160+
todo!("lambda type arg with typaram: {:?}", t)
161+
}
162+
}
135163
}
136164

137165
/// Build the expression that reads a captured variable inside a lambda body.

tests/new_runtime/method_tvar.sk

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class Main
2+
def self.foo<T>(x: T) -> Array<T>
3+
let a = Array<T>.new()
4+
a.push(x)
5+
a
6+
end
7+
end
8+
let ary = Main.foo(1)
9+
puts "ng" unless ary[0] == 1
10+
11+
puts "ok"

0 commit comments

Comments
 (0)