Skip to content

Commit 818d600

Browse files
committed
Continued working on ability to call functions with implementation polymorphs and being able to use polymorphic implementation parameters within functions
1 parent ebe698d commit 818d600

File tree

5 files changed

+204
-46
lines changed

5 files changed

+204
-46
lines changed

Diff for: src/asg/generic_trait_ref.rs

+46-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,51 @@
1-
use super::{TraitRef, Type};
1+
use super::{Asg, TraitRef, Type};
2+
use std::fmt::Display;
23

3-
#[derive(Clone, Debug)]
4+
#[derive(Clone, Debug, PartialEq)]
45
pub struct GenericTraitRef {
56
pub trait_ref: TraitRef,
67
pub args: Vec<Type>,
78
}
9+
10+
impl GenericTraitRef {
11+
pub fn display<'a>(&'a self, asg: &'a Asg) -> DisplayGenericTraitRef<'a> {
12+
DisplayGenericTraitRef {
13+
generic_trait: self,
14+
asg,
15+
}
16+
}
17+
}
18+
19+
pub struct DisplayGenericTraitRef<'a> {
20+
generic_trait: &'a GenericTraitRef,
21+
asg: &'a Asg<'a>,
22+
}
23+
24+
impl<'a> Display for DisplayGenericTraitRef<'a> {
25+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26+
let trait_decl = self
27+
.asg
28+
.traits
29+
.get(self.generic_trait.trait_ref)
30+
.expect("referenced trait to exist");
31+
32+
write!(f, "{}", trait_decl.human_name.0)?;
33+
34+
if self.generic_trait.args.is_empty() {
35+
return Ok(());
36+
}
37+
38+
write!(f, "<")?;
39+
40+
for (i, ty) in self.generic_trait.args.iter().enumerate() {
41+
if i != 0 {
42+
write!(f, ", ")?;
43+
}
44+
45+
write!(f, "{}", ty)?;
46+
}
47+
48+
write!(f, ">")?;
49+
Ok(())
50+
}
51+
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ pub fn lower_expr(
167167
PolyValue::Expr(_) => {
168168
todo!("compile-time expression parameters are not supported when calling generic functions yet")
169169
}
170-
PolyValue::Impl(_) => {
171-
eprintln!("warning: implementation polymorphs are not propogated yet when calling from functions that have them");
170+
PolyValue::Impl(impl_ref) => {
171+
polymorphs.insert(name.clone(), PolyValue::Impl(*impl_ref));
172172
}
173173
}
174174
}

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

