Skip to content

Commit b7800f4

Browse files
committed
Started working on ability to pass trait implementations without specifying the target implementation parameter
1 parent 65bd95c commit b7800f4

File tree

4 files changed

+49
-8
lines changed

4 files changed

+49
-8
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ pub struct Call {
1515

1616
#[derive(Clone, Debug)]
1717
pub struct Using {
18-
pub name: String,
18+
pub name: Option<String>,
1919
pub ty: Type,
2020
}

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

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

85-
let name = self.parse_identifier(Some("for implementation parameter name"))?;
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+
};
8692

8793
using.push(Using {
8894
name,

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

+40-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{
1414
use itertools::Itertools;
1515
use num::BigInt;
1616
use ordered_float::NotNan;
17+
use std::collections::HashSet;
1718

1819
pub fn resolve_call_expr(
1920
ctx: &mut ResolveExprCtx,
@@ -69,6 +70,8 @@ pub fn call_callee(
6970
mut args: Vec<TypedExpr>,
7071
source: Source,
7172
) -> Result<TypedExpr, ResolveError> {
73+
let mut used_names = HashSet::new();
74+
7275
for impl_using in call.using.iter() {
7376
let impl_arg = &impl_using.ty;
7477
let (impl_ref, impl_poly_catalog) = resolve_impl_mention_from_type(ctx, impl_arg)?;
@@ -80,14 +83,46 @@ pub fn call_callee(
8083
.expect("referenced impl to exist");
8184

8285
let arg_concrete_trait = impl_poly_catalog.bake().resolve_trait(&imp.target)?;
83-
8486
let function = ctx.asg.funcs.get(callee.function).unwrap();
8587

86-
let poly_impl_name = &impl_using.name;
88+
let poly_impl_name = if let Some(name) = &impl_using.name {
89+
name.clone()
90+
} else {
91+
function
92+
.impl_params
93+
.params
94+
.iter()
95+
.filter(|(param_name, param)| {
96+
param.trait_ref == arg_concrete_trait.trait_ref
97+
&& used_names.contains(*param_name)
98+
})
99+
.map(|(param_name, _)| param_name)
100+
.next()
101+
.ok_or_else(|| {
102+
ResolveError::other(
103+
"No implementation parameter left for implementation argument",
104+
impl_arg.source,
105+
)
106+
})?
107+
.clone()
108+
};
87109

88-
let Some(param_generic_trait) = function.impl_params.params.get(&impl_using.name) else {
110+
if !used_names.insert(poly_impl_name.clone()) {
89111
return Err(ResolveError::other(
90-
format!("Unknown implementation argument '${}'", poly_impl_name),
112+
format!(
113+
"Implementation for '${}' was already specified",
114+
&poly_impl_name
115+
),
116+
impl_arg.source,
117+
));
118+
}
119+
120+
let Some(param_generic_trait) = function.impl_params.params.get(&poly_impl_name) else {
121+
return Err(ResolveError::other(
122+
format!(
123+
"Callee does not have implementation parameter '${}'",
124+
&poly_impl_name
125+
),
91126
source,
92127
));
93128
};
@@ -107,7 +142,7 @@ pub fn call_callee(
107142
if callee
108143
.recipe
109144
.polymorphs
110-
.insert(poly_impl_name.into(), PolyValue::Impl(impl_ref))
145+
.insert(poly_impl_name.clone(), PolyValue::Impl(impl_ref))
111146
.is_some()
112147
{
113148
return Err(ResolveError::other(

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ pub fn resolve_impl_mention(
102102

103103
let Some(imp) = impl_ref.and_then(|found| ctx.asg.impls.get(*found)) else {
104104
return Err(ResolveError::other(
105-
"Undefined trait implementation",
105+
format!("Undefined trait implementation '{}'", impl_name),
106106
source,
107107
));
108108
};

0 commit comments

Comments
 (0)