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