1use std::{fmt, sync::Arc};
2
3use super::Block;
4use crate::compiler::expression::function_call::Warning::AbortInfallible;
5use crate::compiler::state::{TypeInfo, TypeState};
6use crate::compiler::{
7 CompileConfig, Context, Expression, Function, Resolved, Span, TypeDef,
8 expression::{ExpressionError, FunctionArgument, levenstein},
9 function::{
10 ArgumentList, Closure, Example, FunctionCompileContext, Parameter,
11 closure::{self, VariableKind},
12 },
13 parser::{Ident, Node},
14 state::LocalEnv,
15 type_def::Details,
16 value::Kind,
17};
18use crate::diagnostic::{DiagnosticMessage, Label, Note, Severity, Urls};
19use crate::prelude::Note::SeeErrorDocs;
20
21pub(crate) struct Builder<'a> {
22 abort_on_error: bool,
23 arguments_with_unknown_type_validity: Vec<(Parameter, Node<FunctionArgument>)>,
24 call_span: Span,
25 ident_span: Span,
26 function_id: usize,
27 arguments: Arc<Vec<Node<FunctionArgument>>>,
28 closure: Option<(Vec<Ident>, closure::Input)>,
29 list: ArgumentList,
30 function: &'a dyn Function,
31}
32
33pub(crate) struct CallCompilationResult {
34 pub(crate) function_call: FunctionCall,
35 pub(crate) error: Option<FunctionCallError>,
36}
37
38impl<'a> Builder<'a> {
39 pub(crate) fn get_arg_list(&self) -> &ArgumentList {
40 &self.list
41 }
42
43 #[allow(clippy::too_many_lines)]
44 #[allow(clippy::too_many_arguments)]
45 pub(crate) fn new(
46 call_span: Span,
47 ident: Node<Ident>,
48 abort_on_error: bool,
49 arguments: Vec<Node<FunctionArgument>>,
50 funcs: &'a [Box<dyn Function>],
51 state_before_function_args: &TypeState,
52 state: &mut TypeState,
53 closure_variables: Option<Node<Vec<Node<Ident>>>>,
54 ) -> Result<Self, FunctionCallError> {
55 let (ident_span, ident) = ident.take();
56
57 let Some((function_id, function)) = funcs
59 .iter()
60 .enumerate()
61 .find(|(_pos, f)| f.identifier() == ident.as_ref())
62 else {
63 let idents = funcs
64 .iter()
65 .map(|func| func.identifier())
66 .collect::<Vec<_>>();
67
68 return Err(FunctionCallError::Undefined {
69 ident_span,
70 ident: ident.clone(),
71 idents,
72 });
73 };
74
75 if arguments.len() > function.parameters().len() {
77 let arguments_span = {
78 let start = arguments.first().unwrap().span().start();
79 let end = arguments.last().unwrap().span().end();
80
81 Span::new(start, end)
82 };
83
84 return Err(FunctionCallError::WrongNumberOfArgs {
85 arguments_span,
86 max: function.parameters().len(),
87 });
88 }
89
90 let mut index = 0;
96 let mut list = ArgumentList::default();
97
98 let mut arguments_with_unknown_type_validity = vec![];
99 for node in &arguments {
100 let (argument_span, argument) = node.clone().take();
101
102 let parameter = match argument.keyword() {
103 None => {
105 index += 1;
106 function.parameters().get(index - 1)
107 }
108
109 Some(k) => function
111 .parameters()
112 .iter()
113 .enumerate()
114 .find(|(_, param)| param.keyword == k)
115 .map(|(pos, param)| {
116 if pos == index {
117 index += 1;
118 }
119
120 param
121 }),
122 }
123 .ok_or_else(|| FunctionCallError::UnknownKeyword {
124 keyword_span: argument.keyword_span().expect("exists"),
125 ident_span,
126 keywords: function.parameters().iter().map(|p| p.keyword).collect(),
127 })?;
128
129 let argument_type_def = argument.expr().type_def(state_before_function_args);
131 let expr_kind = argument_type_def.kind();
132 let param_kind = parameter.kind();
133
134 if !param_kind.intersects(expr_kind) {
135 return Err(FunctionCallError::InvalidArgumentKind(
136 InvalidArgumentErrorContext {
137 function_ident: function.identifier(),
138 abort_on_error,
139 arguments_fmt: arguments
140 .iter()
141 .map(|arg| arg.inner().to_string())
142 .collect::<Vec<_>>(),
143 parameter: *parameter,
144 got: expr_kind.clone(),
145 argument,
146 argument_span,
147 },
148 ));
149 } else if param_kind.is_superset(expr_kind).is_err() {
150 arguments_with_unknown_type_validity.push((*parameter, node.clone()));
151 }
152
153 if argument_type_def.is_fallible() {
155 return Err(FunctionCallError::FallibleArgument {
156 expr_span: argument.span(),
157 });
158 }
159
160 list.insert(parameter.keyword, argument.into_inner());
161 }
162
163 function
165 .parameters()
166 .iter()
167 .enumerate()
168 .filter(|(_, p)| p.required)
169 .filter(|(_, p)| !list.keywords().contains(&p.keyword))
170 .try_for_each(|(i, p)| -> Result<_, _> {
171 Err(FunctionCallError::MissingArgument {
172 call_span,
173 keyword: p.keyword,
174 position: i,
175 })
176 })?;
177
178 let closure = Self::check_closure(
180 function.as_ref(),
181 closure_variables,
182 call_span,
183 &list,
184 state,
185 ident_span,
186 )?;
187
188 Ok(Self {
189 abort_on_error,
190 arguments_with_unknown_type_validity,
191 call_span,
192 ident_span,
193 function_id,
194 arguments: Arc::new(arguments),
195 closure,
196 list,
197 function: function.as_ref(),
198 })
199 }
200
201 #[allow(clippy::too_many_lines)]
202 fn check_closure(
203 function: &dyn Function,
204 closure_variables: Option<Node<Vec<Node<Ident>>>>,
205 call_span: Span,
206 list: &ArgumentList,
207 state: &mut TypeState,
208 ident_span: Span,
209 ) -> Result<Option<(Vec<Ident>, closure::Input)>, FunctionCallError> {
210 let closure = match (function.closure(), closure_variables) {
211 (None, Some(variables)) => {
214 let closure_span = variables.span();
215
216 return Err(FunctionCallError::UnexpectedClosure {
217 call_span,
218 closure_span,
219 });
220 }
221
222 (Some(definition), None) => {
224 let example = definition.inputs.first().map(|input| input.example);
225
226 return Err(FunctionCallError::MissingClosure { call_span, example });
227 }
228
229 (Some(definition), Some(variables)) => {
231 let mut matched = None;
232 let mut err_found_type_def = None;
233
234 for input in definition.inputs {
235 match list.arguments.get(input.parameter_keyword) {
237 None => (),
243
244 Some(expr) => {
248 let type_def = expr.type_def(state);
249 if input.kind.is_superset(type_def.kind()).is_err() {
257 err_found_type_def = Some(type_def.kind().clone());
258 continue;
259 }
260
261 matched = Some((input, expr));
262 break;
263 }
264 }
265 }
266
267 match matched {
269 None => {
270 return Err(FunctionCallError::ClosureParameterTypeMismatch {
271 call_span,
272 found_kind: err_found_type_def.unwrap_or_else(Kind::any),
273 });
274 }
275
276 Some((input, target)) => {
277 if input.variables.len() != variables.len() {
285 let closure_arguments_span =
286 variables.first().map_or(call_span, |node| {
287 (node.span().start(), variables.last().unwrap().span().end())
288 .into()
289 });
290
291 return Err(FunctionCallError::ClosureArityMismatch {
292 ident_span,
293 closure_arguments_span,
294 expected: input.variables.len(),
295 supplied: variables.len(),
296 });
297 }
298
299 for (index, input_var) in input.variables.clone().into_iter().enumerate() {
313 let call_ident = &variables[index];
314 let type_def = target.type_info(state).result;
315
316 let (type_def, value) = match input_var.kind {
317 VariableKind::Exact(kind) => (kind.into(), None),
320
321 VariableKind::Target => (
324 target.type_info(state).result,
325 target.resolve_constant(state),
326 ),
327
328 VariableKind::TargetInnerValue => {
335 let kind = if let Some(object) = type_def.as_object() {
336 object.reduced_kind()
337 } else if let Some(array) = type_def.as_array() {
338 array.reduced_kind()
339 } else {
340 Kind::any()
341 };
342
343 (kind.into(), None)
344 }
345
346 VariableKind::TargetInnerKey => {
358 let mut kind = Kind::never();
359
360 if type_def.is_collection() {
361 if type_def.is_object() {
362 kind.add_bytes();
363 }
364 if type_def.is_array() {
365 kind.add_integer();
366 }
367 } else {
368 kind = Kind::any();
369 }
370
371 (kind.into(), None)
372 }
373 };
374
375 let details = Details { type_def, value };
376
377 state
378 .local
379 .insert_variable(call_ident.clone().into_inner(), details);
380 }
381
382 let variables = variables
383 .into_inner()
384 .into_iter()
385 .map(Node::into_inner)
386 .collect();
387
388 Some((variables, input))
389 }
390 }
391 }
392
393 _ => None,
394 };
395 Ok(closure)
396 }
397
398 pub(crate) fn compile(
399 mut self,
400 state_before_function_args: &TypeState,
401 state: &mut TypeState,
402 closure_block: Option<Node<(Block, TypeDef)>>,
403 local_snapshot: LocalEnv,
404 config: &mut CompileConfig,
405 ) -> Result<CallCompilationResult, FunctionCallError> {
406 let (closure, closure_fallible) =
407 self.compile_closure(closure_block, local_snapshot, state)?;
408
409 let call_span = self.call_span;
410 let ident_span = self.ident_span;
411
412 let temp_config = std::mem::take(config);
416
417 let mut compile_ctx = FunctionCompileContext::new(self.call_span, temp_config);
418
419 let expr = self
420 .function
421 .compile(
422 state_before_function_args,
423 &mut compile_ctx,
424 self.list.clone(),
425 )
426 .map_err(|error| FunctionCallError::Compilation { call_span, error })?;
427
428 *config = compile_ctx.into_config();
430
431 let mut warnings = Vec::new();
435 if self.abort_on_error
436 && self.arguments_with_unknown_type_validity.is_empty()
437 && !expr
438 .type_info(state_before_function_args)
439 .result
440 .is_fallible()
441 {
442 warnings.push(AbortInfallible {
443 ident_span,
444 abort_span: Span::new(ident_span.end(), ident_span.end() + 1),
445 });
446 }
447
448 let mut invalid_argument_error = None;
452 if let Some((parameter, argument)) =
453 self.arguments_with_unknown_type_validity.first().cloned()
454 && !self.abort_on_error
455 {
456 invalid_argument_error = Some(FunctionCallError::InvalidArgumentKind(
457 InvalidArgumentErrorContext {
458 function_ident: self.function.identifier(),
459 abort_on_error: self.abort_on_error,
460 arguments_fmt: self
461 .arguments
462 .iter()
463 .map(|arg| arg.inner().to_string())
464 .collect::<Vec<_>>(),
465 parameter,
466 got: argument
467 .expr()
468 .type_info(state_before_function_args)
469 .result
470 .into(),
471 argument: argument.clone().into_inner(),
472 argument_span: argument
473 .keyword_span()
474 .unwrap_or_else(|| argument.expr_span()),
475 },
476 ));
477 }
478
479 Ok(CallCompilationResult {
480 function_call: FunctionCall {
481 abort_on_error: self.abort_on_error,
482 expr,
483 arguments_with_unknown_type_validity: self.arguments_with_unknown_type_validity,
484 closure_fallible,
485 closure,
486 span: call_span,
487 ident: self.function.identifier(),
488 function_id: self.function_id,
489 arguments: self.arguments.clone(),
490 warnings,
491 },
492 error: invalid_argument_error,
493 })
494 }
495
496 fn compile_closure(
497 &mut self,
498 closure_block: Option<Node<(Block, TypeDef)>>,
499 mut locals: LocalEnv,
500 state: &mut TypeState,
501 ) -> Result<(Option<Closure>, bool), FunctionCallError> {
502 if let Some((variables, input)) = self.closure.clone() {
504 let block = closure_block.expect("closure must contain block");
508
509 for ident in &variables {
512 match locals.remove_variable(ident) {
513 Some(details) => state.local.insert_variable(ident.clone(), details),
514 None => {
515 state.local.remove_variable(ident);
516 }
517 }
518 }
519
520 let (block_span, (block, block_type_def)) = block.take();
521
522 let closure_fallible = block_type_def.is_fallible();
523
524 let expected_kind = input.output.into_kind();
527 let found_kind = block_type_def
528 .kind()
529 .union(block_type_def.returns().clone());
530
531 if expected_kind.is_superset(&found_kind).is_err() {
532 return Err(FunctionCallError::ReturnTypeMismatch {
533 block_span,
534 found_kind,
535 expected_kind,
536 });
537 }
538
539 let fnclosure = Closure::new(variables, block, block_type_def);
540 self.list.set_closure(fnclosure.clone());
541
542 Ok((Some(fnclosure), closure_fallible))
544 } else {
545 Ok((None, false))
546 }
547 }
548}
549
550#[derive(Clone)]
551pub struct FunctionCall {
552 abort_on_error: bool,
553 expr: Box<dyn Expression>,
554 arguments_with_unknown_type_validity: Vec<(Parameter, Node<FunctionArgument>)>,
555 closure_fallible: bool,
556 #[allow(dead_code)]
558 closure: Option<Closure>,
559
560 pub(crate) span: Span,
564
565 pub(crate) ident: &'static str,
567
568 #[allow(dead_code)]
570 function_id: usize,
571 arguments: Arc<Vec<Node<FunctionArgument>>>,
572
573 pub(crate) warnings: Vec<Warning>,
574}
575
576impl FunctionCall {
577 #[allow(dead_code)]
583 fn resolve_arguments(
584 &self,
585 function: &dyn Function,
586 ) -> Result<Vec<(&'static str, Option<FunctionArgument>)>, String> {
587 let params = function.parameters().to_vec();
588 let mut result = params
589 .iter()
590 .map(|param| (param.keyword, None))
591 .collect::<Vec<_>>();
592
593 let mut unnamed = Vec::new();
594
595 for param in self.arguments.iter() {
597 match param.keyword() {
598 None => unnamed.push(param.clone().take().1),
599 Some(keyword) => {
600 match params.iter().position(|param| param.keyword == keyword) {
601 None => {
602 return Err(format!("parameter {keyword} not found."));
604 }
605 Some(pos) => {
606 result[pos].1 = Some(param.clone().take().1);
607 }
608 }
609 }
610 }
611 }
612
613 let mut pos = 0;
615 for param in unnamed {
616 while result[pos].1.is_some() {
617 pos += 1;
618 }
619
620 if pos > result.len() {
621 return Err("Too many parameters".to_string());
622 }
623
624 result[pos].1 = Some(param);
625 }
626
627 Ok(result)
628 }
629
630 #[must_use]
631 pub fn arguments_fmt(&self) -> Vec<String> {
632 self.arguments
633 .iter()
634 .map(|arg| arg.inner().to_string())
635 .collect::<Vec<_>>()
636 }
637
638 #[must_use]
639 pub fn arguments_dbg(&self) -> Vec<String> {
640 self.arguments
641 .iter()
642 .map(|arg| format!("{:?}", arg.inner()))
643 .collect::<Vec<_>>()
644 }
645}
646
647impl Expression for FunctionCall {
648 fn resolve(&self, ctx: &mut Context) -> Resolved {
649 self.expr.resolve(ctx).map_err(|err| match err {
650 ExpressionError::Abort { .. }
651 | ExpressionError::Fallible { .. }
652 | ExpressionError::Missing { .. } => {
653 err
655 }
656 ExpressionError::Return { span, .. } => ExpressionError::Error {
657 message: "return cannot be used inside closures".to_owned(),
658 labels: vec![Label::primary(
659 "return cannot be used inside closures",
660 span,
661 )],
662 notes: Vec::new(),
663 },
664 ExpressionError::Error {
665 message,
666 mut labels,
667 notes,
668 } => {
669 labels.push(Label::primary(message.clone(), self.span));
670
671 ExpressionError::Error {
672 message: format!(
673 r#"function call error for "{}" at ({}:{}): {}"#,
674 self.ident,
675 self.span.start(),
676 self.span.end(),
677 message
678 ),
679 labels,
680 notes,
681 }
682 }
683 })
684 }
685
686 fn type_info(&self, state: &TypeState) -> TypeInfo {
687 let mut state = state.clone();
688
689 for arg_node in &*self.arguments {
697 let _result = arg_node.inner().expr().apply_type_info(&mut state);
698 }
699
700 let mut expr_result = self.expr.apply_type_info(&mut state);
701
702 if !self.arguments_with_unknown_type_validity.is_empty() {
760 expr_result = expr_result.fallible();
761 }
762
763 if self.closure_fallible {
776 expr_result = expr_result.fallible();
777 }
778
779 if self.abort_on_error {
780 expr_result = expr_result.infallible();
781 }
782
783 TypeInfo::new(state, expr_result)
784 }
785}
786
787impl fmt::Display for FunctionCall {
788 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
789 self.ident.fmt(f)?;
790 f.write_str("(")?;
791
792 let arguments = self.arguments_fmt();
793 let mut iter = arguments.iter().peekable();
794 while let Some(arg) = iter.next() {
795 f.write_str(arg)?;
796
797 if iter.peek().is_some() {
798 f.write_str(", ")?;
799 }
800 }
801
802 f.write_str(")")
803 }
804}
805
806impl fmt::Debug for FunctionCall {
807 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
808 f.write_str("FunctionCall(")?;
809 self.ident.fmt(f)?;
810
811 f.write_str("(")?;
812
813 let arguments = self.arguments_dbg();
814 let mut iter = arguments.iter().peekable();
815 while let Some(arg) = iter.next() {
816 f.write_str(arg)?;
817
818 if iter.peek().is_some() {
819 f.write_str(", ")?;
820 }
821 }
822
823 f.write_str("))")
824 }
825}
826
827impl PartialEq for FunctionCall {
828 fn eq(&self, other: &Self) -> bool {
829 self.ident == other.ident
830 }
831}
832
833#[derive(Debug, Clone)]
835pub(crate) struct InvalidArgumentErrorContext {
836 pub(crate) function_ident: &'static str,
837 pub(crate) abort_on_error: bool,
838 pub(crate) arguments_fmt: Vec<String>,
839 pub(crate) parameter: Parameter,
840 pub(crate) got: Kind,
841 pub(crate) argument: FunctionArgument,
842 pub(crate) argument_span: Span,
843}
844
845#[derive(thiserror::Error, Debug, Clone)]
846pub(crate) enum Warning {
847 #[error("can't abort infallible function")]
848 AbortInfallible { ident_span: Span, abort_span: Span },
849}
850
851#[derive(thiserror::Error, Debug)]
852#[allow(clippy::large_enum_variant)]
853pub(crate) enum FunctionCallError {
854 #[error("call to undefined function")]
855 Undefined {
856 ident_span: Span,
857 ident: Ident,
858 idents: Vec<&'static str>,
859 },
860
861 #[error("wrong number of function arguments")]
862 WrongNumberOfArgs { arguments_span: Span, max: usize },
863
864 #[error("unknown function argument keyword")]
865 UnknownKeyword {
866 keyword_span: Span,
867 ident_span: Span,
868 keywords: Vec<&'static str>,
869 },
870
871 #[error("missing function argument")]
872 MissingArgument {
873 call_span: Span,
874 keyword: &'static str,
875 position: usize,
876 },
877
878 #[error("function compilation error: error[E{}] {}", error.code(), error)]
879 Compilation {
880 call_span: Span,
881 error: Box<dyn DiagnosticMessage>,
882 },
883
884 #[error("invalid argument type")]
885 InvalidArgumentKind(InvalidArgumentErrorContext),
886
887 #[error("fallible argument")]
888 FallibleArgument { expr_span: Span },
889
890 #[error("unexpected closure")]
891 UnexpectedClosure { call_span: Span, closure_span: Span },
892
893 #[error("missing closure")]
894 MissingClosure {
895 call_span: Span,
896 example: Option<Example>,
897 },
898
899 #[error("invalid closure arity")]
900 ClosureArityMismatch {
901 ident_span: Span,
902 closure_arguments_span: Span,
903 expected: usize,
904 supplied: usize,
905 },
906 #[error("type mismatch in closure parameter")]
907 ClosureParameterTypeMismatch { call_span: Span, found_kind: Kind },
908 #[error("type mismatch in closure return type")]
909 ReturnTypeMismatch {
910 block_span: Span,
911 found_kind: Kind,
912 expected_kind: Kind,
913 },
914}
915
916impl DiagnosticMessage for Warning {
917 fn code(&self) -> usize {
918 match self {
919 AbortInfallible { .. } => 620,
920 }
921 }
922
923 fn labels(&self) -> Vec<Label> {
924 match self {
925 AbortInfallible {
926 ident_span,
927 abort_span,
928 } => {
929 vec![
930 Label::primary("this function can't fail", ident_span),
931 Label::context("remove this abort (!) instruction", abort_span),
932 ]
933 }
934 }
935 }
936
937 fn notes(&self) -> Vec<Note> {
938 vec![SeeErrorDocs]
939 }
940
941 fn severity(&self) -> Severity {
942 Severity::Warning
943 }
944}
945
946impl DiagnosticMessage for FunctionCallError {
947 fn code(&self) -> usize {
948 use FunctionCallError::{
949 ClosureArityMismatch, ClosureParameterTypeMismatch, Compilation, FallibleArgument,
950 InvalidArgumentKind, MissingArgument, MissingClosure, ReturnTypeMismatch, Undefined,
951 UnexpectedClosure, UnknownKeyword, WrongNumberOfArgs,
952 };
953
954 match self {
955 Undefined { .. } => 105,
956 WrongNumberOfArgs { .. } => 106,
957 UnknownKeyword { .. } => 108,
958 Compilation { .. } => 610,
959 MissingArgument { .. } => 107,
960 InvalidArgumentKind { .. } => 110,
961 FallibleArgument { .. } => 630,
962 UnexpectedClosure { .. } => 109,
963 MissingClosure { .. } => 111,
964 ClosureArityMismatch { .. } => 120,
965 ClosureParameterTypeMismatch { .. } => 121,
966 ReturnTypeMismatch { .. } => 122,
967 }
968 }
969
970 #[allow(clippy::too_many_lines)]
971 fn labels(&self) -> Vec<Label> {
972 use FunctionCallError::{
973 ClosureArityMismatch, ClosureParameterTypeMismatch, Compilation, FallibleArgument,
974 InvalidArgumentKind, MissingArgument, MissingClosure, ReturnTypeMismatch, Undefined,
975 UnexpectedClosure, UnknownKeyword, WrongNumberOfArgs,
976 };
977
978 match self {
979 Undefined {
980 ident_span,
981 ident,
982 idents,
983 } => {
984 let mut vec = vec![Label::primary("undefined function", ident_span)];
985 let ident_chars = ident.as_ref().chars().collect::<Vec<_>>();
986
987 if let Some((idx, _)) = idents
988 .iter()
989 .map(|possible| {
990 let possible_chars = possible.chars().collect::<Vec<_>>();
991 levenstein::distance(&ident_chars, &possible_chars)
992 })
993 .enumerate()
994 .min_by_key(|(_, score)| *score)
995 {
996 {
997 let guessed: &str = idents[idx];
998 vec.push(Label::context(
999 format!(r#"did you mean "{guessed}"?"#),
1000 ident_span,
1001 ));
1002 }
1003 }
1004
1005 vec
1006 }
1007
1008 WrongNumberOfArgs {
1009 arguments_span,
1010 max,
1011 } => {
1012 let arg = if *max == 1 { "argument" } else { "arguments" };
1013
1014 vec![
1015 Label::primary("too many function arguments", arguments_span),
1016 Label::context(
1017 format!("this function takes a maximum of {max} {arg}"),
1018 arguments_span,
1019 ),
1020 ]
1021 }
1022
1023 UnknownKeyword {
1024 keyword_span,
1025 ident_span,
1026 keywords,
1027 } => vec![
1028 Label::primary("unknown keyword", keyword_span),
1029 Label::context(
1030 format!(
1031 "this function accepts the following keywords: {}",
1032 keywords
1033 .iter()
1034 .map(|k| format!(r#""{k}""#))
1035 .collect::<Vec<_>>()
1036 .join(", ")
1037 ),
1038 ident_span,
1039 ),
1040 ],
1041
1042 Compilation { call_span, error } => error
1043 .labels()
1044 .into_iter()
1045 .map(|mut label| {
1046 label.span = *call_span;
1047 label
1048 })
1049 .collect(),
1050
1051 MissingArgument {
1052 call_span,
1053 keyword,
1054 position,
1055 } => {
1056 vec![Label::primary(
1057 format!(r#"required argument missing: "{keyword}" (position {position})"#),
1058 call_span,
1059 )]
1060 }
1061
1062 InvalidArgumentKind(context) => {
1063 let keyword = context.parameter.keyword;
1064 let expected = context.parameter.kind();
1065 let expr_span = context.argument.span();
1066
1067 let kind_str = |kind: &Kind| {
1069 if kind.is_any() {
1070 kind.to_string()
1071 } else if kind.is_exact() {
1072 format!("the exact type {kind}")
1073 } else {
1074 format!("one of {kind}")
1075 }
1076 };
1077
1078 vec![
1079 Label::primary(
1080 format!("this expression resolves to {}", kind_str(&context.got)),
1081 expr_span,
1082 ),
1083 Label::context(
1084 format!(
1085 r#"but the parameter "{}" expects {}"#,
1086 keyword,
1087 kind_str(&expected)
1088 ),
1089 context.argument_span,
1090 ),
1091 ]
1092 }
1093
1094 FallibleArgument { expr_span } => vec![
1095 Label::primary("this expression can fail", expr_span),
1096 Label::context(
1097 "handle the error before passing it in as an argument",
1098 expr_span,
1099 ),
1100 ],
1101 UnexpectedClosure {
1102 call_span,
1103 closure_span,
1104 } => vec![
1105 Label::primary("unexpected closure", closure_span),
1106 Label::context("this function does not accept a closure", call_span),
1107 ],
1108 MissingClosure { call_span, .. } => {
1109 vec![Label::primary("this function expects a closure", call_span)]
1110 }
1111 ClosureArityMismatch {
1112 ident_span,
1113 closure_arguments_span,
1114 expected,
1115 supplied,
1116 } => vec![
1117 Label::primary(
1118 format!("this function requires a closure with {expected} argument(s)"),
1119 ident_span,
1120 ),
1121 Label::context(
1122 format!("but {supplied} argument(s) are supplied"),
1123 closure_arguments_span,
1124 ),
1125 ],
1126 ClosureParameterTypeMismatch {
1127 call_span,
1128 found_kind,
1129 } => vec![
1130 Label::primary(
1131 "the closure tied to this function call expects a different input value",
1132 call_span,
1133 ),
1134 Label::context(
1135 format!(
1136 "expression has an inferred type of {found_kind} where an array or object was expected"
1137 ),
1138 call_span,
1139 ),
1140 ],
1141 ReturnTypeMismatch {
1142 block_span,
1143 found_kind,
1144 expected_kind,
1145 } => vec![
1146 Label::primary("block returns invalid value type", block_span),
1147 Label::context(format!("expected: {expected_kind}"), block_span),
1148 Label::context(format!("received: {found_kind}"), block_span),
1149 ],
1150 }
1151 }
1152
1153 fn notes(&self) -> Vec<Note> {
1154 use FunctionCallError::{
1155 Compilation, FallibleArgument, InvalidArgumentKind, MissingClosure, WrongNumberOfArgs,
1156 };
1157
1158 match self {
1159 WrongNumberOfArgs { .. } => vec![Note::SeeDocs(
1160 "function arguments".to_owned(),
1161 Urls::expression_docs_url("#arguments"),
1162 )],
1163 FallibleArgument { .. } => vec![Note::SeeErrorDocs],
1164 InvalidArgumentKind(context) => {
1165 let kind = &context.parameter.kind();
1167 let argument = &context.argument;
1168 let guard = if kind.is_bytes() {
1169 format!("string!({argument})")
1170 } else if kind.is_integer() {
1171 format!("int!({argument})")
1172 } else if kind.is_float() {
1173 format!("float!({argument})")
1174 } else if kind.is_boolean() {
1175 format!("bool!({argument})")
1176 } else if kind.is_object() {
1177 format!("object!({argument})")
1178 } else if kind.is_array() {
1179 format!("array!({argument})")
1180 } else if kind.is_timestamp() {
1181 format!("timestamp!({argument})")
1182 } else {
1183 return vec![];
1184 };
1185
1186 let coerce = if kind.is_bytes() {
1187 Some(format!(r#"to_string({argument}) ?? "default""#))
1188 } else if kind.is_integer() {
1189 Some(format!("to_int({argument}) ?? 0"))
1190 } else if kind.is_float() {
1191 Some(format!("to_float({argument}) ?? 0"))
1192 } else if kind.is_boolean() {
1193 Some(format!("to_bool({argument}) ?? false"))
1194 } else if kind.is_timestamp() {
1195 Some(format!("to_unix_timestamp({argument}) ?? now()"))
1196 } else {
1197 None
1198 };
1199
1200 let args = {
1201 let mut args = String::new();
1202 let mut iter = context.arguments_fmt.iter().peekable();
1203 while let Some(arg) = iter.next() {
1204 args.push_str(arg);
1205 if iter.peek().is_some() {
1206 args.push_str(", ");
1207 }
1208 }
1209
1210 args
1211 };
1212
1213 let abort = if context.abort_on_error { "!" } else { "" };
1214
1215 let mut notes = vec![];
1216
1217 let call = format!("{}{abort}({args})", context.function_ident);
1218
1219 notes.append(&mut Note::solution(
1220 "ensuring an appropriate type at runtime",
1221 vec![format!("{argument} = {guard}"), call.clone()],
1222 ));
1223
1224 if let Some(coerce) = coerce {
1225 notes.append(&mut Note::solution(
1226 "coercing to an appropriate type and specifying a default value as a fallback in case coercion fails",
1227 vec![format!("{argument} = {coerce}"), call],
1228 ));
1229 }
1230
1231 notes.push(Note::SeeErrorDocs);
1232
1233 notes
1234 }
1235
1236 Compilation { error, .. } => error.notes(),
1237
1238 MissingClosure { example, .. } if example.is_some() => {
1239 let code = example.unwrap().source.to_owned();
1240 vec![Note::Example(code)]
1241 }
1242
1243 _ => vec![],
1244 }
1245 }
1246}
1247
1248#[cfg(test)]
1249mod tests {
1250 use crate::compiler::{Category, FunctionExpression, value::kind};
1251
1252 use super::*;
1253
1254 #[derive(Clone, Debug)]
1255 struct Fn;
1256
1257 impl FunctionExpression for Fn {
1258 fn resolve(&self, _ctx: &mut Context) -> Resolved {
1259 todo!()
1260 }
1261
1262 fn type_def(&self, _state: &TypeState) -> TypeDef {
1263 TypeDef::null().infallible()
1264 }
1265 }
1266
1267 #[derive(Debug)]
1268 struct TestFn;
1269
1270 impl Function for TestFn {
1271 fn identifier(&self) -> &'static str {
1272 "test"
1273 }
1274
1275 fn usage(&self) -> &'static str {
1276 "Test function"
1277 }
1278
1279 fn category(&self) -> &'static str {
1280 Category::Debug.as_ref()
1281 }
1282
1283 fn return_kind(&self) -> u16 {
1284 kind::NULL
1285 }
1286
1287 fn examples(&self) -> &'static [crate::compiler::function::Example] {
1288 &[]
1289 }
1290
1291 fn parameters(&self) -> &'static [Parameter] {
1292 const PARAMETERS: &[Parameter] = &[
1293 Parameter::optional("one", kind::INTEGER, "one"),
1294 Parameter::optional("two", kind::INTEGER, "two"),
1295 Parameter::optional("three", kind::INTEGER, "three"),
1296 ];
1297
1298 PARAMETERS
1299 }
1300
1301 fn compile(
1302 &self,
1303 _state: &TypeState,
1304 _ctx: &mut FunctionCompileContext,
1305 _arguments: ArgumentList,
1306 ) -> crate::compiler::function::Compiled {
1307 Ok(Fn.as_expr())
1308 }
1309 }
1310
1311 fn create_node<T>(inner: T) -> Node<T> {
1312 Node::new(Span::new(0, 0), inner)
1313 }
1314
1315 fn create_argument(ident: Option<&str>, value: i64) -> FunctionArgument {
1316 use crate::compiler::expression::{Expr, Literal};
1317
1318 FunctionArgument::new(
1319 ident.map(|ident| create_node(Ident::new(ident))),
1320 create_node(Expr::Literal(Literal::Integer(value))),
1321 )
1322 }
1323
1324 fn create_function_call(arguments: Vec<Node<FunctionArgument>>) -> FunctionCall {
1325 let mut state = TypeState::default();
1326 let original_state = state.clone();
1327 let mut config = CompileConfig::default();
1328 Builder::new(
1329 Span::new(0, 0),
1330 Node::new(Span::new(0, 0), Ident::new("test")),
1331 false,
1332 arguments,
1333 &[Box::new(TestFn) as _],
1334 &original_state,
1335 &mut state,
1336 None,
1337 )
1338 .unwrap()
1339 .compile(
1340 &original_state,
1341 &mut state,
1342 None,
1343 LocalEnv::default(),
1344 &mut config,
1345 )
1346 .unwrap()
1347 .function_call
1348 }
1349
1350 #[test]
1351 fn resolve_arguments_simple() {
1352 let call = create_function_call(vec![
1353 create_node(create_argument(None, 1)),
1354 create_node(create_argument(None, 2)),
1355 create_node(create_argument(None, 3)),
1356 ]);
1357
1358 let params = call.resolve_arguments(&TestFn);
1359 let expected: Vec<(&'static str, Option<FunctionArgument>)> = vec![
1360 ("one", Some(create_argument(None, 1))),
1361 ("two", Some(create_argument(None, 2))),
1362 ("three", Some(create_argument(None, 3))),
1363 ];
1364
1365 assert_eq!(Ok(expected), params);
1366 }
1367
1368 #[test]
1369 fn resolve_arguments_named() {
1370 let call = create_function_call(vec![
1371 create_node(create_argument(Some("one"), 1)),
1372 create_node(create_argument(Some("two"), 2)),
1373 create_node(create_argument(Some("three"), 3)),
1374 ]);
1375
1376 let params = call.resolve_arguments(&TestFn);
1377 let expected: Vec<(&'static str, Option<FunctionArgument>)> = vec![
1378 ("one", Some(create_argument(Some("one"), 1))),
1379 ("two", Some(create_argument(Some("two"), 2))),
1380 ("three", Some(create_argument(Some("three"), 3))),
1381 ];
1382
1383 assert_eq!(Ok(expected), params);
1384 }
1385
1386 #[test]
1387 fn resolve_arguments_named_unordered() {
1388 let call = create_function_call(vec![
1389 create_node(create_argument(Some("three"), 3)),
1390 create_node(create_argument(Some("two"), 2)),
1391 create_node(create_argument(Some("one"), 1)),
1392 ]);
1393
1394 let params = call.resolve_arguments(&TestFn);
1395 let expected: Vec<(&'static str, Option<FunctionArgument>)> = vec![
1396 ("one", Some(create_argument(Some("one"), 1))),
1397 ("two", Some(create_argument(Some("two"), 2))),
1398 ("three", Some(create_argument(Some("three"), 3))),
1399 ];
1400
1401 assert_eq!(Ok(expected), params);
1402 }
1403
1404 #[test]
1405 fn resolve_arguments_unnamed_unordered_one() {
1406 let call = create_function_call(vec![
1407 create_node(create_argument(Some("three"), 3)),
1408 create_node(create_argument(None, 2)),
1409 create_node(create_argument(Some("one"), 1)),
1410 ]);
1411
1412 let params = call.resolve_arguments(&TestFn);
1413 let expected: Vec<(&'static str, Option<FunctionArgument>)> = vec![
1414 ("one", Some(create_argument(Some("one"), 1))),
1415 ("two", Some(create_argument(None, 2))),
1416 ("three", Some(create_argument(Some("three"), 3))),
1417 ];
1418
1419 assert_eq!(Ok(expected), params);
1420 }
1421
1422 #[test]
1423 fn resolve_arguments_unnamed_unordered_two() {
1424 let call = create_function_call(vec![
1425 create_node(create_argument(Some("three"), 3)),
1426 create_node(create_argument(None, 1)),
1427 create_node(create_argument(None, 2)),
1428 ]);
1429
1430 let params = call.resolve_arguments(&TestFn);
1431 let expected: Vec<(&'static str, Option<FunctionArgument>)> = vec![
1432 ("one", Some(create_argument(None, 1))),
1433 ("two", Some(create_argument(None, 2))),
1434 ("three", Some(create_argument(Some("three"), 3))),
1435 ];
1436
1437 assert_eq!(Ok(expected), params);
1438 }
1439}