+60-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use crate::{
66
resolve::{
77
conform::{conform_expr, to_default::conform_expr_to_default, ConformMode, Perform},
88
error::{ResolveError, ResolveErrorKind},
9-
Initialized,
9+
expr::static_member::resolve_impl_mention_from_type,
10+
Initialized, PolyValue,
1011
},
1112
source_files::Source,
1213
};
@@ -64,13 +65,70 @@ pub fn resolve_call_expr(
6465
pub fn call_callee(
6566
ctx: &mut ResolveExprCtx,
6667
call: &ast::Call,
67-
callee: Callee,
68+
mut callee: Callee,
6869
mut args: Vec<TypedExpr>,
6970
source: Source,
7071
) -> Result<TypedExpr, ResolveError> {
72+
for impl_arg in call.using.iter() {
73+
let (impl_ref, impl_poly_catalog) = resolve_impl_mention_from_type(ctx, impl_arg)?;
74+
75+
let imp = ctx
76+
.asg
77+
.impls
78+
.get(impl_ref)
79+
.expect("referenced impl to exist");
80+
81+
dbg!(&callee.recipe);
82+
dbg!(&imp.target);
83+
84+
let arg_concrete_trait = impl_poly_catalog.bake().resolve_trait(&imp.target)?;
85+
86+
let function = ctx.asg.funcs.get(callee.function).unwrap();
87+
for (poly_impl_name, param_generic_trait) in function.impl_params.params.iter() {
88+
let param_concrete_trait = callee.recipe.resolve_trait(param_generic_trait)?;
89+
90+
if arg_concrete_trait != param_concrete_trait {
91+
return Err(ResolveError::other(
92+
format!(
93+
"Implementation of {} cannot be used for {}",
94+
arg_concrete_trait.display(ctx.asg),
95+
param_concrete_trait.display(ctx.asg)
96+
),
97+
impl_arg.source,
98+
));
99+
}
100+
101+
dbg!(&arg_concrete_trait);
102+
dbg!(&param_concrete_trait);
103+
104+
if callee
105+
.recipe
106+
.polymorphs
107+
.insert(poly_impl_name.into(), PolyValue::Impl(impl_ref))
108+
.is_some()
109+
{
110+
return Err(ResolveError::other(
111+
format!(
112+
"Multiple implementations were specified for implementation parameter '${}'",
113+
poly_impl_name
114+
),
115+
impl_arg.source,
116+
));
117+
}
118+
}
119+
120+
// NOTE: We will need to populate the callee's poly recipe with `callee.recipe.polymorphs.insert()`
121+
// ...
122+
}
123+
71124
let function = ctx.asg.funcs.get(callee.function).unwrap();
72125
let num_required = function.params.required.len();
73126

127+
if !function.impl_params.params.is_empty() {
128+
dbg!(&function.impl_params);
129+
eprintln!("warning: calling functions with implementation parameters is not fully implemented yet!");
130+
}
131+
74132
for (i, arg) in args.iter_mut().enumerate() {
75133
let function = ctx.asg.funcs.get(callee.function).unwrap();
76134

Diff for: src/resolve/expr/static_member.rs

+75-37
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{call::call_callee, resolve_expr, ResolveExprCtx, ResolveExprMode};
22
use crate::{
3-
asg::{self, PolyCall, PolyCallee, TypeKind, TypedExpr},
3+
asg::{self, ImplRef, PolyCall, PolyCallee, TypeKind, TypedExpr},
44
ast::{self, StaticMemberCall, StaticMemberValue, TypeArg},
55
name::Name,
66
resolve::{
@@ -13,6 +13,7 @@ use crate::{
1313
initialized::Initialized,
1414
PolyCatalog, PolyRecipe,
1515
},
16+
source_files::Source,
1617
};
1718
use indexmap::IndexMap;
1819
use itertools::Itertools;
@@ -70,62 +71,52 @@ pub fn resolve_static_member_call(
7071
}
7172
}
7273

73-
pub fn resolve_static_member_call_named(
74+
pub fn resolve_impl_mention_from_type<'a>(
75+
ctx: &mut ResolveExprCtx,
76+
ty: &ast::Type,
77+
) -> Result<(ImplRef, PolyCatalog), ResolveError> {
78+
let ast::TypeKind::Named(name, type_args) = &ty.kind else {
79+
return Err(ResolveError::other(
80+
"Expected implementation name",
81+
ty.source,
82+
));
83+
};
84+
85+
resolve_impl_mention(ctx, name, type_args, ty.source)
86+
}
87+
88+
pub fn resolve_impl_mention(
7489
ctx: &mut ResolveExprCtx,
75-
static_member_call: &StaticMemberCall,
7690
impl_name: &Name,
7791
impl_args: &[TypeArg],
78-
) -> Result<TypedExpr, ResolveError> {
79-
let StaticMemberCall {
80-
subject: _,
81-
call,
82-
call_source,
83-
source,
84-
} = &static_member_call;
85-
92+
source: Source,
93+
) -> Result<(ImplRef, PolyCatalog), ResolveError> {
8694
let Some(impl_name) = impl_name.as_plain_str() else {
87-
return Err(ResolveError::other("Invalid implementation name", *source));
95+
return Err(ResolveError::other("Invalid implementation name", source));
8896
};
8997

9098
let impl_ref = ctx
9199
.impls_in_modules
92100
.get(&ctx.module_fs_node_id)
93101
.and_then(|impls| impls.get(impl_name));
94102

95-
let mut args = Vec::with_capacity(call.args.len());
96-
for arg in call.args.iter() {
97-
args.push(resolve_expr(
98-
ctx,
99-
arg,
100-
None,
101-
Initialized::Require,
102-
ResolveExprMode::RequireValue,
103-
)?);
104-
}
105-
106103
let Some(imp) = impl_ref.and_then(|found| ctx.asg.impls.get(*found)) else {
107104
return Err(ResolveError::other(
108105
"Undefined trait implementation",
109-
*source,
106+
source,
110107
));
111108
};
112109

110+
// Guaranteed to be valid now
111+
let impl_ref = impl_ref.unwrap();
112+
113113
if imp.name_params.len() != impl_args.len() {
114114
return Err(ResolveError::other(
115115
"Wrong number of arguments for implementation",
116-
*source,
116+
source,
117117
));
118118
}
119119

120-
let target = &imp.target;
121-
122-
let Some(callee_name) = call.name.as_plain_str() else {
123-
return Err(ResolveError::other(
124-
"Implementation does not have namespaced functions",
125-
*call_source,
126-
));
127-
};
128-
129120
let mut catalog = PolyCatalog::default();
130121

131122
for (name, arg) in imp.name_params.keys().zip(impl_args) {
@@ -144,9 +135,56 @@ pub fn resolve_static_member_call_named(
144135
}
145136
}
146137

147-
let mut only_match = imp.body.get(callee_name).into_iter().flat_map(|func_ref| {
148-
FuncHaystack::fits(ctx, *func_ref, &args, Some(catalog.clone()), *call_source)
149-
});
138+
Ok((*impl_ref, catalog))
139+
}
140+
141+
pub fn resolve_static_member_call_named(
142+
ctx: &mut ResolveExprCtx,
143+
static_member_call: &StaticMemberCall,
144+
impl_name: &Name,
145+
impl_args: &[TypeArg],
146+
) -> Result<TypedExpr, ResolveError> {
147+
let StaticMemberCall {
148+
subject: _,
149+
call,
150+
call_source,
151+
source: _,
152+
} = &static_member_call;
153+
154+
let mut args = Vec::with_capacity(call.args.len());
155+
for arg in call.args.iter() {
156+
args.push(resolve_expr(
157+
ctx,
158+
arg,
159+
None,
160+
Initialized::Require,
161+
ResolveExprMode::RequireValue,
162+
)?);
163+
}
164+
165+
let (impl_ref, catalog) =
166+
resolve_impl_mention(ctx, impl_name, impl_args, static_member_call.source)?;
167+
168+
let Some(callee_name) = call.name.as_plain_str() else {
169+
return Err(ResolveError::other(
170+
"Implementation does not have namespaced functions",
171+
*call_source,
172+
));
173+
};
174+
let imp = ctx
175+
.asg
176+
.impls
177+
.get(impl_ref)
178+
.expect("referenced impl to exist");
179+
180+
let mut only_match = imp
181+
.body
182+
.get(callee_name)
183+
.into_iter()
184+
.copied()
185+
.flat_map(|func_ref| {
186+
FuncHaystack::fits(ctx, func_ref, &args, Some(catalog.clone()), *call_source)
187+
});
150188

151189
let callee = only_match.next().ok_or_else(|| {
152190
ResolveErrorKind::FailedToFindFunction {

Diff for: src/resolve/polymorph.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use super::expr::ResolveExprCtx;
22
use crate::{
3-
asg::{self, Type},
3+
asg::{self, GenericTraitRef, Type},
44
source_files::Source,
55
};
66
use core::hash::Hash;
77
use derive_more::IsVariant;
88
use indexmap::IndexMap;
9+
use itertools::Itertools;
910
use std::fmt::Display;
1011

1112
// TODO: We probably want this to store some kind of internal hash
@@ -41,8 +42,11 @@ impl Display for PolyRecipe {
4142
PolyValue::Expr(_) => {
4243
todo!("mangle name for polymorphic function with expr polymorph")
4344
}
44-
PolyValue::Impl(_) => {
45-
todo!("mangle name for polymorphic implementation with impl polymorph")
45+
PolyValue::Impl(impl_ref) => {
46+
eprintln!(
47+
"warning: name mangling for functions called with impl params is ad-hoc"
48+
);
49+
write!(f, "{:?}", impl_ref)?;
4650
}
4751
}
4852

@@ -152,6 +156,20 @@ impl PolyRecipe {
152156
}
153157
.map_err(|err| err.at(source))
154158
}
159+
160+
pub fn resolve_trait(
161+
&self,
162+
generic_trait: &GenericTraitRef,
163+
) -> Result<GenericTraitRef, PolymorphError> {
164+
Ok(GenericTraitRef {
165+
trait_ref: generic_trait.trait_ref,
166+
args: generic_trait
167+
.args
168+
.iter()
169+
.map(|ty| self.resolve_type(ty))
170+
.try_collect()?,
171+
})
172+
}
155173
}
156174

157175
impl Hash for PolyRecipe {

0 commit comments

Comments
 (0)