Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

refactor deeply nested branch into its own function

author
Giacomo Cavalieri
committer
Louis Pilfold
date (May 21, 2026, 12:59 PM +0100) commit fc11a21e parent 761e961e change-id vlpvtzrx
+133 -56
+133 -56
compiler-core/src/type_/expression.rs
··· 4810 4810 self.problems.error(error); 4811 4811 } 4812 4812 4813 - let mut missing_arguments = 0; 4814 - let mut ignored_labelled_arguments = vec![]; 4815 4813 // Extract the type of the fun, ensuring it actually is a function 4816 - let (mut arguments_types, return_type) = 4817 - match match_fun_type(fun.type_(), arguments.len(), self.environment) { 4818 - Ok(function) => function, 4819 - Err(error) => { 4820 - let converted_error = 4821 - convert_not_fun_error(error.clone(), fun.location(), location, kind); 4822 - match error { 4823 - // If the function was valid but had the wrong number of arguments passed. 4824 - // Then we keep the error but still want to continue analysing the arguments that were passed. 4825 - MatchFunTypeError::IncorrectArity { 4826 - arguments: arg_types, 4827 - return_type, 4828 - expected, 4829 - given, 4830 - .. 4831 - } => { 4832 - missing_arguments = expected.saturating_sub(given); 4833 - // If the function has labels then arity issues will already 4834 - // be handled by the field map so we can ignore them here. 4835 - if !labelled_arity_error { 4836 - self.problems.error(converted_error); 4837 - (arg_types, return_type) 4838 - } else { 4839 - // Since arity errors with labels cause incorrect 4840 - // ordering, we can't type check the labelled arguments here. 4841 - let first_labelled_arg = 4842 - arguments.iter().position(|arg| arg.label.is_some()); 4843 - ignored_labelled_arguments = arguments 4844 - .iter() 4845 - .skip_while(|argument| argument.label.is_none()) 4846 - .map(|argument| { 4847 - ( 4848 - argument.label.clone(), 4849 - argument.location, 4850 - argument.implicit, 4851 - ) 4852 - }) 4853 - .collect_vec(); 4854 - let arguments_to_keep = 4855 - first_labelled_arg.unwrap_or(arguments.len()); 4856 - ( 4857 - arg_types.iter().take(arguments_to_keep).cloned().collect(), 4858 - return_type, 4859 - ) 4860 - } 4861 - } 4862 - MatchFunTypeError::NotFn { .. } => { 4863 - self.problems.error(converted_error); 4864 - (vec![], self.new_unbound_var()) 4865 - } 4866 - } 4867 - } 4868 - }; 4814 + let FunctionTypeMatch { 4815 + expected_arguments: mut arguments_types, 4816 + expected_return: return_type, 4817 + missing_arguments, 4818 + ignored_labelled_arguments, 4819 + } = self.fault_tolerant_match_function_type( 4820 + labelled_arity_error, 4821 + kind, 4822 + fun.type_(), 4823 + fun.location(), 4824 + location, 4825 + &arguments, 4826 + ); 4869 4827 4870 4828 // When typing the function's arguments we don't care if the previous 4871 4829 // expression panics or not because we want to provide a specialised ··· 4971 4929 // 4972 4930 // So now what we want to do is add back those labelled arguments to 4973 4931 // make sure the LS can still see that those were explicitly supplied. 4974 - for (label, location, implicit) in ignored_labelled_arguments { 4932 + for IgnoredLabelledArgument { 4933 + label, 4934 + location, 4935 + implicit, 4936 + } in ignored_labelled_arguments 4937 + { 4975 4938 typed_arguments.push(CallArg { 4976 4939 label, 4977 4940 value: TypedExpr::Invalid { ··· 5454 5417 | Constant::Invalid { .. } => (), 5455 5418 } 5456 5419 } 5420 + 5421 + fn fault_tolerant_match_function_type<A>( 5422 + &mut self, 5423 + has_labelled_arity_error: bool, 5424 + call_kind: CallKind, 5425 + constructor_type: Arc<Type>, 5426 + // The span of the called element 5427 + called_location: SrcSpan, 5428 + // The full span of the function call 5429 + full_location: SrcSpan, 5430 + arguments: &[CallArg<A>], 5431 + ) -> FunctionTypeMatch { 5432 + // We start by matching the function type. If there's no error we're good 5433 + // to go, we can immediately return the inferred types. 5434 + let result = match_fun_type(constructor_type, arguments.len(), self.environment); 5435 + let error = match result { 5436 + Err(error) => error, 5437 + Ok((expected_arguments, expected_return)) => { 5438 + return FunctionTypeMatch { 5439 + expected_arguments, 5440 + expected_return, 5441 + missing_arguments: 0, 5442 + ignored_labelled_arguments: vec![], 5443 + }; 5444 + } 5445 + }; 5446 + 5447 + let converted_error = 5448 + convert_not_fun_error(error.clone(), called_location, full_location, call_kind); 5449 + 5450 + match error { 5451 + // If the error is caused by the called thing not being a function 5452 + // then there isn't much to do, there's no further expectation on 5453 + // the function types. 5454 + MatchFunTypeError::NotFn { .. } => { 5455 + self.problems.error(converted_error); 5456 + FunctionTypeMatch { 5457 + expected_arguments: vec![], 5458 + expected_return: self.new_unbound_var(), 5459 + missing_arguments: 0, 5460 + ignored_labelled_arguments: vec![], 5461 + } 5462 + } 5463 + 5464 + // If the function was valid but had the wrong number of arguments 5465 + // passed that's when we want to try and recover! 5466 + // We will have to continue analysing the arguments that were 5467 + // passed. 5468 + MatchFunTypeError::IncorrectArity { 5469 + arguments: arguments_types, 5470 + return_type, 5471 + expected, 5472 + given, 5473 + .. 5474 + } => { 5475 + let missing_arguments = expected.saturating_sub(given); 5476 + 5477 + // If the function has labels then arity issues will already 5478 + // be handled by the field map so we can ignore them here. 5479 + if !has_labelled_arity_error { 5480 + self.problems.error(converted_error); 5481 + return FunctionTypeMatch { 5482 + expected_arguments: arguments_types, 5483 + expected_return: return_type, 5484 + missing_arguments, 5485 + ignored_labelled_arguments: vec![], 5486 + }; 5487 + } 5488 + 5489 + // Since arity errors with labels cause incorrect ordering, we 5490 + // can't type check the labelled arguments here. 5491 + let first_labelled_arg = arguments.iter().position(|arg| arg.label.is_some()); 5492 + let arguments_to_keep = first_labelled_arg.unwrap_or(arguments.len()); 5493 + let kept_arguments = arguments_types 5494 + .iter() 5495 + .take(arguments_to_keep) 5496 + .cloned() 5497 + .collect(); 5498 + let ignored_labelled_arguments = arguments 5499 + .iter() 5500 + .skip_while(|argument| argument.label.is_none()) 5501 + .map(|argument| IgnoredLabelledArgument { 5502 + label: argument.label.clone(), 5503 + location: argument.location(), 5504 + implicit: argument.implicit, 5505 + }) 5506 + .collect_vec(); 5507 + 5508 + FunctionTypeMatch { 5509 + expected_arguments: kept_arguments, 5510 + expected_return: return_type, 5511 + missing_arguments, 5512 + ignored_labelled_arguments, 5513 + } 5514 + } 5515 + } 5516 + } 5517 + } 5518 + 5519 + struct FunctionTypeMatch { 5520 + /// The types the arguments of the function are expected to have. 5521 + expected_arguments: Vec<Arc<Type>>, 5522 + /// The return type the function is expected to have. 5523 + expected_return: Arc<Type>, 5524 + /// How many arguments are missing from the function call. 5525 + missing_arguments: usize, 5526 + /// A list of the labelled arguments that were not provided to the function call. 5527 + ignored_labelled_arguments: Vec<IgnoredLabelledArgument>, 5528 + } 5529 + 5530 + struct IgnoredLabelledArgument { 5531 + label: Option<EcoString>, 5532 + location: SrcSpan, 5533 + implicit: Option<ImplicitCallArgOrigin>, 5457 5534 } 5458 5535 5459 5536 /// Given a constants, this will change its type into the given one, turning