Skip to content

Commit 3786bef

Browse files
committed
Added ability to use trait implementation polymorphs as implementation arguments for function calls
1 parent 212118b commit 3786bef

File tree

5 files changed

+340
-196
lines changed

5 files changed

+340
-196
lines changed

Diff for: src/lower/expr/call.rs

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
use super::lower_expr;
2+
use crate::{
3+
asg::{self, Asg, Call, Expr, PolyCall, TypedExpr},
4+
ir,
5+
lower::{builder::Builder, datatype::lower_type, error::LowerError, function::lower_func_head},
6+
resolve::{PolyRecipe, PolyValue},
7+
source_files::Source,
8+
};
9+
use indexmap::IndexMap;
10+
use std::borrow::Borrow;
11+
12+
pub fn lower_expr_call(
13+
builder: &mut Builder,
14+
ir_module: &ir::Module,
15+
expr: &Expr,
16+
function: &asg::Func,
17+
asg: &Asg,
18+
call: &Call,
19+
) -> Result<ir::Value, LowerError> {
20+
lower_expr_call_core(
21+
builder,
22+
ir_module,
23+
expr,
24+
function,
25+
asg,
26+
call.callee.function,
27+
&call.callee.recipe,
28+
call.args.as_slice(),
29+
)
30+
}
31+
32+
pub fn lower_expr_poly_call(
33+
builder: &mut Builder,
34+
ir_module: &ir::Module,
35+
expr: &Expr,
36+
callee_func: &asg::Func,
37+
asg: &Asg,
38+
poly_call: &PolyCall,
39+
) -> Result<ir::Value, LowerError> {
40+
let impl_ref = builder
41+
.poly_recipe()
42+
.resolve_impl(&poly_call.callee.polymorph, expr.source)
43+
.map_err(LowerError::from)?;
44+
45+
let imp = asg.impls.get(impl_ref).expect("referenced impl to exist");
46+
47+
let func_ref = imp
48+
.body
49+
.get(&poly_call.callee.member)
50+
.expect("expected impl body function referenced by poly call to exist");
51+
52+
lower_expr_call_core(
53+
builder,
54+
ir_module,
55+
expr,
56+
callee_func,
57+
asg,
58+
*func_ref,
59+
&poly_call.callee.recipe,
60+
poly_call.args.as_slice(),
61+
)
62+
}
63+
64+
fn lower_expr_call_core(
65+
builder: &mut Builder,
66+
ir_module: &ir::Module,
67+
expr: &Expr,
68+
function: &asg::Func,
69+
asg: &Asg,
70+
func_ref: asg::FuncRef,
71+
callee_recipe: &PolyRecipe,
72+
all_args: &[TypedExpr],
73+
) -> Result<ir::Value, LowerError> {
74+
let callee = asg
75+
.funcs
76+
.get(func_ref)
77+
.expect("referenced function to exist");
78+
79+
let args = all_args
80+
.iter()
81+
.map(|arg| lower_expr(builder, ir_module, &arg.expr, function, asg))
82+
.collect::<Result<Box<[_]>, _>>()?;
83+
84+
let variadic_arg_types = all_args[callee.params.required.len()..]
85+
.iter()
86+
.map(|arg| lower_type(ir_module, &builder.unpoly(&arg.ty)?, asg))
87+
.collect::<Result<Box<[_]>, _>>()?;
88+
89+
let recipe = lower_call_poly_recipe(builder, &callee_recipe, expr.source)?;
90+
91+
let function = ir_module.funcs.translate(func_ref, &recipe, || {
92+
lower_func_head(ir_module, func_ref, &recipe, asg)
93+
})?;
94+
95+
Ok(builder.push(ir::Instr::Call(ir::Call {
96+
func: function,
97+
args,
98+
unpromoted_variadic_arg_types: variadic_arg_types,
99+
})))
100+
}
101+
102+
fn lower_call_poly_recipe(
103+
builder: &Builder,
104+
callee_recipe: &PolyRecipe,
105+
source: Source,
106+
) -> Result<PolyRecipe, LowerError> {
107+
let mut polymorphs = IndexMap::<String, PolyValue>::new();
108+
109+
for (name, value) in callee_recipe.polymorphs.iter() {
110+
match value {
111+
PolyValue::Type(ty) => {
112+
polymorphs.insert(
113+
name.clone(),
114+
PolyValue::Type(Borrow::<asg::Type>::borrow(&builder.unpoly(&ty)?.0).clone()),
115+
);
116+
}
117+
PolyValue::Expr(_) => {
118+
todo!("compile-time expression parameters are not supported when calling generic functions yet")
119+
}
120+
PolyValue::Impl(impl_ref) => {
121+
polymorphs.insert(name.clone(), PolyValue::Impl(*impl_ref));
122+
}
123+
PolyValue::PolyImpl(from_name) => {
124+
let Some(poly_value) = builder.poly_recipe().polymorphs.get(from_name) else {
125+
return Err(LowerError::other(
126+
format!("Undefined polymorph '{}' cannot be used as polymorphic trait implementation", name),
127+
source,
128+
));
129+
};
130+
131+
let PolyValue::Impl(impl_ref) = poly_value else {
132+
return Err(LowerError::other(
133+
format!("Polymorph '{}' must be a trait implementation", name),
134+
source,
135+
));
136+
};
137+
138+
polymorphs.insert(name.clone(), PolyValue::Impl(*impl_ref));
139+
}
140+
}
141+
}
142+
143+
Ok(PolyRecipe { polymorphs })
144+
}

