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

Configure Feed

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

make constant records more fault tolerant

author
Giacomo Cavalieri
committer
Louis Pilfold
date (May 21, 2026, 12:59 PM +0100) commit 4dc957a9 parent fc11a21e change-id kxotypnv
+110 -21
+56 -21
compiler-core/src/type_/expression.rs
··· 4423 4423 ), 4424 4424 }; 4425 4425 4426 - // If there's an error reordering the fields, or there's labelled 4427 - // arguments with no field map, then we return an invalid expression. 4426 + // If there's an error with the constructor being passed the wrong 4427 + // number of arguments we keep track of it, but don't immediately return 4428 + // an invalid node! 4429 + // We still want to analyse the passed arguments. 4430 + let mut labelled_arity_error = false; 4428 4431 if let Err(error) = result { 4432 + if let Error::IncorrectArity { .. } = error { 4433 + labelled_arity_error = true; 4434 + } 4429 4435 self.problems.error(error); 4430 - return self.new_invalid_constant(location); 4431 4436 } 4432 4437 4433 - let (mut arguments_types, return_type) = 4434 - match match_fun_type(constructor.type_.clone(), arguments.len(), self.environment) { 4435 - Ok((arguments_types, return_type)) => (arguments_types, return_type), 4436 - Err(error) => { 4437 - self.problems.error(convert_not_fun_error( 4438 - error, 4439 - module.map_or(location, |(_, module_location)| { 4440 - module_location.merge(&location) 4441 - }), 4442 - location, 4443 - CallKind::Function, 4444 - )); 4445 - return self.new_invalid_constant(location); 4446 - } 4447 - }; 4438 + let called_location = module.as_ref().map_or(location, |(_, module_location)| { 4439 + module_location.merge(&location) 4440 + }); 4441 + 4442 + let FunctionTypeMatch { 4443 + mut expected_arguments, 4444 + expected_return, 4445 + missing_arguments: _, 4446 + ignored_labelled_arguments, 4447 + } = self.fault_tolerant_match_function_type( 4448 + labelled_arity_error, 4449 + CallKind::Function, 4450 + constructor.type_.clone(), 4451 + called_location, 4452 + location, 4453 + &arguments, 4454 + ); 4448 4455 4449 - let arguments = arguments_types 4456 + let mut typed_arguments = expected_arguments 4450 4457 .iter_mut() 4451 4458 .zip(arguments) 4452 4459 .map(|(type_, argument): (&mut Arc<Type>, _)| { ··· 4473 4480 }) 4474 4481 .collect_vec(); 4475 4482 4483 + // Now if we had supplied less arguments than required and some of those 4484 + // were labelled, in the previous step we would have got rid of those 4485 + // _before_ typing. 4486 + // That is because we can only reliably type positional arguments in 4487 + // case of mismatched arity, as labelled arguments cannot be reordered. 4488 + // 4489 + // So now what we want to do is add back those labelled arguments to 4490 + // make sure the LS can still see that those were explicitly supplied. 4491 + for IgnoredLabelledArgument { 4492 + label, 4493 + location, 4494 + implicit, 4495 + } in ignored_labelled_arguments 4496 + { 4497 + typed_arguments.push(CallArg { 4498 + label, 4499 + value: TypedConstant::Invalid { 4500 + location, 4501 + type_: self.new_unbound_var(), 4502 + extra_information: None, 4503 + }, 4504 + implicit, 4505 + location, 4506 + }) 4507 + } 4508 + 4476 4509 Constant::Record { 4477 4510 module, 4478 4511 location, 4479 4512 name, 4480 - arguments, 4481 - type_: return_type, 4513 + arguments: typed_arguments, 4514 + type_: expected_return, 4482 4515 field_map: match field_map { 4483 4516 Some(field_map) => Inferred::Known(field_map), 4484 4517 None => Inferred::Unknown, ··· 5516 5549 } 5517 5550 } 5518 5551 5552 + #[derive(Debug)] 5519 5553 struct FunctionTypeMatch { 5520 5554 /// The types the arguments of the function are expected to have. 5521 5555 expected_arguments: Vec<Arc<Type>>, ··· 5527 5561 ignored_labelled_arguments: Vec<IgnoredLabelledArgument>, 5528 5562 } 5529 5563 5564 + #[derive(Debug)] 5530 5565 struct IgnoredLabelledArgument { 5531 5566 label: Option<EcoString>, 5532 5567 location: SrcSpan,
+13
compiler-core/src/type_/tests/functions.rs
··· 572 572 "# 573 573 ); 574 574 } 575 + 576 + #[test] 577 + fn constant_record_incorrect_arg_types_fault_tolerance() { 578 + assert_module_error!( 579 + r#" 580 + pub type Wibble { 581 + Wibble(Int, Int) 582 + } 583 + 584 + pub const wibble = Wibble(1.0, 1.0) 585 + "# 586 + ); 587 + }
+41
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__functions__constant_record_incorrect_arg_types_fault_tolerance.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/functions.rs 3 + expression: "\npub type Wibble {\n Wibble(Int, Int)\n}\n\npub const wibble = Wibble(1.0, 1.0)\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub type Wibble { 8 + Wibble(Int, Int) 9 + } 10 + 11 + pub const wibble = Wibble(1.0, 1.0) 12 + 13 + 14 + ----- ERROR 15 + error: Type mismatch 16 + ┌─ /src/one/two.gleam:6:27 17 + 18 + 6 │ pub const wibble = Wibble(1.0, 1.0) 19 + │ ^^^ 20 + 21 + Expected type: 22 + 23 + Int 24 + 25 + Found type: 26 + 27 + Float 28 + 29 + error: Type mismatch 30 + ┌─ /src/one/two.gleam:6:32 31 + 32 + 6 │ pub const wibble = Wibble(1.0, 1.0) 33 + │ ^^^ 34 + 35 + Expected type: 36 + 37 + Int 38 + 39 + Found type: 40 + 41 + Float