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