Diff for: src/lower/expr/mod.rs

+5-118
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
mod call;
12
mod short_circuit;
23

34
use super::{
45
builder::Builder,
56
cast::{integer_cast, integer_extend, integer_truncate},
67
datatype::lower_type,
78
error::{LowerError, LowerErrorKind},
8-
function::lower_func_head,
99
stmts::lower_stmts,
1010
};
1111
use crate::{
@@ -16,11 +16,10 @@ use crate::{
1616
ast::{FloatSize, IntegerBits, IntegerRigidity},
1717
ir::{self, IntegerSign, Literal, OverflowOperator, Value, ValueReference},
1818
lower::structure::mono,
19-
resolve::{PolyCatalog, PolyRecipe, PolyValue},
19+
resolve::PolyCatalog,
2020
};
21-
use indexmap::IndexMap;
21+
use call::{lower_expr_call, lower_expr_poly_call};
2222
use short_circuit::lower_short_circuiting_binary_operation;
23-
use std::borrow::Borrow;
2423

2524
pub fn lower_expr(
2625
builder: &mut Builder,
@@ -134,59 +133,7 @@ pub fn lower_expr(
134133
"String literals are not fully implemented yet, still need ability to lower"
135134
)
136135
}
137-
ExprKind::Call(call) => {
138-
let callee = asg
139-
.funcs
140-
.get(call.callee.function)
141-
.expect("referenced function to exist");
142-
143-
let args = call
144-
.args
145-
.iter()
146-
.map(|arg| lower_expr(builder, ir_module, &arg.expr, function, asg))
147-
.collect::<Result<Box<[_]>, _>>()?;
148-
149-
let variadic_arg_types = call.args[callee.params.required.len()..]
150-
.iter()
151-
.map(|arg| lower_type(ir_module, &builder.unpoly(&arg.ty)?, asg))
152-
.collect::<Result<Box<[_]>, _>>()?;
153-
154-
// NOTE: We have to resolve our own polymorphs in the mapping
155-
let mut polymorphs = IndexMap::<String, PolyValue>::new();
156-
157-
for (name, value) in call.callee.recipe.polymorphs.iter() {
158-
match value {
159-
PolyValue::Type(ty) => {
160-
polymorphs.insert(
161-
name.clone(),
162-
PolyValue::Type(
163-
Borrow::<asg::Type>::borrow(&builder.unpoly(ty)?.0).clone(),
164-
),
165-
);
166-
}
167-
PolyValue::Expr(_) => {
168-
todo!("compile-time expression parameters are not supported when calling generic functions yet")
169-
}
170-
PolyValue::Impl(impl_ref) => {
171-
polymorphs.insert(name.clone(), PolyValue::Impl(*impl_ref));
172-
}
173-
}
174-
}
175-
176-
let recipe = PolyRecipe { polymorphs };
177-
178-
let function = ir_module
179-
.funcs
180-
.translate(call.callee.function, &recipe, || {
181-
lower_func_head(ir_module, call.callee.function, &recipe, asg)
182-
})?;
183-
184-
Ok(builder.push(ir::Instr::Call(ir::Call {
185-
func: function,
186-
args,
187-
unpromoted_variadic_arg_types: variadic_arg_types,
188-
})))
189-
}
136+
ExprKind::Call(call) => lower_expr_call(builder, ir_module, expr, function, asg, call),
190137
ExprKind::Variable(variable) => {
191138
let pointer_to_variable = lower_variable_to_value(variable.key);
192139
let variable_type = lower_type(ir_module, &builder.unpoly(&variable.ty)?, asg)?;
@@ -544,67 +491,7 @@ pub fn lower_expr(
544491
Ok(builder.push(ir::Instr::InterpreterSyscall(*syscall, values)))
545492
}
546493
ExprKind::PolyCall(poly_call) => {
547-
let impl_ref = builder
548-
.poly_recipe()
549-
.resolve_impl(&poly_call.callee.polymorph, expr.source)
550-
.map_err(LowerError::from)?;
551-
552-
let imp = asg.impls.get(impl_ref).expect("referenced impl to exist");
553-
554-
let func_ref = imp
555-
.body
556-
.get(&poly_call.callee.member)
557-
.expect("expected impl body function referenced by poly call to exist");
558-
559-
let callee = asg
560-
.funcs
561-
.get(*func_ref)
562-
.expect("referenced function to exist");
563-
564-
let args = poly_call
565-
.args
566-
.iter()
567-
.map(|arg| lower_expr(builder, ir_module, &arg.expr, function, asg))
568-
.collect::<Result<Box<[_]>, _>>()?;
569-
570-
let variadic_arg_types = poly_call.args[callee.params.required.len()..]
571-
.iter()
572-
.map(|arg| lower_type(ir_module, &builder.unpoly(&arg.ty)?, asg))
573-
.collect::<Result<Box<[_]>, _>>()?;
574-
575-
// NOTE: We have to resolve our own polymorphs in the mapping
576-
let mut polymorphs = IndexMap::<String, PolyValue>::new();
577-
578-
for (name, value) in poly_call.callee.recipe.polymorphs.iter() {
579-
match value {
580-
PolyValue::Type(ty) => {
581-
polymorphs.insert(
582-
name.clone(),
583-
PolyValue::Type(
584-
Borrow::<asg::Type>::borrow(&builder.unpoly(&ty)?.0).clone(),
585-
),
586-
);
587-
}
588-
PolyValue::Expr(_) => {
589-
todo!("compile-time expression parameters are not supported when calling generic functions yet")
590-
}
591-
PolyValue::Impl(impl_ref) => {
592-
polymorphs.insert(name.clone(), PolyValue::Impl(*impl_ref));
593-
}
594-
}
595-
}
596-
597-
let recipe = PolyRecipe { polymorphs };
598-
599-
let function = ir_module.funcs.translate(*func_ref, &recipe, || {
600-
lower_func_head(ir_module, *func_ref, &recipe, asg)
601-
})?;
602-
603-
Ok(builder.push(ir::Instr::Call(ir::Call {
604-
func: function,
605-
args,
606-
unpromoted_variadic_arg_types: variadic_arg_types,
607-
})))
494+
lower_expr_poly_call(builder, ir_module, expr, function, asg, poly_call)
608495
}
609496
}
610497
}

Diff for: src/parser/parse_expr/primary/call.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,10 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
8282
self.ignore_newlines();
8383
}
8484

85-
let name = if self.input.peek().is_identifier()
86-
&& self.input.peek_nth(1).could_start_type()
87-
{
88-
Some(self.parse_identifier(Some("for implementation parameter name"))?)
89-
} else {
90-
None
91-
};
85+
let name = (self.input.peek().is_identifier()
86+
&& self.input.peek_nth(1).could_start_type())
87+
.then(|| self.parse_identifier(Some("for implementation parameter name")))
88+
.transpose()?;
9289

9390
using.push(Using {
9491
name,

0 commit comments

Comments
 (0)