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