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

Configure Feed

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

gleam / compiler-core / src / analyse.rs
66 kB 1900 lines
1mod imports; 2pub(crate) mod name; 3 4#[cfg(test)] 5mod tests; 6 7use crate::{ 8 GLEAM_CORE_PACKAGE_NAME, 9 ast::{ 10 self, Arg, BitArrayOption, CustomType, Definition, DefinitionLocation, Function, 11 GroupedStatements, Import, ModuleConstant, Publicity, RecordConstructor, 12 RecordConstructorArg, SrcSpan, Statement, TypeAlias, TypeAst, TypeAstConstructor, 13 TypeAstFn, TypeAstHole, TypeAstTuple, TypeAstVar, TypedDefinition, TypedExpr, 14 TypedFunction, TypedModule, UntypedArg, UntypedCustomType, UntypedFunction, UntypedImport, 15 UntypedModule, UntypedModuleConstant, UntypedStatement, UntypedTypeAlias, 16 }, 17 build::{Origin, Outcome, Target}, 18 call_graph::{CallGraphNode, into_dependency_order}, 19 config::PackageConfig, 20 dep_tree, 21 line_numbers::LineNumbers, 22 parse::SpannedString, 23 type_::{ 24 self, AccessorsMap, Deprecation, ModuleInterface, PatternConstructor, RecordAccessor, Type, 25 TypeConstructor, TypeValueConstructor, TypeValueConstructorField, TypeVariantConstructors, 26 ValueConstructor, ValueConstructorVariant, Warning, 27 environment::*, 28 error::{Error, FeatureKind, MissingAnnotation, Named, Problems, convert_unify_error}, 29 expression::{ExprTyper, FunctionDefinition, Implementations}, 30 fields::{FieldMap, FieldMapBuilder}, 31 hydrator::Hydrator, 32 prelude::*, 33 }, 34 uid::UniqueIdGenerator, 35 warning::TypeWarningEmitter, 36}; 37use camino::Utf8PathBuf; 38use ecow::EcoString; 39use hexpm::version::Version; 40use itertools::Itertools; 41use name::{check_argument_names, check_name_case}; 42use std::{ 43 collections::HashMap, 44 ops::Deref, 45 sync::{Arc, OnceLock}, 46}; 47use vec1::Vec1; 48 49use self::imports::Importer; 50 51#[derive(Debug, Clone, PartialEq, Eq)] 52pub enum Inferred<T> { 53 Known(T), 54 Unknown, 55} 56 57impl<T> Inferred<T> { 58 pub fn expect(self, message: &str) -> T { 59 match self { 60 Inferred::Known(value) => Some(value), 61 Inferred::Unknown => None, 62 } 63 .expect(message) 64 } 65 66 pub fn expect_ref(&self, message: &str) -> &T { 67 match self { 68 Inferred::Known(value) => Some(value), 69 Inferred::Unknown => None, 70 } 71 .expect(message) 72 } 73} 74 75impl Inferred<PatternConstructor> { 76 pub fn definition_location(&self) -> Option<DefinitionLocation> { 77 match self { 78 Inferred::Known(value) => value.definition_location(), 79 Inferred::Unknown => None, 80 } 81 } 82 83 pub fn get_documentation(&self) -> Option<&str> { 84 match self { 85 Inferred::Known(value) => value.get_documentation(), 86 Inferred::Unknown => None, 87 } 88 } 89} 90 91/// How the compiler should treat target support. 92#[derive(Clone, Copy, Debug, PartialEq, Eq)] 93pub enum TargetSupport { 94 /// Target support is enfored, meaning if a function is found to not have an implementation for 95 /// the current target then an error is emitted and compilation halts. 96 /// 97 /// This is used when compiling the root package, with the exception of when using 98 /// `gleam run --module $module` to run a module from a dependency package, in which case we do 99 /// not want to error as the root package code isn't going to be run. 100 Enforced, 101 /// Target support is enfored, meaning if a function is found to not have an implementation for 102 /// the current target it will continue onwards and not generate any code for this function. 103 /// 104 /// This is used when compiling dependencies. 105 NotEnforced, 106} 107 108impl TargetSupport { 109 /// Returns `true` if the target support is [`Enforced`]. 110 /// 111 /// [`Enforced`]: TargetSupport::Enforced 112 #[must_use] 113 pub fn is_enforced(&self) -> bool { 114 match self { 115 Self::Enforced => true, 116 Self::NotEnforced => false, 117 } 118 } 119} 120 121impl<T> From<Error> for Outcome<T, Vec1<Error>> { 122 fn from(error: Error) -> Self { 123 Outcome::TotalFailure(Vec1::new(error)) 124 } 125} 126 127/// This struct is used to take the data required for analysis. It is used to 128/// construct the private ModuleAnalyzer which has this data plus any 129/// internal state. 130/// 131#[derive(Debug)] 132pub struct ModuleAnalyzerConstructor<'a, A> { 133 pub target: Target, 134 pub ids: &'a UniqueIdGenerator, 135 pub origin: Origin, 136 pub importable_modules: &'a im::HashMap<EcoString, ModuleInterface>, 137 pub warnings: &'a TypeWarningEmitter, 138 pub direct_dependencies: &'a HashMap<EcoString, A>, 139 pub target_support: TargetSupport, 140 pub package_config: &'a PackageConfig, 141} 142 143impl<A> ModuleAnalyzerConstructor<'_, A> { 144 /// Crawl the AST, annotating each node with the inferred type or 145 /// returning an error. 146 /// 147 pub fn infer_module( 148 self, 149 module: UntypedModule, 150 line_numbers: LineNumbers, 151 src_path: Utf8PathBuf, 152 ) -> Outcome<TypedModule, Vec1<Error>> { 153 ModuleAnalyzer { 154 target: self.target, 155 ids: self.ids, 156 origin: self.origin, 157 importable_modules: self.importable_modules, 158 warnings: self.warnings, 159 direct_dependencies: self.direct_dependencies, 160 target_support: self.target_support, 161 package_config: self.package_config, 162 line_numbers, 163 src_path, 164 problems: Problems::new(), 165 value_names: HashMap::with_capacity(module.definitions.len()), 166 hydrators: HashMap::with_capacity(module.definitions.len()), 167 module_name: module.name.clone(), 168 minimum_required_version: Version::new(0, 1, 0), 169 } 170 .infer_module(module) 171 } 172} 173 174struct ModuleAnalyzer<'a, A> { 175 target: Target, 176 ids: &'a UniqueIdGenerator, 177 origin: Origin, 178 importable_modules: &'a im::HashMap<EcoString, ModuleInterface>, 179 warnings: &'a TypeWarningEmitter, 180 direct_dependencies: &'a HashMap<EcoString, A>, 181 target_support: TargetSupport, 182 package_config: &'a PackageConfig, 183 line_numbers: LineNumbers, 184 src_path: Utf8PathBuf, 185 problems: Problems, 186 value_names: HashMap<EcoString, SrcSpan>, 187 hydrators: HashMap<EcoString, Hydrator>, 188 module_name: EcoString, 189 190 /// The minimum Gleam version required to compile the analysed module. 191 minimum_required_version: Version, 192} 193 194impl<'a, A> ModuleAnalyzer<'a, A> { 195 pub fn infer_module(mut self, mut module: UntypedModule) -> Outcome<TypedModule, Vec1<Error>> { 196 if let Err(error) = validate_module_name(&self.module_name) { 197 return self.all_errors(error); 198 } 199 200 let documentation = std::mem::take(&mut module.documentation); 201 let env = Environment::new( 202 self.ids.clone(), 203 self.package_config.name.clone(), 204 self.package_config.gleam_version.clone(), 205 self.module_name.clone(), 206 self.target, 207 self.importable_modules, 208 self.target_support, 209 ); 210 211 let statements = GroupedStatements::new(module.into_iter_statements(self.target)); 212 let statements_count = statements.len(); 213 214 // Register any modules, types, and values being imported 215 // We process imports first so that anything imported can be referenced 216 // anywhere in the module. 217 let mut env = Importer::run(self.origin, env, &statements.imports, &mut self.problems); 218 219 // Register types so they can be used in constructors and functions 220 // earlier in the module. 221 for t in &statements.custom_types { 222 if let Err(error) = self.register_types_from_custom_type(t, &mut env) { 223 return self.all_errors(error); 224 } 225 } 226 227 let sorted_aliases = match sorted_type_aliases(&statements.type_aliases) { 228 Ok(it) => it, 229 Err(error) => return self.all_errors(error), 230 }; 231 for t in sorted_aliases { 232 self.register_type_alias(t, &mut env); 233 } 234 235 for f in &statements.functions { 236 if let Err(error) = self.register_value_from_function(f, &mut env) { 237 return self.all_errors(error); 238 } 239 } 240 241 // Infer the types of each statement in the module 242 let mut typed_statements = Vec::with_capacity(statements_count); 243 for i in statements.imports { 244 optionally_push(&mut typed_statements, self.analyse_import(i, &env)); 245 } 246 for t in statements.custom_types { 247 optionally_push(&mut typed_statements, self.analyse_custom_type(t, &mut env)); 248 } 249 for t in statements.type_aliases { 250 typed_statements.push(analyse_type_alias(t, &mut env)); 251 } 252 253 // Sort functions and constants into dependency order for inference. Definitions that do 254 // not depend on other definitions are inferred first, then ones that depend 255 // on those, etc. 256 let definition_groups = 257 match into_dependency_order(statements.functions, statements.constants) { 258 Ok(it) => it, 259 Err(error) => return self.all_errors(error), 260 }; 261 let mut working_group = vec![]; 262 263 for group in definition_groups { 264 // A group may have multiple functions that depend on each other through 265 // mutual recursion. 266 267 for definition in group { 268 let def = match definition { 269 CallGraphNode::Function(f) => self.infer_function(f, &mut env), 270 CallGraphNode::ModuleConstant(c) => self.infer_module_constant(c, &mut env), 271 }; 272 working_group.push(def); 273 } 274 275 // Now that the entire group has been inferred, generalise their types. 276 for inferred in working_group.drain(..) { 277 typed_statements.push(generalise_statement(inferred, &self.module_name, &mut env)); 278 } 279 } 280 281 // Generate warnings for unused items 282 env.convert_unused_to_warnings(&mut self.problems); 283 284 // Remove imported types and values to create the public interface 285 // Private types and values are retained so they can be used in the language 286 // server, but are filtered out when type checking to prevent using private 287 // items. 288 env.module_types 289 .retain(|_, info| info.module == self.module_name); 290 291 // Ensure no exported values have private types in their type signature 292 for value in env.module_values.values() { 293 self.check_for_type_leaks(value) 294 } 295 296 let Environment { 297 module_types: types, 298 module_types_constructors: types_constructors, 299 module_values: values, 300 accessors, 301 names: type_names, 302 .. 303 } = env; 304 305 let is_internal = self 306 .package_config 307 .is_internal_module(self.module_name.as_str()); 308 309 // We sort warnings and errors to ensure they are emitted in a 310 // deterministic order, making them easier to test and debug, and to 311 // make the output predictable. 312 self.problems.sort(); 313 314 let warnings = self.problems.take_warnings(); 315 for warning in &warnings { 316 // TODO: remove this clone 317 self.warnings.emit(warning.clone()); 318 } 319 320 let module = ast::Module { 321 documentation, 322 name: self.module_name.clone(), 323 definitions: typed_statements, 324 type_info: ModuleInterface { 325 name: self.module_name, 326 types, 327 types_value_constructors: types_constructors, 328 values, 329 accessors, 330 origin: self.origin, 331 package: self.package_config.name.clone(), 332 is_internal, 333 line_numbers: self.line_numbers, 334 src_path: self.src_path, 335 warnings, 336 minimum_required_version: self.minimum_required_version, 337 }, 338 names: type_names, 339 }; 340 341 match Vec1::try_from_vec(self.problems.take_errors()) { 342 Err(_) => Outcome::Ok(module), 343 Ok(errors) => Outcome::PartialFailure(module, errors), 344 } 345 } 346 347 fn all_errors<T>(&mut self, error: Error) -> Outcome<T, Vec1<Error>> { 348 Outcome::TotalFailure(Vec1::from_vec_push(self.problems.take_errors(), error)) 349 } 350 351 fn infer_module_constant( 352 &mut self, 353 c: UntypedModuleConstant, 354 environment: &mut Environment<'_>, 355 ) -> TypedDefinition { 356 let ModuleConstant { 357 documentation: doc, 358 location, 359 name, 360 name_location, 361 annotation, 362 publicity, 363 value, 364 deprecation, 365 .. 366 } = c; 367 self.check_name_case(name_location, &name, Named::Constant); 368 369 let definition = FunctionDefinition { 370 has_body: true, 371 has_erlang_external: false, 372 has_javascript_external: false, 373 }; 374 let mut expr_typer = ExprTyper::new(environment, definition, &mut self.problems); 375 let typed_expr = expr_typer.infer_const(&annotation, *value); 376 let type_ = typed_expr.type_(); 377 let implementations = expr_typer.implementations; 378 379 let minimum_required_version = expr_typer.minimum_required_version; 380 if minimum_required_version > self.minimum_required_version { 381 self.minimum_required_version = minimum_required_version; 382 } 383 384 match publicity { 385 Publicity::Private 386 | Publicity::Public 387 | Publicity::Internal { 388 attribute_location: None, 389 } => (), 390 391 Publicity::Internal { 392 attribute_location: Some(location), 393 } => self.track_feature_usage(FeatureKind::InternalAnnotation, location), 394 } 395 396 let variant = ValueConstructor { 397 publicity, 398 deprecation: deprecation.clone(), 399 variant: ValueConstructorVariant::ModuleConstant { 400 documentation: doc.as_ref().map(|(_, doc)| doc.clone()), 401 location, 402 literal: typed_expr.clone(), 403 module: self.module_name.clone(), 404 implementations, 405 }, 406 type_: type_.clone(), 407 }; 408 409 environment.insert_variable( 410 name.clone(), 411 variant.variant.clone(), 412 type_.clone(), 413 publicity, 414 Deprecation::NotDeprecated, 415 ); 416 environment.insert_module_value(name.clone(), variant); 417 418 if publicity.is_private() { 419 environment.init_usage( 420 name.clone(), 421 EntityKind::PrivateConstant, 422 location, 423 &mut self.problems, 424 ); 425 } 426 427 Definition::ModuleConstant(ModuleConstant { 428 documentation: doc, 429 location, 430 name, 431 name_location, 432 annotation, 433 publicity, 434 value: Box::new(typed_expr), 435 type_, 436 deprecation, 437 implementations, 438 }) 439 } 440 441 // TODO: Extract this into a class of its own! Or perhaps it just wants some 442 // helper methods extracted. There's a whole bunch of state in this one 443 // function, and it does a handful of things. 444 fn infer_function( 445 &mut self, 446 f: UntypedFunction, 447 environment: &mut Environment<'_>, 448 ) -> TypedDefinition { 449 let Function { 450 documentation: doc, 451 location, 452 name, 453 publicity, 454 arguments, 455 body, 456 return_annotation, 457 end_position: end_location, 458 deprecation, 459 external_erlang, 460 external_javascript, 461 return_type: (), 462 implementations: _, 463 } = f; 464 let (name_location, name) = name.expect("Function in a definition must be named"); 465 let target = environment.target; 466 let body_location = body.last().location(); 467 let preregistered_fn = environment 468 .get_variable(&name) 469 .expect("Could not find preregistered type for function"); 470 let field_map = preregistered_fn.field_map().cloned(); 471 let preregistered_type = preregistered_fn.type_.clone(); 472 let (prereg_args_types, prereg_return_type) = preregistered_type 473 .fn_types() 474 .expect("Preregistered type for fn was not a fn"); 475 476 // Ensure that folks are not writing inline JavaScript expressions as 477 // the implementation for JS externals. 478 self.assert_valid_javascript_external(&name, external_javascript.as_ref(), location); 479 480 // Find the external implementation for the current target, if one has been given. 481 let external = 482 target_function_implementation(target, &external_erlang, &external_javascript); 483 484 // The function must have at least one implementation somewhere. 485 let has_implementation = self.ensure_function_has_an_implementation( 486 &body, 487 &external_erlang, 488 &external_javascript, 489 location, 490 ); 491 492 if external.is_some() { 493 // There was an external implementation, so type annotations are 494 // mandatory as the Gleam implementation may be absent, and because we 495 // think you should always specify types for external functions for 496 // clarity + to avoid accidental mistakes. 497 self.ensure_annotations_present(&arguments, return_annotation.as_ref(), location); 498 } 499 500 let has_body = !body.first().is_placeholder(); 501 let definition = FunctionDefinition { 502 has_body, 503 has_erlang_external: external_erlang.is_some(), 504 has_javascript_external: external_javascript.is_some(), 505 }; 506 507 let typed_args = arguments 508 .into_iter() 509 .zip(&prereg_args_types) 510 .map(|(a, t)| a.set_type(t.clone())) 511 .collect_vec(); 512 513 // Infer the type using the preregistered args + return types as a starting point 514 let result = environment.in_new_scope(&mut self.problems, |environment, problems| { 515 let mut expr_typer = ExprTyper::new(environment, definition, problems); 516 expr_typer.hydrator = self 517 .hydrators 518 .remove(&name) 519 .expect("Could not find hydrator for fn"); 520 521 let (args, body) = expr_typer.infer_fn_with_known_types( 522 typed_args.clone(), 523 body, 524 Some(prereg_return_type.clone()), 525 )?; 526 let args_types = args.iter().map(|a| a.type_.clone()).collect(); 527 let type_ = fn_(args_types, body.last().type_()); 528 Ok(( 529 type_, 530 body, 531 expr_typer.implementations, 532 expr_typer.minimum_required_version, 533 )) 534 }); 535 536 // If we could not successfully infer the type etc information of the 537 // function then register the error and continue anaylsis using the best 538 // information that we have, so we can still learn about the rest of the 539 // module. 540 let (type_, body, implementations, required_version) = match result { 541 Ok((type_, body, implementations, required_version)) => { 542 (type_, body, implementations, required_version) 543 } 544 Err(error) => { 545 self.problems.error(error); 546 let type_ = preregistered_type.clone(); 547 let body = Vec1::new(Statement::Expression(TypedExpr::Invalid { 548 type_: prereg_return_type.clone(), 549 location: SrcSpan { 550 start: body_location.end, 551 end: body_location.end, 552 }, 553 })); 554 let implementations = Implementations::supporting_all(); 555 (type_, body, implementations, Version::new(1, 0, 0)) 556 } 557 }; 558 559 if required_version > self.minimum_required_version { 560 self.minimum_required_version = required_version; 561 } 562 563 match publicity { 564 Publicity::Private 565 | Publicity::Public 566 | Publicity::Internal { 567 attribute_location: None, 568 } => (), 569 570 Publicity::Internal { 571 attribute_location: Some(location), 572 } => self.track_feature_usage(FeatureKind::InternalAnnotation, location), 573 } 574 575 if let Some((module, _, location)) = &external_javascript { 576 if module.contains('@') { 577 self.track_feature_usage(FeatureKind::AtInJavascriptModules, *location) 578 } 579 } 580 581 // Assert that the inferred type matches the type of any recursive call 582 if let Err(error) = unify(preregistered_type.clone(), type_) { 583 self.problems.error(convert_unify_error(error, location)); 584 } 585 586 // Ensure that the current target has an implementation for the function. 587 // This is done at the expression level while inferring the function body, but we do it again 588 // here as externally implemented functions may not have a Gleam body. 589 // 590 // We don't emit this error if there is no implementation, as this would 591 // have already emitted an error above. 592 if has_implementation 593 && publicity.is_importable() 594 && environment.target_support.is_enforced() 595 && !implementations.supports(target) 596 // We don't emit this error if there is a body 597 // since this would be caught at the statement level 598 && !has_body 599 { 600 self.problems.error(Error::UnsupportedPublicFunctionTarget { 601 name: name.clone(), 602 target, 603 location, 604 }); 605 } 606 607 let variant = ValueConstructorVariant::ModuleFn { 608 documentation: doc.as_ref().map(|(_, doc)| doc.clone()), 609 name: name.clone(), 610 external_erlang: external_erlang 611 .as_ref() 612 .map(|(m, f, _)| (m.clone(), f.clone())), 613 external_javascript: external_javascript 614 .as_ref() 615 .map(|(m, f, _)| (m.clone(), f.clone())), 616 field_map, 617 module: environment.current_module.clone(), 618 arity: typed_args.len(), 619 location, 620 implementations, 621 }; 622 623 environment.insert_variable( 624 name.clone(), 625 variant, 626 preregistered_type.clone(), 627 publicity, 628 deprecation.clone(), 629 ); 630 631 Definition::Function(Function { 632 documentation: doc, 633 location, 634 name: Some((name_location, name)), 635 publicity, 636 deprecation, 637 arguments: typed_args, 638 end_position: end_location, 639 return_annotation, 640 return_type: preregistered_type 641 .return_type() 642 .expect("Could not find return type for fn"), 643 body, 644 external_erlang, 645 external_javascript, 646 implementations, 647 }) 648 } 649 650 fn assert_valid_javascript_external( 651 &mut self, 652 function_name: &EcoString, 653 external_javascript: Option<&(EcoString, EcoString, SrcSpan)>, 654 location: SrcSpan, 655 ) { 656 use regex::Regex; 657 658 static MODULE: OnceLock<Regex> = OnceLock::new(); 659 static FUNCTION: OnceLock<Regex> = OnceLock::new(); 660 661 let (module, function) = match external_javascript { 662 None => return, 663 Some((module, function, _location)) => (module, function), 664 }; 665 if !MODULE 666 .get_or_init(|| Regex::new("^[@a-zA-Z0-9\\./:_-]+$").expect("regex")) 667 .is_match(module) 668 { 669 self.problems.error(Error::InvalidExternalJavascriptModule { 670 location, 671 module: module.clone(), 672 name: function_name.clone(), 673 }); 674 } 675 if !FUNCTION 676 .get_or_init(|| Regex::new("^[a-zA-Z_][a-zA-Z0-9_]*$").expect("regex")) 677 .is_match(function) 678 { 679 self.problems 680 .error(Error::InvalidExternalJavascriptFunction { 681 location, 682 function: function.clone(), 683 name: function_name.clone(), 684 }); 685 } 686 } 687 688 fn ensure_annotations_present( 689 &mut self, 690 arguments: &[UntypedArg], 691 return_annotation: Option<&TypeAst>, 692 location: SrcSpan, 693 ) { 694 for arg in arguments { 695 if arg.annotation.is_none() { 696 self.problems.error(Error::ExternalMissingAnnotation { 697 location: arg.location, 698 kind: MissingAnnotation::Parameter, 699 }); 700 } 701 } 702 if return_annotation.is_none() { 703 self.problems.error(Error::ExternalMissingAnnotation { 704 location, 705 kind: MissingAnnotation::Return, 706 }); 707 } 708 } 709 710 fn ensure_function_has_an_implementation( 711 &mut self, 712 body: &Vec1<UntypedStatement>, 713 external_erlang: &Option<(EcoString, EcoString, SrcSpan)>, 714 external_javascript: &Option<(EcoString, EcoString, SrcSpan)>, 715 location: SrcSpan, 716 ) -> bool { 717 match (external_erlang, external_javascript) { 718 (None, None) if body.first().is_placeholder() => { 719 self.problems.error(Error::NoImplementation { location }); 720 false 721 } 722 _ => true, 723 } 724 } 725 726 fn analyse_import( 727 &mut self, 728 i: UntypedImport, 729 environment: &Environment<'_>, 730 ) -> Option<TypedDefinition> { 731 let Import { 732 documentation, 733 location, 734 module, 735 as_name, 736 unqualified_values, 737 unqualified_types, 738 .. 739 } = i; 740 // Find imported module 741 let Some(module_info) = environment.importable_modules.get(&module) else { 742 // Here the module being imported doesn't exist. We don't emit an 743 // error here as the `Importer` that was run earlier will have 744 // already emitted an error for this. 745 return None; 746 }; 747 748 // Modules should belong to a package that is a direct dependency of the 749 // current package to be imported. 750 // Upgrade this to an error in future. 751 if module_info.package != GLEAM_CORE_PACKAGE_NAME 752 && module_info.package != self.package_config.name 753 && !self.direct_dependencies.contains_key(&module_info.package) 754 { 755 self.warnings.emit(Warning::TransitiveDependencyImported { 756 location, 757 module: module_info.name.clone(), 758 package: module_info.package.clone(), 759 }) 760 } 761 762 Some(Definition::Import(Import { 763 documentation, 764 location, 765 module, 766 as_name, 767 unqualified_values, 768 unqualified_types, 769 package: module_info.package.clone(), 770 })) 771 } 772 773 fn analyse_custom_type( 774 &mut self, 775 t: UntypedCustomType, 776 environment: &mut Environment<'_>, 777 ) -> Option<TypedDefinition> { 778 match self.do_analyse_custom_type(t, environment) { 779 Ok(t) => Some(t), 780 Err(error) => { 781 self.problems.error(error); 782 None 783 } 784 } 785 } 786 787 // TODO: split this into a new class. 788 fn do_analyse_custom_type( 789 &mut self, 790 t: UntypedCustomType, 791 environment: &mut Environment<'_>, 792 ) -> Result<TypedDefinition, Error> { 793 self.register_values_from_custom_type( 794 &t, 795 environment, 796 &t.parameters.iter().map(|(_, name)| name).collect_vec(), 797 )?; 798 799 let CustomType { 800 documentation: doc, 801 location, 802 end_position, 803 publicity, 804 opaque, 805 name, 806 name_location, 807 parameters, 808 constructors, 809 deprecation, 810 .. 811 } = t; 812 813 match publicity { 814 Publicity::Private 815 | Publicity::Public 816 | Publicity::Internal { 817 attribute_location: None, 818 } => (), 819 820 Publicity::Internal { 821 attribute_location: Some(location), 822 } => self.track_feature_usage(FeatureKind::InternalAnnotation, location), 823 } 824 825 let constructors: Vec<RecordConstructor<Arc<Type>>> = constructors 826 .into_iter() 827 .map( 828 |RecordConstructor { 829 location, 830 name_location, 831 name, 832 arguments: args, 833 documentation, 834 deprecation: constructor_deprecation, 835 }| { 836 self.check_name_case(name_location, &name, Named::CustomTypeVariant); 837 if constructor_deprecation.is_deprecated() { 838 self.track_feature_usage( 839 FeatureKind::VariantWithDeprecatedAnnotation, 840 location, 841 ); 842 } 843 844 let preregistered_fn = environment 845 .get_variable(&name) 846 .expect("Could not find preregistered type for function"); 847 let preregistered_type = preregistered_fn.type_.clone(); 848 849 let args = match preregistered_type.fn_types() { 850 Some((args_types, _return_type)) => args 851 .into_iter() 852 .zip(&args_types) 853 .map(|(argument, t)| { 854 if let Some((location, label)) = &argument.label { 855 self.check_name_case(*location, label, Named::Label); 856 } 857 858 RecordConstructorArg { 859 label: argument.label, 860 ast: argument.ast, 861 location: argument.location, 862 type_: t.clone(), 863 doc: argument.doc, 864 } 865 }) 866 .collect(), 867 _ => { 868 vec![] 869 } 870 }; 871 872 RecordConstructor { 873 location, 874 name_location, 875 name, 876 arguments: args, 877 documentation, 878 deprecation: constructor_deprecation, 879 } 880 }, 881 ) 882 .collect(); 883 let typed_parameters = environment 884 .get_type_constructor(&None, &name) 885 .expect("Could not find preregistered type constructor ") 886 .parameters 887 .clone(); 888 889 // Check if all constructors are deprecated if so error. 890 if !constructors.is_empty() 891 && constructors 892 .iter() 893 .all(|record| record.deprecation.is_deprecated()) 894 { 895 self.problems 896 .error(Error::AllVariantsDeprecated { location }); 897 } 898 899 // If any constructor record/varient is deprecated while 900 // the type is deprecated as a whole that is considered an error. 901 if deprecation.is_deprecated() 902 && !constructors.is_empty() 903 && constructors 904 .iter() 905 .any(|record| record.deprecation.is_deprecated()) 906 { 907 // Report error on all variants attibuted with deprecated 908 constructors 909 .iter() 910 .filter(|record| record.deprecation.is_deprecated()) 911 .for_each(|record| { 912 self.problems 913 .error(Error::DeprecatedVariantOnDeprecatedType { 914 location: record.location, 915 }); 916 }); 917 } 918 919 Ok(Definition::CustomType(CustomType { 920 documentation: doc, 921 location, 922 end_position, 923 publicity, 924 opaque, 925 name, 926 name_location, 927 parameters, 928 constructors, 929 typed_parameters, 930 deprecation, 931 })) 932 } 933 934 fn register_values_from_custom_type( 935 &mut self, 936 t: &UntypedCustomType, 937 environment: &mut Environment<'_>, 938 type_parameters: &[&EcoString], 939 ) -> Result<(), Error> { 940 let CustomType { 941 publicity, 942 opaque, 943 name, 944 constructors, 945 deprecation, 946 .. 947 } = t; 948 949 let mut hydrator = self 950 .hydrators 951 .remove(name) 952 .expect("Could not find hydrator for register_values custom type"); 953 hydrator.disallow_new_type_variables(); 954 let type_ = environment 955 .module_types 956 .get(name) 957 .expect("Type for custom type not found in register_values") 958 .type_ 959 .clone(); 960 961 let Accessors { 962 shared_accessors, 963 variant_specific_accessors, 964 } = custom_type_accessors(constructors, &mut hydrator, environment, &mut self.problems)?; 965 966 let map = AccessorsMap { 967 publicity: if *opaque { 968 Publicity::Private 969 } else { 970 *publicity 971 }, 972 shared_accessors, 973 // TODO: improve the ownership here so that we can use the 974 // `return_type_constructor` below rather than looking it up twice. 975 type_: type_.clone(), 976 variant_specific_accessors, 977 }; 978 environment.insert_accessors(name.clone(), map); 979 980 let mut constructors_data = vec![]; 981 982 let mut index = 0; 983 for constructor in constructors.iter() { 984 if let Err(error) = assert_unique_name( 985 &mut self.value_names, 986 &constructor.name, 987 constructor.location, 988 ) { 989 self.problems.error(error); 990 continue; 991 } 992 993 let mut field_map = FieldMap::new(constructor.arguments.len() as u32); 994 let mut args_types = Vec::with_capacity(constructor.arguments.len()); 995 let mut fields = Vec::with_capacity(constructor.arguments.len()); 996 997 for (i, RecordConstructorArg { label, ast, .. }) in 998 constructor.arguments.iter().enumerate() 999 { 1000 // Build a type from the annotation AST 1001 let t = match hydrator.type_from_ast(ast, environment, &mut self.problems) { 1002 Ok(t) => t, 1003 Err(e) => { 1004 self.problems.error(e); 1005 continue; 1006 } 1007 }; 1008 1009 fields.push(TypeValueConstructorField { type_: t.clone() }); 1010 1011 // Register the type for this parameter 1012 args_types.push(t); 1013 1014 // Register the label for this parameter, if there is one 1015 if let Some((location, label)) = label { 1016 if field_map.insert(label.clone(), i as u32).is_err() { 1017 self.problems.error(Error::DuplicateField { 1018 label: label.clone(), 1019 location: *location, 1020 }); 1021 }; 1022 } 1023 } 1024 let field_map = field_map.into_option(); 1025 // Insert constructor function into module scope 1026 let mut type_ = type_.deref().clone(); 1027 type_.set_custom_type_variant(index as u16); 1028 let type_ = match constructor.arguments.len() { 1029 0 => Arc::new(type_), 1030 _ => fn_(args_types.clone(), Arc::new(type_)), 1031 }; 1032 let constructor_info = ValueConstructorVariant::Record { 1033 documentation: constructor 1034 .documentation 1035 .as_ref() 1036 .map(|(_, doc)| doc.clone()), 1037 variants_count: constructors.len() as u16, 1038 name: constructor.name.clone(), 1039 arity: constructor.arguments.len() as u16, 1040 field_map: field_map.clone(), 1041 location: constructor.location, 1042 module: self.module_name.clone(), 1043 variant_index: index as u16, 1044 }; 1045 index += 1; 1046 1047 // If the contructor belongs to an opaque type then it's going to be 1048 // considered as private. 1049 let value_constructor_publicity = if *opaque { 1050 Publicity::Private 1051 } else { 1052 *publicity 1053 }; 1054 1055 // If the whole custom type is deprecated all of its varints are too. 1056 // Otherwise just the varint(s) attributed as deprecated are. 1057 let deprecate_constructor = if deprecation.is_deprecated() { 1058 deprecation 1059 } else { 1060 &constructor.deprecation 1061 }; 1062 1063 environment.insert_module_value( 1064 constructor.name.clone(), 1065 ValueConstructor { 1066 publicity: value_constructor_publicity, 1067 deprecation: deprecate_constructor.clone(), 1068 type_: type_.clone(), 1069 variant: constructor_info.clone(), 1070 }, 1071 ); 1072 1073 if value_constructor_publicity.is_private() { 1074 environment.init_usage( 1075 constructor.name.clone(), 1076 EntityKind::PrivateTypeConstructor(name.clone()), 1077 constructor.location, 1078 &mut self.problems, 1079 ); 1080 } 1081 1082 constructors_data.push(TypeValueConstructor { 1083 name: constructor.name.clone(), 1084 parameters: fields, 1085 }); 1086 environment.insert_variable( 1087 constructor.name.clone(), 1088 constructor_info, 1089 type_, 1090 value_constructor_publicity, 1091 deprecate_constructor.clone(), 1092 ); 1093 1094 environment.names.named_constructor_in_scope( 1095 environment.current_module.clone(), 1096 constructor.name.clone(), 1097 constructor.name.clone(), 1098 ); 1099 } 1100 1101 // Now record the constructors for the type. 1102 environment.insert_type_to_constructors( 1103 name.clone(), 1104 TypeVariantConstructors::new(constructors_data, type_parameters, hydrator), 1105 ); 1106 1107 Ok(()) 1108 } 1109 1110 fn register_types_from_custom_type( 1111 &mut self, 1112 t: &UntypedCustomType, 1113 environment: &mut Environment<'a>, 1114 ) -> Result<(), Error> { 1115 let CustomType { 1116 name, 1117 name_location, 1118 publicity, 1119 parameters, 1120 location, 1121 deprecation, 1122 opaque, 1123 constructors, 1124 documentation, 1125 .. 1126 } = t; 1127 // We exit early here as we don't yet have a good way to handle the two 1128 // duplicate definitions in the later pass of the analyser which 1129 // register the constructor values for the types. The latter would end up 1130 // overwriting the former, but here in type registering we keep the 1131 // former. I think we want to really keep the former both times. 1132 // The fact we can't straightforwardly do this indicated to me that we 1133 // could improve our approach here somewhat. 1134 environment.assert_unique_type_name(name, *location)?; 1135 1136 self.check_name_case(*name_location, name, Named::Type); 1137 1138 let mut hydrator = Hydrator::new(); 1139 let parameters = self.make_type_vars(parameters, &mut hydrator, environment); 1140 1141 hydrator.clear_ridgid_type_names(); 1142 1143 // We check is the type comes from an internal module and restrict its 1144 // publicity. 1145 let publicity = match publicity { 1146 // It's important we only restrict the publicity of public types. 1147 Publicity::Public if self.package_config.is_internal_module(&self.module_name) => { 1148 Publicity::Internal { 1149 attribute_location: None, 1150 } 1151 } 1152 // If a type is private we don't want to make it internal just because 1153 // it comes from an internal module, so in that case the publicity is 1154 // left unchanged. 1155 Publicity::Public | Publicity::Private | Publicity::Internal { .. } => *publicity, 1156 }; 1157 1158 let type_ = Arc::new(Type::Named { 1159 publicity, 1160 package: environment.current_package.clone(), 1161 module: self.module_name.to_owned(), 1162 name: name.clone(), 1163 args: parameters.clone(), 1164 inferred_variant: None, 1165 }); 1166 let _ = self.hydrators.insert(name.clone(), hydrator); 1167 environment 1168 .insert_type_constructor( 1169 name.clone(), 1170 TypeConstructor { 1171 origin: *location, 1172 module: self.module_name.clone(), 1173 deprecation: deprecation.clone(), 1174 parameters, 1175 publicity, 1176 type_, 1177 documentation: documentation.as_ref().map(|(_, doc)| doc.clone()), 1178 }, 1179 ) 1180 .expect("name uniqueness checked above"); 1181 1182 environment.names.named_type_in_scope( 1183 environment.current_module.clone(), 1184 name.clone(), 1185 name.clone(), 1186 ); 1187 1188 if *opaque && constructors.is_empty() { 1189 self.problems.warning(Warning::OpaqueExternalType { 1190 location: *location, 1191 }); 1192 } 1193 1194 if publicity.is_private() { 1195 environment.init_usage( 1196 name.clone(), 1197 EntityKind::PrivateType, 1198 *location, 1199 &mut self.problems, 1200 ); 1201 }; 1202 Ok(()) 1203 } 1204 1205 fn register_type_alias(&mut self, t: &UntypedTypeAlias, environment: &mut Environment<'_>) { 1206 let TypeAlias { 1207 location, 1208 publicity, 1209 parameters: args, 1210 alias: name, 1211 name_location, 1212 type_ast: resolved_type, 1213 deprecation, 1214 type_: _, 1215 documentation, 1216 } = t; 1217 1218 // A type alias must not have the same name as any other type in the module. 1219 if let Err(error) = environment.assert_unique_type_name(name, *location) { 1220 self.problems.error(error); 1221 // A type already exists with the name so we cannot continue and 1222 // register this new type with the same name. 1223 return; 1224 } 1225 1226 self.check_name_case(*name_location, name, Named::TypeAlias); 1227 1228 // Use the hydrator to convert the AST into a type, erroring if the AST was invalid 1229 // in some fashion. 1230 let mut hydrator = Hydrator::new(); 1231 let parameters = self.make_type_vars(args, &mut hydrator, environment); 1232 let tryblock = || { 1233 hydrator.disallow_new_type_variables(); 1234 let type_ = hydrator.type_from_ast(resolved_type, environment, &mut self.problems)?; 1235 1236 environment 1237 .names 1238 .type_in_scope(name.clone(), type_.as_ref(), &parameters); 1239 1240 // Insert the alias so that it can be used by other code. 1241 environment.insert_type_constructor( 1242 name.clone(), 1243 TypeConstructor { 1244 origin: *location, 1245 module: self.module_name.clone(), 1246 parameters, 1247 type_, 1248 deprecation: deprecation.clone(), 1249 publicity: *publicity, 1250 documentation: documentation.as_ref().map(|(_, doc)| doc.clone()), 1251 }, 1252 )?; 1253 1254 if let Some(name) = hydrator.unused_type_variables().next() { 1255 return Err(Error::UnusedTypeAliasParameter { 1256 location: *location, 1257 name: name.clone(), 1258 }); 1259 } 1260 1261 Ok(()) 1262 }; 1263 let result = tryblock(); 1264 self.record_if_error(result); 1265 1266 // Register the type for detection of dead code. 1267 if publicity.is_private() { 1268 environment.init_usage( 1269 name.clone(), 1270 EntityKind::PrivateType, 1271 *location, 1272 &mut self.problems, 1273 ); 1274 }; 1275 } 1276 1277 fn make_type_vars( 1278 &mut self, 1279 args: &[SpannedString], 1280 hydrator: &mut Hydrator, 1281 environment: &mut Environment<'_>, 1282 ) -> Vec<Arc<Type>> { 1283 args.iter() 1284 .map(|(location, name)| { 1285 self.check_name_case(*location, name, Named::TypeVariable); 1286 match hydrator.add_type_variable(name, environment) { 1287 Ok(t) => t, 1288 Err(t) => { 1289 self.problems.error(Error::DuplicateTypeParameter { 1290 location: *location, 1291 name: name.clone(), 1292 }); 1293 t 1294 } 1295 } 1296 }) 1297 .collect() 1298 } 1299 1300 fn record_if_error(&mut self, result: Result<(), Error>) { 1301 if let Err(error) = result { 1302 self.problems.error(error); 1303 } 1304 } 1305 1306 fn register_value_from_function( 1307 &mut self, 1308 f: &UntypedFunction, 1309 environment: &mut Environment<'_>, 1310 ) -> Result<(), Error> { 1311 let Function { 1312 name, 1313 arguments: args, 1314 location, 1315 return_annotation, 1316 publicity, 1317 documentation, 1318 external_erlang, 1319 external_javascript, 1320 deprecation, 1321 end_position: _, 1322 body: _, 1323 return_type: _, 1324 implementations, 1325 } = f; 1326 let (name_location, name) = name.as_ref().expect("A module's function must be named"); 1327 1328 self.check_name_case(*name_location, name, Named::Function); 1329 1330 let mut builder = FieldMapBuilder::new(args.len() as u32); 1331 for Arg { 1332 names, location, .. 1333 } in args.iter() 1334 { 1335 check_argument_names(names, &mut self.problems); 1336 1337 builder.add(names.get_label(), *location)?; 1338 } 1339 let field_map = builder.finish(); 1340 let mut hydrator = Hydrator::new(); 1341 1342 // When external implementations are present then the type annotations 1343 // must be given in full, so we disallow holes in the annotations. 1344 hydrator.permit_holes(external_erlang.is_none() && external_javascript.is_none()); 1345 1346 let arg_types = args 1347 .iter() 1348 .map(|arg| { 1349 hydrator.type_from_option_ast(&arg.annotation, environment, &mut self.problems) 1350 }) 1351 .try_collect()?; 1352 let return_type = 1353 hydrator.type_from_option_ast(return_annotation, environment, &mut self.problems)?; 1354 let type_ = fn_(arg_types, return_type); 1355 let _ = self.hydrators.insert(name.clone(), hydrator); 1356 1357 let variant = ValueConstructorVariant::ModuleFn { 1358 documentation: documentation.as_ref().map(|(_, doc)| doc.clone()), 1359 name: name.clone(), 1360 field_map, 1361 external_erlang: external_erlang 1362 .as_ref() 1363 .map(|(m, f, _)| (m.clone(), f.clone())), 1364 external_javascript: external_javascript 1365 .as_ref() 1366 .map(|(m, f, _)| (m.clone(), f.clone())), 1367 module: environment.current_module.clone(), 1368 arity: args.len(), 1369 location: *location, 1370 implementations: *implementations, 1371 }; 1372 environment.insert_variable( 1373 name.clone(), 1374 variant, 1375 type_, 1376 *publicity, 1377 deprecation.clone(), 1378 ); 1379 if publicity.is_private() { 1380 environment.init_usage( 1381 name.clone(), 1382 EntityKind::PrivateFunction, 1383 *location, 1384 &mut self.problems, 1385 ); 1386 }; 1387 Ok(()) 1388 } 1389 1390 fn check_for_type_leaks(&mut self, value: &ValueConstructor) { 1391 // A private value doesn't export anything so it can't leak anything. 1392 if value.publicity.is_private() { 1393 return; 1394 } 1395 1396 // If a private or internal value references a private type 1397 if let Some(leaked) = value.type_.find_private_type() { 1398 self.problems.error(Error::PrivateTypeLeak { 1399 location: value.variant.definition_location(), 1400 leaked, 1401 }); 1402 } 1403 } 1404 1405 fn check_name_case(&mut self, location: SrcSpan, name: &EcoString, kind: Named) { 1406 if let Err(error) = check_name_case(location, name, kind) { 1407 self.problems.error(error); 1408 } 1409 } 1410 1411 fn track_feature_usage(&mut self, feature_kind: FeatureKind, location: SrcSpan) { 1412 let minimum_required_version = feature_kind.required_version(); 1413 1414 // Then if the required version is not in the specified version for the 1415 // range we emit a warning highlighting the usage of the feature. 1416 if let Some(gleam_version) = &self.package_config.gleam_version { 1417 if let Some(lowest_allowed_version) = gleam_version.lowest_version() { 1418 // There is a version in the specified range that is lower than 1419 // the one required by this feature! This means that the 1420 // specified range is wrong and would allow someone to run a 1421 // compiler that is too old to know of this feature. 1422 if minimum_required_version > lowest_allowed_version { 1423 self.problems 1424 .warning(Warning::FeatureRequiresHigherGleamVersion { 1425 location, 1426 feature_kind, 1427 minimum_required_version: minimum_required_version.clone(), 1428 wrongfully_allowed_version: lowest_allowed_version, 1429 }) 1430 } 1431 } 1432 } 1433 1434 if minimum_required_version > self.minimum_required_version { 1435 self.minimum_required_version = minimum_required_version; 1436 } 1437 } 1438} 1439 1440fn optionally_push<T>(vector: &mut Vec<T>, item: Option<T>) { 1441 if let Some(item) = item { 1442 vector.push(item) 1443 } 1444} 1445 1446fn validate_module_name(name: &EcoString) -> Result<(), Error> { 1447 if is_prelude_module(name) { 1448 return Err(Error::ReservedModuleName { name: name.clone() }); 1449 }; 1450 for segment in name.split('/') { 1451 if crate::parse::lexer::str_to_keyword(segment).is_some() { 1452 return Err(Error::KeywordInModuleName { 1453 name: name.clone(), 1454 keyword: segment.into(), 1455 }); 1456 } 1457 } 1458 Ok(()) 1459} 1460 1461fn target_function_implementation<'a>( 1462 target: Target, 1463 external_erlang: &'a Option<(EcoString, EcoString, SrcSpan)>, 1464 external_javascript: &'a Option<(EcoString, EcoString, SrcSpan)>, 1465) -> &'a Option<(EcoString, EcoString, SrcSpan)> { 1466 match target { 1467 Target::Erlang => external_erlang, 1468 Target::JavaScript => external_javascript, 1469 } 1470} 1471 1472fn analyse_type_alias(t: UntypedTypeAlias, environment: &mut Environment<'_>) -> TypedDefinition { 1473 let TypeAlias { 1474 documentation: doc, 1475 location, 1476 publicity, 1477 alias, 1478 name_location, 1479 parameters: args, 1480 type_ast: resolved_type, 1481 deprecation, 1482 .. 1483 } = t; 1484 1485 // There could be no type alias registered if it was invalid in some way. 1486 // analysis aims to be fault tolerant to get the best possible feedback for 1487 // the programmer in the language server, so the analyser gets here even 1488 // though there was previously errors. 1489 let type_ = match environment.get_type_constructor(&None, &alias) { 1490 Ok(constructor) => constructor.type_.clone(), 1491 Err(_) => environment.new_generic_var(), 1492 }; 1493 Definition::TypeAlias(TypeAlias { 1494 documentation: doc, 1495 location, 1496 publicity, 1497 alias, 1498 name_location, 1499 parameters: args, 1500 type_ast: resolved_type, 1501 type_, 1502 deprecation, 1503 }) 1504} 1505 1506pub fn infer_bit_array_option<UntypedValue, TypedValue, Typer>( 1507 segment_option: BitArrayOption<UntypedValue>, 1508 mut type_check: Typer, 1509) -> Result<BitArrayOption<TypedValue>, Error> 1510where 1511 Typer: FnMut(UntypedValue, Arc<Type>) -> Result<TypedValue, Error>, 1512{ 1513 match segment_option { 1514 BitArrayOption::Size { 1515 value, 1516 location, 1517 short_form, 1518 .. 1519 } => { 1520 let value = type_check(*value, int())?; 1521 Ok(BitArrayOption::Size { 1522 location, 1523 short_form, 1524 value: Box::new(value), 1525 }) 1526 } 1527 1528 BitArrayOption::Unit { location, value } => Ok(BitArrayOption::Unit { location, value }), 1529 1530 BitArrayOption::Bytes { location } => Ok(BitArrayOption::Bytes { location }), 1531 BitArrayOption::Int { location } => Ok(BitArrayOption::Int { location }), 1532 BitArrayOption::Float { location } => Ok(BitArrayOption::Float { location }), 1533 BitArrayOption::Bits { location } => Ok(BitArrayOption::Bits { location }), 1534 BitArrayOption::Utf8 { location } => Ok(BitArrayOption::Utf8 { location }), 1535 BitArrayOption::Utf16 { location } => Ok(BitArrayOption::Utf16 { location }), 1536 BitArrayOption::Utf32 { location } => Ok(BitArrayOption::Utf32 { location }), 1537 BitArrayOption::Utf8Codepoint { location } => { 1538 Ok(BitArrayOption::Utf8Codepoint { location }) 1539 } 1540 BitArrayOption::Utf16Codepoint { location } => { 1541 Ok(BitArrayOption::Utf16Codepoint { location }) 1542 } 1543 BitArrayOption::Utf32Codepoint { location } => { 1544 Ok(BitArrayOption::Utf32Codepoint { location }) 1545 } 1546 BitArrayOption::Signed { location } => Ok(BitArrayOption::Signed { location }), 1547 BitArrayOption::Unsigned { location } => Ok(BitArrayOption::Unsigned { location }), 1548 BitArrayOption::Big { location } => Ok(BitArrayOption::Big { location }), 1549 BitArrayOption::Little { location } => Ok(BitArrayOption::Little { location }), 1550 BitArrayOption::Native { location } => Ok(BitArrayOption::Native { location }), 1551 } 1552} 1553 1554fn generalise_statement( 1555 s: TypedDefinition, 1556 module_name: &EcoString, 1557 environment: &mut Environment<'_>, 1558) -> TypedDefinition { 1559 match s { 1560 Definition::Function(function) => generalise_function(function, environment, module_name), 1561 Definition::ModuleConstant(constant) => { 1562 generalise_module_constant(constant, environment, module_name) 1563 } 1564 statement @ (Definition::TypeAlias(TypeAlias { .. }) 1565 | Definition::CustomType(CustomType { .. }) 1566 | Definition::Import(Import { .. })) => statement, 1567 } 1568} 1569 1570fn generalise_module_constant( 1571 constant: ModuleConstant<Arc<Type>, EcoString>, 1572 environment: &mut Environment<'_>, 1573 module_name: &EcoString, 1574) -> TypedDefinition { 1575 let ModuleConstant { 1576 documentation: doc, 1577 location, 1578 name, 1579 name_location, 1580 annotation, 1581 publicity, 1582 value, 1583 type_, 1584 deprecation, 1585 implementations, 1586 } = constant; 1587 let type_ = type_.clone(); 1588 let type_ = type_::generalise(type_); 1589 let variant = ValueConstructorVariant::ModuleConstant { 1590 documentation: doc.as_ref().map(|(_, doc)| doc.clone()), 1591 location, 1592 literal: *value.clone(), 1593 module: module_name.clone(), 1594 implementations, 1595 }; 1596 environment.insert_variable( 1597 name.clone(), 1598 variant.clone(), 1599 type_.clone(), 1600 publicity, 1601 deprecation.clone(), 1602 ); 1603 1604 environment.insert_module_value( 1605 name.clone(), 1606 ValueConstructor { 1607 publicity, 1608 variant, 1609 deprecation: deprecation.clone(), 1610 type_: type_.clone(), 1611 }, 1612 ); 1613 1614 Definition::ModuleConstant(ModuleConstant { 1615 documentation: doc, 1616 location, 1617 name, 1618 name_location, 1619 annotation, 1620 publicity, 1621 value, 1622 type_, 1623 deprecation, 1624 implementations, 1625 }) 1626} 1627 1628fn generalise_function( 1629 function: TypedFunction, 1630 environment: &mut Environment<'_>, 1631 module_name: &EcoString, 1632) -> TypedDefinition { 1633 let Function { 1634 documentation: doc, 1635 location, 1636 name, 1637 publicity, 1638 deprecation, 1639 arguments: args, 1640 body, 1641 return_annotation, 1642 end_position: end_location, 1643 return_type, 1644 external_erlang, 1645 external_javascript, 1646 implementations, 1647 } = function; 1648 1649 let (name_location, name) = name.expect("Function in a definition must be named"); 1650 1651 // Lookup the inferred function information 1652 let function = environment 1653 .get_variable(&name) 1654 .expect("Could not find preregistered type for function"); 1655 let field_map = function.field_map().cloned(); 1656 let type_ = function.type_.clone(); 1657 1658 let type_ = type_::generalise(type_); 1659 1660 // Insert the function into the module's interface 1661 let variant = ValueConstructorVariant::ModuleFn { 1662 documentation: doc.as_ref().map(|(_, doc)| doc.clone()), 1663 name: name.clone(), 1664 field_map, 1665 external_erlang: external_erlang 1666 .as_ref() 1667 .map(|(m, f, _)| (m.clone(), f.clone())), 1668 external_javascript: external_javascript 1669 .as_ref() 1670 .map(|(m, f, _)| (m.clone(), f.clone())), 1671 module: module_name.clone(), 1672 arity: args.len(), 1673 location, 1674 implementations, 1675 }; 1676 environment.insert_variable( 1677 name.clone(), 1678 variant.clone(), 1679 type_.clone(), 1680 publicity, 1681 deprecation.clone(), 1682 ); 1683 environment.insert_module_value( 1684 name.clone(), 1685 ValueConstructor { 1686 publicity, 1687 deprecation: deprecation.clone(), 1688 type_, 1689 variant, 1690 }, 1691 ); 1692 1693 Definition::Function(Function { 1694 documentation: doc, 1695 location, 1696 name: Some((name_location, name)), 1697 publicity, 1698 deprecation, 1699 arguments: args, 1700 end_position: end_location, 1701 return_annotation, 1702 return_type, 1703 body, 1704 external_erlang, 1705 external_javascript, 1706 implementations, 1707 }) 1708} 1709 1710fn assert_unique_name( 1711 names: &mut HashMap<EcoString, SrcSpan>, 1712 name: &EcoString, 1713 location: SrcSpan, 1714) -> Result<(), Error> { 1715 match names.insert(name.clone(), location) { 1716 Some(previous_location) => Err(Error::DuplicateName { 1717 location_a: location, 1718 location_b: previous_location, 1719 name: name.clone(), 1720 }), 1721 None => Ok(()), 1722 } 1723} 1724 1725struct Accessors { 1726 shared_accessors: HashMap<EcoString, RecordAccessor>, 1727 variant_specific_accessors: Vec<HashMap<EcoString, RecordAccessor>>, 1728} 1729 1730fn custom_type_accessors<A: std::fmt::Debug>( 1731 constructors: &[RecordConstructor<A>], 1732 hydrator: &mut Hydrator, 1733 environment: &mut Environment<'_>, 1734 problems: &mut Problems, 1735) -> Result<Accessors, Error> { 1736 let args = get_compatible_record_fields(constructors); 1737 1738 let mut shared_accessors = HashMap::with_capacity(args.len()); 1739 1740 hydrator.disallow_new_type_variables(); 1741 for (index, label, ast) in args { 1742 let type_ = hydrator.type_from_ast(ast, environment, problems)?; 1743 let _ = shared_accessors.insert( 1744 label.clone(), 1745 RecordAccessor { 1746 index: index as u64, 1747 label: label.clone(), 1748 type_, 1749 }, 1750 ); 1751 } 1752 1753 let mut variant_specific_accessors = Vec::with_capacity(constructors.len()); 1754 1755 for constructor in constructors { 1756 let mut fields = HashMap::with_capacity(constructor.arguments.len()); 1757 1758 for (index, argument) in constructor.arguments.iter().enumerate() { 1759 let Some((_location, label)) = &argument.label else { 1760 continue; 1761 }; 1762 1763 let type_ = hydrator.type_from_ast(&argument.ast, environment, problems)?; 1764 let _ = fields.insert( 1765 label.clone(), 1766 RecordAccessor { 1767 index: index as u64, 1768 label: label.clone(), 1769 type_, 1770 }, 1771 ); 1772 } 1773 variant_specific_accessors.push(fields); 1774 } 1775 1776 Ok(Accessors { 1777 shared_accessors, 1778 variant_specific_accessors, 1779 }) 1780} 1781 1782/// Returns the fields that have the same label and type across all variants of 1783/// the given type. 1784fn get_compatible_record_fields<A: std::fmt::Debug>( 1785 constructors: &[RecordConstructor<A>], 1786) -> Vec<(usize, &EcoString, &TypeAst)> { 1787 let mut compatible = vec![]; 1788 1789 let first = match constructors.first() { 1790 Some(first) => first, 1791 None => return compatible, 1792 }; 1793 1794 'next_argument: for (index, first_argument) in first.arguments.iter().enumerate() { 1795 // Fields without labels do not have accessors 1796 let first_label = match first_argument.label.as_ref() { 1797 Some((_, label)) => label, 1798 None => continue 'next_argument, 1799 }; 1800 1801 // Check each variant to see if they have an field in the same position 1802 // with the same label and the same type 1803 for constructor in constructors.iter().skip(1) { 1804 // The field must exist in all variants 1805 let argument = match constructor.arguments.get(index) { 1806 Some(argument) => argument, 1807 None => continue 'next_argument, 1808 }; 1809 1810 // The labels must be the same 1811 if argument 1812 .label 1813 .as_ref() 1814 .is_none_or(|(_, arg_label)| arg_label != first_label) 1815 { 1816 continue 'next_argument; 1817 } 1818 1819 // The types must be the same 1820 if !argument.ast.is_logically_equal(&first_argument.ast) { 1821 continue 'next_argument; 1822 } 1823 } 1824 1825 // The previous loop did not find any incompatible fields in the other 1826 // variants so this field is compatible across variants and we should 1827 // generate an accessor for it. 1828 compatible.push((index, first_label, &first_argument.ast)) 1829 } 1830 1831 compatible 1832} 1833 1834/// Given a type, return a list of all the types it depends on 1835fn get_type_dependencies(type_: &TypeAst) -> Vec<EcoString> { 1836 let mut deps = Vec::with_capacity(1); 1837 1838 match type_ { 1839 TypeAst::Var(TypeAstVar { .. }) => (), 1840 TypeAst::Hole(TypeAstHole { .. }) => (), 1841 TypeAst::Constructor(TypeAstConstructor { 1842 name, 1843 arguments, 1844 module, 1845 .. 1846 }) => { 1847 deps.push(match module { 1848 Some((module, _)) => format!("{name}.{module}").into(), 1849 None => name.clone(), 1850 }); 1851 1852 for arg in arguments { 1853 deps.extend(get_type_dependencies(arg)) 1854 } 1855 } 1856 TypeAst::Fn(TypeAstFn { 1857 arguments, return_, .. 1858 }) => { 1859 for arg in arguments { 1860 deps.extend(get_type_dependencies(arg)) 1861 } 1862 deps.extend(get_type_dependencies(return_)) 1863 } 1864 TypeAst::Tuple(TypeAstTuple { elems, .. }) => { 1865 for elem in elems { 1866 deps.extend(get_type_dependencies(elem)) 1867 } 1868 } 1869 } 1870 1871 deps 1872} 1873 1874fn sorted_type_aliases(aliases: &Vec<UntypedTypeAlias>) -> Result<Vec<&UntypedTypeAlias>, Error> { 1875 let mut deps: Vec<(EcoString, Vec<EcoString>)> = Vec::with_capacity(aliases.len()); 1876 1877 for alias in aliases { 1878 deps.push((alias.alias.clone(), get_type_dependencies(&alias.type_ast))) 1879 } 1880 1881 let sorted_deps = dep_tree::toposort_deps(deps).map_err(|err| { 1882 let dep_tree::Error::Cycle(cycle) = err; 1883 1884 let last = cycle.last().expect("Cycle should not be empty"); 1885 let alias = aliases 1886 .iter() 1887 .find(|alias| alias.alias == *last) 1888 .expect("Could not find alias for cycle"); 1889 1890 Error::RecursiveTypeAlias { 1891 cycle, 1892 location: alias.location, 1893 } 1894 })?; 1895 1896 Ok(aliases 1897 .iter() 1898 .sorted_by_key(|alias| sorted_deps.iter().position(|x| x == &alias.alias)) 1899 .collect()) 1900}