Skip to content

Commit 0997fe0

Browse files
committed
Improved error messages for calling functions without specifying the required implementation arguments or with non-existent target implementation parameters specified
1 parent 301435e commit 0997fe0

File tree

12 files changed

+142
-105
lines changed

12 files changed

+142
-105
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ pub struct Call {
99

1010
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
1111
pub struct Callee {
12-
pub function: FuncRef,
12+
pub func_ref: FuncRef,
1313
pub recipe: PolyRecipe,
1414
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::Expr;
22
use crate::{
33
ast::{Type, TypeArg},
44
name::Name,
5+
source_files::source::Sourced,
56
};
67

78
#[derive(Clone, Debug)]
@@ -15,6 +16,6 @@ pub struct Call {
1516

1617
#[derive(Clone, Debug)]
1718
pub struct Using {
18-
pub name: Option<String>,
19+
pub name: Option<Sourced<String>>,
1920
pub ty: Type,
2021
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub fn lower_expr_call(
2323
expr,
2424
function,
2525
asg,
26-
call.callee.function,
26+
call.callee.func_ref,
2727
&call.callee.recipe,
2828
call.args.as_slice(),
2929
)

Diff for: src/parser/parse_annotation.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
1919
let mut annotations = Vec::with_capacity(2);
2020

2121
loop {
22-
let (annotation_name, source) =
23-
self.parse_identifier_keep_location(Some("for annotation name"))?;
22+
let (annotation_name, source) = self
23+
.parse_identifier_keep_location(Some("for annotation name"))?
24+
.tuple();
2425

2526
let annotation = match annotation_name.as_str() {
2627
"foreign" => AnnotationKind::Foreign,

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
8484

8585
let name = (self.input.peek().is_identifier()
8686
&& self.input.peek_nth(1).could_start_type())
87-
.then(|| self.parse_identifier(Some("for implementation parameter name")))
87+
.then(|| {
88+
self.parse_identifier_keep_location(Some("for implementation parameter name"))
89+
})
8890
.transpose()?;
8991

9092
using.push(Using {

Diff for: src/parser/parse_global_variable.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
3232
}
3333
}
3434

35-
let (name, source) =
36-
self.parse_identifier_keep_location(Some("for name of global variable"))?;
35+
let (name, source) = self
36+
.parse_identifier_keep_location(Some("for name of global variable"))?
37+
.tuple();
3738

3839
// Better error message for trying to call functions at global scope
3940
if self.input.peek_is(TokenKind::OpenParen) {

Diff for: src/parser/parse_stmt/parse_declaration.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use crate::{
77

88
impl<'a, I: Inflow<Token>> Parser<'a, I> {
99
pub fn parse_declaration(&mut self) -> Result<Stmt, ParseError> {
10-
let (name, source) = self.parse_identifier_keep_location(Some("for variable name"))?;
10+
let (name, source) = self
11+
.parse_identifier_keep_location(Some("for variable name"))?
12+
.tuple();
1113

1214
let variable_type = self.parse_type(None::<&str>, Some("for variable"))?;
1315

Diff for: src/parser/parse_util.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::{
55
use crate::{
66
inflow::Inflow,
77
name::Name,
8-
source_files::Source,
8+
source_files::{source::Sourced, Source},
99
token::{Token, TokenKind},
1010
};
1111
use std::borrow::Borrow;
@@ -30,17 +30,20 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
3030
&mut self,
3131
for_reason: Option<impl ToString>,
3232
) -> Result<String, ParseError> {
33-
Ok(self.parse_identifier_keep_location(for_reason)?.0)
33+
Ok(self
34+
.parse_identifier_keep_location(for_reason)?
35+
.inner()
36+
.into())
3437
}
3538

3639
pub fn parse_identifier_keep_location(
3740
&mut self,
3841
for_reason: Option<impl ToString>,
39-
) -> Result<(String, Source), ParseError> {
42+
) -> Result<Sourced<String>, ParseError> {
4043
let token = self.input.advance();
4144

4245
if let TokenKind::Identifier(identifier) = &token.kind {
43-
Ok((identifier.into(), token.source))
46+
Ok(Sourced::new(identifier.into(), token.source))
4447
} else {
4548
Err(ParseError::expected("identifier", for_reason, token))
4649
}

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

+58-87
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
use crate::{
2-
asg::{Callee, GenericTraitRef},
2+
asg::{self, Callee, GenericTraitRef, ImplParams},
33
ast::{self, Using},
44
resolve::{
55
error::ResolveError,
66
expr::{static_member::resolve_impl_mention_from_type, ResolveExprCtx},
77
PolyValue,
88
},
9-
source_files::Source,
9+
source_files::{source::Sourced, Source},
1010
};
1111
use std::collections::HashSet;
1212

1313
pub fn resolve_impl_arg(
1414
ctx: &mut ResolveExprCtx,
1515
callee: &mut Callee,
16-
source: Source,
1716
using: &Using,
1817
used_names: &mut HashSet<String>,
1918
) -> Result<(), ResolveError> {
@@ -22,7 +21,7 @@ pub fn resolve_impl_arg(
2221
if let ast::TypeKind::Polymorph(polymorph, args_to_polymorph) = &impl_arg.kind {
2322
resolve_polymorph_impl_arg(ctx, callee, using, polymorph, args_to_polymorph, used_names)
2423
} else {
25-
resolve_concrete_impl_arg(ctx, callee, using, impl_arg, source, used_names)
24+
resolve_concrete_impl_arg(ctx, callee, using, impl_arg, used_names)
2625
}
2726
}
2827

@@ -31,7 +30,6 @@ fn resolve_concrete_impl_arg(
3130
callee: &mut Callee,
3231
using: &Using,
3332
impl_arg: &ast::Type,
34-
call_source: Source,
3533
used_names: &mut HashSet<String>,
3634
) -> Result<(), ResolveError> {
3735
let impl_arg_source = using.ty.source;
@@ -44,51 +42,18 @@ fn resolve_concrete_impl_arg(
4442
.expect("referenced impl to exist");
4543

4644
let arg_concrete_trait = impl_poly_catalog.bake().resolve_trait(&imp.target)?;
47-
48-
let function = ctx.asg.funcs.get(callee.function).unwrap();
49-
50-
let target_poly_impl_name = match &using.name {
51-
Some(name) => name,
52-
None => function
53-
.impl_params
54-
.params
55-
.iter()
56-
.filter(|(param_name, param)| {
57-
param.trait_ref == arg_concrete_trait.trait_ref && !used_names.contains(*param_name)
58-
})
59-
.map(|(param_name, _)| param_name)
60-
.next()
61-
.ok_or_else(|| {
62-
ResolveError::other(
63-
format!(
64-
"Excess implementation of trait '{}' is not used by callee",
65-
arg_concrete_trait.display(&ctx.asg)
66-
),
67-
impl_arg.source,
68-
)
69-
})?,
70-
}
71-
.clone();
72-
73-
let Some(param_generic_trait) = function.impl_params.params.get(&target_poly_impl_name) else {
74-
return Err(ResolveError::other(
75-
format!(
76-
"Callee does not have implementation parameter '${}'",
77-
target_poly_impl_name
78-
),
79-
call_source,
80-
));
81-
};
45+
let callee_func = ctx.asg.funcs.get(callee.func_ref).unwrap();
8246

8347
try_register_specified_impl(
8448
ctx,
8549
callee,
86-
target_poly_impl_name,
50+
callee_func,
51+
using,
8752
impl_arg_source,
8853
used_names,
8954
PolyValue::Impl(impl_ref),
9055
&arg_concrete_trait,
91-
&param_generic_trait,
56+
&callee_func.impl_params,
9257
)
9358
}
9459

@@ -101,7 +66,7 @@ fn resolve_polymorph_impl_arg(
10166
used_names: &mut HashSet<String>,
10267
) -> Result<(), ResolveError> {
10368
let impl_arg_source = using.ty.source;
104-
let callee_func = ctx.asg.funcs.get(callee.function).unwrap();
69+
let callee_func = ctx.asg.funcs.get(callee.func_ref).unwrap();
10570

10671
if !args_to_polymorph.is_empty() {
10772
return Err(ResolveError::other(
@@ -130,69 +95,75 @@ fn resolve_polymorph_impl_arg(
13095
));
13196
};
13297

133-
let target_poly_impl_name = match &using.name {
134-
Some(name) => name,
135-
None => callee_func
136-
.impl_params
137-
.params
138-
.iter()
139-
.filter(|(param_name, param)| {
140-
param.trait_ref == arg_concrete_trait.trait_ref && !used_names.contains(*param_name)
141-
})
142-
.map(|(param_name, _)| param_name)
143-
.next()
144-
.ok_or_else(|| {
145-
ResolveError::other(
146-
format!(
147-
"Excess implementation of trait '{}' is not used by callee",
148-
arg_concrete_trait.display(&ctx.asg)
149-
),
150-
impl_arg_source,
151-
)
152-
})?,
153-
}
154-
.clone();
155-
156-
let Some(param_generic_trait) = callee_func.impl_params.params.get(&target_poly_impl_name)
157-
else {
158-
return Err(ResolveError::other(
159-
format!(
160-
"Callee does not have implementation parameter '${}'",
161-
target_poly_impl_name
162-
),
163-
impl_arg_source,
164-
));
165-
};
166-
16798
try_register_specified_impl(
16899
ctx,
169100
callee,
170-
target_poly_impl_name,
101+
callee_func,
102+
using,
171103
impl_arg_source,
172104
used_names,
173105
PolyValue::PolyImpl(polymorph.into()),
174106
arg_concrete_trait,
175-
param_generic_trait,
107+
&callee_func.impl_params,
176108
)
177109
}
178110

179111
fn try_register_specified_impl(
180112
ctx: &ResolveExprCtx,
181113
callee: &mut Callee,
182-
target_poly_impl_name: String,
114+
callee_func: &asg::Func,
115+
using: &Using,
183116
impl_arg_source: Source,
184117
used_names: &mut HashSet<String>,
185118
poly_value: PolyValue,
186119
arg_concrete_trait: &GenericTraitRef,
187-
param_generic_trait: &GenericTraitRef,
120+
impl_params: &ImplParams,
188121
) -> Result<(), ResolveError> {
189-
if !used_names.insert(target_poly_impl_name.clone()) {
122+
let target_poly_impl = match &using.name {
123+
Some(name_and_source) => name_and_source.as_ref(),
124+
None => Sourced::new(
125+
callee_func
126+
.impl_params
127+
.params
128+
.iter()
129+
.filter(|(param_name, param)| {
130+
param.trait_ref == arg_concrete_trait.trait_ref
131+
&& !used_names.contains(*param_name)
132+
})
133+
.map(|(param_name, _)| param_name)
134+
.next()
135+
.ok_or_else(|| {
136+
ResolveError::other(
137+
format!(
138+
"Excess implementation of trait '{}' is not used by callee",
139+
arg_concrete_trait.display(&ctx.asg)
140+
),
141+
impl_arg_source,
142+
)
143+
})?,
144+
impl_arg_source,
145+
),
146+
}
147+
.clone();
148+
149+
let Some(param_generic_trait) = impl_params.params.get(target_poly_impl.inner().as_str())
150+
else {
151+
return Err(ResolveError::other(
152+
format!(
153+
"No implementation parameter named '${}' exists on callee",
154+
target_poly_impl.inner()
155+
),
156+
target_poly_impl.source,
157+
));
158+
};
159+
160+
if !used_names.insert(target_poly_impl.inner().to_string()) {
190161
return Err(ResolveError::other(
191162
format!(
192163
"Implementation for '${}' was already specified",
193-
target_poly_impl_name
164+
target_poly_impl.inner()
194165
),
195-
impl_arg_source,
166+
target_poly_impl.source,
196167
));
197168
}
198169

@@ -212,15 +183,15 @@ fn try_register_specified_impl(
212183
callee
213184
.recipe
214185
.polymorphs
215-
.insert(target_poly_impl_name.clone(), poly_value)
186+
.insert(target_poly_impl.inner().to_string(), poly_value)
216187
.is_some()
217188
.then(|| {
218189
ResolveError::other(
219190
format!(
220191
"Multiple implementations were specified for implementation parameter '${}'",
221-
target_poly_impl_name
192+
target_poly_impl.inner()
222193
),
223-
impl_arg_source,
194+
target_poly_impl.source,
224195
)
225196
})
226197
.map_or(Ok(()), Err)

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

+17-4
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,30 @@ pub fn call_callee(
7474
let mut used_names = HashSet::new();
7575

7676
for using in call.using.iter() {
77-
resolve_impl_arg(ctx, &mut callee, source, using, &mut used_names)?;
77+
resolve_impl_arg(ctx, &mut callee, using, &mut used_names)?;
7878
}
7979

80-
let function = ctx.asg.funcs.get(callee.function).unwrap();
80+
let function = ctx.asg.funcs.get(callee.func_ref).unwrap();
8181
let num_required = function.params.required.len();
8282

83+
for (expected_name, expected_trait) in function.impl_params.params.iter() {
84+
if !used_names.contains(expected_name) {
85+
return Err(ResolveError::other(
86+
format!(
87+
"Missing '${} {}' trait implementation required by function call",
88+
expected_name,
89+
expected_trait.display(&ctx.asg),
90+
),
91+
source,
92+
));
93+
}
94+
}
95+
8396
for (i, arg) in args.iter_mut().enumerate() {
84-
let function = ctx.asg.funcs.get(callee.function).unwrap();
97+
let function = ctx.asg.funcs.get(callee.func_ref).unwrap();
8598

8699
let preferred_type =
87-
(i < num_required).then_some(PreferredType::of_parameter(callee.function, i));
100+
(i < num_required).then_some(PreferredType::of_parameter(callee.func_ref, i));
88101

89102
if preferred_type.map_or(false, |ty| ty.view(&ctx.asg).kind.contains_polymorph()) {
90103
*arg = conform_expr_to_default::<Perform>(&*arg, ctx.c_integer_assumptions())

Diff for: src/resolve/func_haystack.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl FuncHaystack {
147147
}
148148

149149
Some(Callee {
150-
function: func_ref,
150+
func_ref,
151151
recipe: catalog.bake(),
152152
})
153153
}

0 commit comments

Comments
 (0)