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
79 kB 2252 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_cranelift_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_cranelift, 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_cranelift, 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 location, 592 ); 593 594 if external.is_some() { 595 // There was an external implementation, so type annotations are 596 // mandatory as the Gleam implementation may be absent, and because we 597 // think you should always specify types for external functions for 598 // clarity + to avoid accidental mistakes. 599 self.ensure_annotations_present(&arguments, return_annotation.as_ref(), location); 600 } 601 602 let has_body = !body.is_empty(); 603 let definition = FunctionDefinition { 604 has_body, 605 has_erlang_external: external_erlang.is_some(), 606 has_javascript_external: external_javascript.is_some(), 607 has_cranelift_external: external_cranelift.is_some(), 608 }; 609 610 // We have already registered the function in the `register_value_from_function` 611 // method, but here we must set this as the current function again, so that anything 612 // we reference in the body of it can be tracked properly in the call graph. 613 environment.references.set_current_node(name.clone()); 614 615 let mut typed_arguments = Vec::with_capacity(arguments.len()); 616 617 // Infer the type using the preregistered args + return types as a starting point 618 let result = environment.in_new_scope(&mut self.problems, |environment, problems| { 619 for (argument, type_) in arguments.into_iter().zip(&prereg_arguments_types) { 620 let argument = argument.set_type(type_.clone()); 621 622 // We track which arguments are discarded so we can provide nice 623 // error messages when someone 624 match &argument.names { 625 ast::ArgNames::Named { .. } | ast::ArgNames::NamedLabelled { .. } => (), 626 ast::ArgNames::Discard { name, location } 627 | ast::ArgNames::LabelledDiscard { 628 name, 629 name_location: location, 630 .. 631 } => { 632 let _ = environment.discarded_names.insert(name.clone(), *location); 633 } 634 } 635 636 typed_arguments.push(argument); 637 } 638 639 let mut expr_typer = ExprTyper::new(environment, definition, problems); 640 expr_typer.hydrator = self 641 .hydrators 642 .remove(&name) 643 .expect("Could not find hydrator for fn"); 644 645 let (arguments, body) = expr_typer.infer_fn_with_known_types( 646 Some(name.clone()), 647 typed_arguments.clone(), 648 body, 649 Some(prereg_return_type.clone()), 650 )?; 651 let arguments_types = arguments.iter().map(|a| a.type_.clone()).collect(); 652 let return_type = body 653 .last() 654 .map_or(prereg_return_type.clone(), |last| last.type_()); 655 656 // `dict.do_fold` is a bit special: since it belongs to the stdlib 657 // it is considered pure by default. 658 // However, since it ends up calling its function argument its 659 // purity should actually be `Impure`. We need to special case it 660 // and set the value ourselves. 661 // 662 // You might wonder why `do_fold` needs this but other similar 663 // functions like `list.each` don't need this special handling. 664 // The key difference is `list.each` calls the higher order function 665 // in its gleam body: 666 // 667 // ```gleam 668 // fn each(list, fun) { 669 // case list { 670 // [] -> Nil 671 // [first, ..rest] -> { 672 // fun(first) 673 // // ^^^ Here we're calling `fun`. It's happening in Gleam so 674 // // the compiler can see this and understand that `each` 675 // // is impure. 676 // // You might argue the purity actually depends on the 677 // // purity of `fun` itself. That's true! But it's a 678 // // separate known problem. For the time being we always 679 // // assume a function argument is impure. 680 // each(rest, fun) 681 // } 682 // } 683 // } 684 // ``` 685 // 686 // But since `do_fold` is an external the compiler can't know what 687 // is going on with its function argument and keeps thinking it must 688 // be pure 689 // 690 // ```gleam 691 // @external(erlang, "", "") 692 // fn do_fold(dict: Dict(k, v), fun: fn(k, v) -> a) -> Nil 693 // ``` 694 // 695 let purity = if expr_typer.environment.current_package == STDLIB_PACKAGE_NAME 696 && expr_typer.environment.current_module == "gleam/dict" 697 && name == "do_fold" 698 { 699 Purity::Impure 700 } else { 701 expr_typer.purity 702 }; 703 704 let type_ = fn_(arguments_types, return_type); 705 Ok(( 706 type_, 707 body, 708 expr_typer.implementations, 709 expr_typer.minimum_required_version, 710 purity, 711 )) 712 }); 713 714 // If we could not successfully infer the type etc information of the 715 // function then register the error and continue anaylsis using the best 716 // information that we have, so we can still learn about the rest of the 717 // module. 718 let (type_, body, implementations, required_version, purity) = match result { 719 Ok((type_, body, implementations, required_version, purity)) => { 720 (type_, body, implementations, required_version, purity) 721 } 722 Err(error) => { 723 self.problems.error(error); 724 let type_ = preregistered_type.clone(); 725 let body = vec![Statement::Expression(TypedExpr::Invalid { 726 type_: prereg_return_type.clone(), 727 location: SrcSpan { 728 start: body_location.end, 729 end: body_location.end, 730 }, 731 extra_information: None, 732 })]; 733 let implementations = Implementations::supporting_all(); 734 ( 735 type_, 736 body, 737 implementations, 738 Version::new(1, 0, 0), 739 Purity::Impure, 740 ) 741 } 742 }; 743 744 if required_version > self.minimum_required_version { 745 self.minimum_required_version = required_version; 746 } 747 748 match publicity { 749 Publicity::Private 750 | Publicity::Public 751 | Publicity::Internal { 752 attribute_location: None, 753 } => (), 754 755 Publicity::Internal { 756 attribute_location: Some(location), 757 } => self.track_feature_usage(FeatureKind::InternalAnnotation, location), 758 } 759 760 if let Some((module, _, location)) = &external_javascript 761 && module.contains('@') 762 { 763 self.track_feature_usage(FeatureKind::AtInJavascriptModules, *location); 764 } 765 766 // Assert that the inferred type matches the type of any recursive call 767 if let Err(error) = unify(preregistered_type.clone(), type_) { 768 self.problems.error(convert_unify_error(error, location)); 769 } 770 771 // Ensure that the current target has an implementation for the function. 772 // This is done at the expression level while inferring the function body, but we do it again 773 // here as externally implemented functions may not have a Gleam body. 774 // 775 // We don't emit this error if there is no implementation, as this would 776 // have already emitted an error above. 777 if has_implementation 778 && publicity.is_importable() 779 && environment.target_support.is_enforced() 780 && !implementations.supports(target) 781 // We don't emit this error if there is a body 782 // since this would be caught at the statement level 783 && !has_body 784 { 785 self.problems.error(Error::UnsupportedPublicFunctionTarget { 786 name: name.clone(), 787 target, 788 location, 789 }); 790 } 791 792 let variant = ValueConstructorVariant::ModuleFn { 793 documentation: doc.as_ref().map(|(_, doc)| doc.clone()), 794 name: name.clone(), 795 external_erlang: external_erlang 796 .as_ref() 797 .map(|(m, f, _)| (m.clone(), f.clone())), 798 external_javascript: external_javascript 799 .as_ref() 800 .map(|(m, f, _)| (m.clone(), f.clone())), 801 external_cranelift: external_javascript 802 .as_ref() 803 .map(|(m, f, _)| (m.clone(), f.clone())), 804 field_map, 805 module: environment.current_module.clone(), 806 arity: typed_arguments.len(), 807 location, 808 implementations, 809 purity, 810 }; 811 812 environment.insert_variable( 813 name.clone(), 814 variant, 815 preregistered_type.clone(), 816 publicity, 817 deprecation.clone(), 818 ); 819 820 environment.references.register_value_reference( 821 environment.current_module.clone(), 822 name.clone(), 823 &name, 824 name_location, 825 ReferenceKind::Definition, 826 ); 827 828 let function = Function { 829 documentation: doc, 830 location, 831 name: Some((name_location, name.clone())), 832 publicity, 833 deprecation, 834 arguments: typed_arguments, 835 body_start, 836 end_position: end_location, 837 return_annotation, 838 return_type: preregistered_type 839 .return_type() 840 .expect("Could not find return type for fn"), 841 body, 842 external_erlang, 843 external_javascript, 844 external_cranelift, 845 implementations, 846 purity, 847 }; 848 849 if let Some(inline_function) = inline::function_to_inlinable( 850 &environment.current_package, 851 &environment.current_module, 852 &function, 853 ) { 854 _ = self.inline_functions.insert(name, inline_function); 855 } 856 857 function 858 } 859 860 fn assert_valid_javascript_external( 861 &mut self, 862 function_name: &EcoString, 863 external_javascript: Option<&(EcoString, EcoString, SrcSpan)>, 864 location: SrcSpan, 865 ) { 866 use regex::Regex; 867 868 let (module, function) = match external_javascript { 869 None => return, 870 Some((module, function, _location)) => (module, function), 871 }; 872 if !EXTERNAL_MODULE_PATTERN 873 .get_or_init(|| Regex::new("^[@a-zA-Z0-9\\./:_-]+$").expect("regex")) 874 .is_match(module) 875 { 876 self.problems.error(Error::InvalidExternalJavascriptModule { 877 location, 878 module: module.clone(), 879 name: function_name.clone(), 880 }); 881 } 882 if !EXTERNAL_FUNCTION_PATTERN 883 .get_or_init(|| Regex::new("^[a-zA-Z_][a-zA-Z0-9_]*$").expect("regex")) 884 .is_match(function) 885 { 886 self.problems 887 .error(Error::InvalidExternalJavascriptFunction { 888 location, 889 function: function.clone(), 890 name: function_name.clone(), 891 }); 892 } 893 } 894 895 fn ensure_annotations_present( 896 &mut self, 897 arguments: &[UntypedArg], 898 return_annotation: Option<&TypeAst>, 899 location: SrcSpan, 900 ) { 901 for arg in arguments { 902 if arg.annotation.is_none() { 903 self.problems.error(Error::ExternalMissingAnnotation { 904 location: arg.location, 905 kind: MissingAnnotation::Parameter, 906 }); 907 } 908 } 909 if return_annotation.is_none() { 910 self.problems.error(Error::ExternalMissingAnnotation { 911 location, 912 kind: MissingAnnotation::Return, 913 }); 914 } 915 } 916 917 fn ensure_function_has_an_implementation( 918 &mut self, 919 body: &[UntypedStatement], 920 external_erlang: &Option<(EcoString, EcoString, SrcSpan)>, 921 external_javascript: &Option<(EcoString, EcoString, SrcSpan)>, 922 location: SrcSpan, 923 ) -> bool { 924 match (external_erlang, external_javascript) { 925 (None, None) if body.is_empty() => { 926 self.problems.error(Error::NoImplementation { location }); 927 false 928 } 929 _ => true, 930 } 931 } 932 933 fn analyse_import( 934 &mut self, 935 i: UntypedImport, 936 environment: &Environment<'_>, 937 ) -> Option<TypedImport> { 938 let Import { 939 documentation, 940 location, 941 module_location, 942 module, 943 as_name, 944 unqualified_values, 945 unqualified_types, 946 .. 947 } = i; 948 // Find imported module 949 let Some(module_info) = environment.importable_modules.get(&module) else { 950 // Here the module being imported doesn't exist. We don't emit an 951 // error here as the `Importer` that was run earlier will have 952 // already emitted an error for this. 953 return None; 954 }; 955 956 // Modules should belong to a package that is a direct dependency of the 957 // current package to be imported. 958 // Upgrade this to an error in future. 959 if module_info.package != GLEAM_CORE_PACKAGE_NAME 960 && module_info.package != self.package_config.name 961 && !self.direct_dependencies.contains_key(&module_info.package) 962 { 963 self.warnings.emit(Warning::TransitiveDependencyImported { 964 location, 965 module: module_info.name.clone(), 966 package: module_info.package.clone(), 967 }); 968 } 969 970 Some(Import { 971 documentation, 972 location, 973 module_location, 974 module, 975 as_name, 976 unqualified_values, 977 unqualified_types, 978 package: module_info.package.clone(), 979 }) 980 } 981 982 fn analyse_custom_type( 983 &mut self, 984 t: UntypedCustomType, 985 environment: &mut Environment<'_>, 986 ) -> Option<TypedCustomType> { 987 match self.do_analyse_custom_type(t, environment) { 988 Ok(custom_type) => Some(custom_type), 989 Err(error) => { 990 self.problems.error(error); 991 None 992 } 993 } 994 } 995 996 // TODO: split this into a new class. 997 fn do_analyse_custom_type( 998 &mut self, 999 t: UntypedCustomType, 1000 environment: &mut Environment<'_>, 1001 ) -> Result<TypedCustomType, Error> { 1002 self.register_values_from_custom_type( 1003 &t, 1004 environment, 1005 &t.parameters.iter().map(|(_, name)| name).collect_vec(), 1006 )?; 1007 1008 let CustomType { 1009 documentation: doc, 1010 location, 1011 end_position, 1012 publicity, 1013 opaque, 1014 name, 1015 name_location, 1016 parameters, 1017 constructors, 1018 deprecation, 1019 external_erlang, 1020 external_javascript, 1021 .. 1022 } = t; 1023 1024 match publicity { 1025 Publicity::Private 1026 | Publicity::Public 1027 | Publicity::Internal { 1028 attribute_location: None, 1029 } => (), 1030 1031 Publicity::Internal { 1032 attribute_location: Some(location), 1033 } => self.track_feature_usage(FeatureKind::InternalAnnotation, location), 1034 } 1035 1036 let constructors: Vec<RecordConstructor<Arc<Type>>> = constructors 1037 .into_iter() 1038 .map( 1039 |RecordConstructor { 1040 location, 1041 name_location, 1042 name, 1043 arguments, 1044 documentation, 1045 deprecation: constructor_deprecation, 1046 }| { 1047 self.check_name_case(name_location, &name, Named::CustomTypeVariant); 1048 if constructor_deprecation.is_deprecated() { 1049 self.track_feature_usage( 1050 FeatureKind::VariantWithDeprecatedAnnotation, 1051 location, 1052 ); 1053 } 1054 1055 let preregistered_fn = environment 1056 .get_variable(&name) 1057 .expect("Could not find preregistered type for function"); 1058 let preregistered_type = preregistered_fn.type_.clone(); 1059 1060 let arguments = match preregistered_type.fn_types() { 1061 Some((arguments_types, _return_type)) => arguments 1062 .into_iter() 1063 .zip(&arguments_types) 1064 .map(|(argument, type_)| { 1065 if let Some((location, label)) = &argument.label { 1066 self.check_name_case(*location, label, Named::Label); 1067 } 1068 1069 RecordConstructorArg { 1070 label: argument.label, 1071 ast: argument.ast, 1072 location: argument.location, 1073 type_: type_.clone(), 1074 doc: argument.doc, 1075 } 1076 }) 1077 .collect(), 1078 _ => { 1079 vec![] 1080 } 1081 }; 1082 1083 RecordConstructor { 1084 location, 1085 name_location, 1086 name, 1087 arguments, 1088 documentation, 1089 deprecation: constructor_deprecation, 1090 } 1091 }, 1092 ) 1093 .collect(); 1094 let typed_parameters = environment 1095 .get_type_constructor(&None, &name) 1096 .expect("Could not find preregistered type constructor") 1097 .parameters 1098 .clone(); 1099 1100 // Check if all constructors are deprecated if so error. 1101 if !constructors.is_empty() 1102 && constructors 1103 .iter() 1104 .all(|record| record.deprecation.is_deprecated()) 1105 { 1106 self.problems 1107 .error(Error::AllVariantsDeprecated { location }); 1108 } 1109 1110 // If any constructor record/varient is deprecated while 1111 // the type is deprecated as a whole that is considered an error. 1112 if deprecation.is_deprecated() 1113 && !constructors.is_empty() 1114 && constructors 1115 .iter() 1116 .any(|record| record.deprecation.is_deprecated()) 1117 { 1118 // Report error on all variants attibuted with deprecated 1119 constructors 1120 .iter() 1121 .filter(|record| record.deprecation.is_deprecated()) 1122 .for_each(|record| { 1123 self.problems 1124 .error(Error::DeprecatedVariantOnDeprecatedType { 1125 location: record.location, 1126 }); 1127 }); 1128 } 1129 1130 if external_erlang.is_some() || external_javascript.is_some() { 1131 self.track_feature_usage(FeatureKind::ExternalCustomType, location); 1132 1133 if !constructors.is_empty() { 1134 self.problems 1135 .error(Error::ExternalTypeWithConstructors { location }); 1136 } 1137 } 1138 1139 Ok(CustomType { 1140 documentation: doc, 1141 location, 1142 end_position, 1143 publicity, 1144 opaque, 1145 name, 1146 name_location, 1147 parameters, 1148 constructors, 1149 typed_parameters, 1150 deprecation, 1151 external_erlang, 1152 external_javascript, 1153 }) 1154 } 1155 1156 fn register_values_from_custom_type( 1157 &mut self, 1158 t: &UntypedCustomType, 1159 environment: &mut Environment<'_>, 1160 type_parameters: &[&EcoString], 1161 ) -> Result<(), Error> { 1162 let CustomType { 1163 publicity, 1164 opaque, 1165 name, 1166 constructors, 1167 deprecation, 1168 .. 1169 } = t; 1170 1171 let mut hydrator = self 1172 .hydrators 1173 .remove(name) 1174 .expect("Could not find hydrator for register_values custom type"); 1175 hydrator.disallow_new_type_variables(); 1176 let type_ = environment 1177 .module_types 1178 .get(name) 1179 .expect("Type for custom type not found in register_values") 1180 .type_ 1181 .clone(); 1182 1183 let mut constructors_data = vec![]; 1184 1185 let mut index = 0; 1186 for constructor in constructors.iter() { 1187 if let Err(error) = assert_unique_name( 1188 &mut self.value_names, 1189 &constructor.name, 1190 constructor.location, 1191 ) { 1192 self.problems.error(error); 1193 continue; 1194 } 1195 1196 // If the constructor belongs to an opaque type then it's going to be 1197 // considered as private. 1198 let value_constructor_publicity = if *opaque { 1199 Publicity::Private 1200 } else { 1201 *publicity 1202 }; 1203 1204 environment.references.register_value( 1205 constructor.name.clone(), 1206 EntityKind::Constructor, 1207 constructor.location, 1208 value_constructor_publicity, 1209 ); 1210 1211 environment 1212 .references 1213 .register_type_reference_in_call_graph(name.clone()); 1214 1215 let mut field_map_builder = FieldMapBuilder::new(constructor.arguments.len() as u32); 1216 let mut arguments_types = Vec::with_capacity(constructor.arguments.len()); 1217 let mut fields = Vec::with_capacity(constructor.arguments.len()); 1218 1219 for RecordConstructorArg { 1220 label, 1221 ast, 1222 location, 1223 doc, 1224 .. 1225 } in constructor.arguments.iter() 1226 { 1227 // Build a type from the annotation AST 1228 let t = match hydrator.type_from_ast(ast, environment, &mut self.problems) { 1229 Ok(t) => t, 1230 Err(e) => { 1231 self.problems.error(e); 1232 environment.new_unbound_var() 1233 } 1234 }; 1235 1236 fields.push(TypeValueConstructorField { 1237 type_: t.clone(), 1238 label: label.as_ref().map(|(_location, label)| label.clone()), 1239 documentation: doc.as_ref().map(|(_, documentation)| documentation.clone()), 1240 }); 1241 1242 // Register the type for this parameter 1243 arguments_types.push(t); 1244 1245 let (label_location, label) = match label { 1246 Some((location, label)) => (*location, Some(label)), 1247 None => (*location, None), 1248 }; 1249 1250 if let Some(label) = label { 1251 environment.references.register_label_definition( 1252 (environment.current_module.clone(), name.clone()), 1253 label.clone(), 1254 label_location, 1255 constructor.name.clone(), 1256 ); 1257 } 1258 1259 // Register the label for this parameter 1260 if let Err(error) = field_map_builder.add(label, label_location) { 1261 self.problems.error(error); 1262 } 1263 } 1264 let field_map = field_map_builder.finish(); 1265 // Insert constructor function into module scope 1266 let mut type_ = type_.deref().clone(); 1267 type_.set_custom_type_variant(index as u16); 1268 let type_ = match constructor.arguments.len() { 1269 0 => Arc::new(type_), 1270 _ => fn_(arguments_types.clone(), Arc::new(type_)), 1271 }; 1272 let constructor_info = ValueConstructorVariant::Record { 1273 documentation: constructor 1274 .documentation 1275 .as_ref() 1276 .map(|(_, doc)| doc.clone()), 1277 variants_count: constructors.len() as u16, 1278 name: constructor.name.clone(), 1279 arity: constructor.arguments.len() as u16, 1280 field_map: field_map.clone(), 1281 location: constructor.location, 1282 module: self.module_name.clone(), 1283 variant_index: index as u16, 1284 }; 1285 index += 1; 1286 1287 // If the whole custom type is deprecated all of its varints are too. 1288 // Otherwise just the varint(s) attributed as deprecated are. 1289 let deprecate_constructor = if deprecation.is_deprecated() { 1290 deprecation 1291 } else { 1292 &constructor.deprecation 1293 }; 1294 1295 environment.insert_module_value( 1296 constructor.name.clone(), 1297 ValueConstructor { 1298 publicity: value_constructor_publicity, 1299 deprecation: deprecate_constructor.clone(), 1300 type_: type_.clone(), 1301 variant: constructor_info.clone(), 1302 }, 1303 ); 1304 1305 environment.references.register_value_reference( 1306 environment.current_module.clone(), 1307 constructor.name.clone(), 1308 &constructor.name, 1309 constructor.name_location, 1310 ReferenceKind::Definition, 1311 ); 1312 1313 constructors_data.push(TypeValueConstructor { 1314 name: constructor.name.clone(), 1315 parameters: fields, 1316 documentation: constructor 1317 .documentation 1318 .as_ref() 1319 .map(|(_, documentation)| documentation.clone()), 1320 }); 1321 environment.insert_variable( 1322 constructor.name.clone(), 1323 constructor_info, 1324 type_, 1325 value_constructor_publicity, 1326 deprecate_constructor.clone(), 1327 ); 1328 1329 environment.names.named_constructor_in_scope( 1330 environment.current_module.clone(), 1331 constructor.name.clone(), 1332 constructor.name.clone(), 1333 ); 1334 } 1335 1336 let Accessors { 1337 shared_accessors, 1338 variant_specific_accessors, 1339 positional_accessors, 1340 } = custom_type_accessors(&constructors_data)?; 1341 1342 let map = AccessorsMap { 1343 publicity: if *opaque { 1344 Publicity::Private 1345 } else { 1346 *publicity 1347 }, 1348 shared_accessors, 1349 // TODO: improve the ownership here so that we can use the 1350 // `return_type_constructor` below rather than looking it up twice. 1351 type_, 1352 variant_specific_accessors, 1353 variant_positional_accessors: positional_accessors, 1354 }; 1355 environment.insert_accessors(name.clone(), map); 1356 1357 let opaque = if *opaque { 1358 Opaque::Opaque 1359 } else { 1360 Opaque::NotOpaque 1361 }; 1362 // Now record the constructors for the type. 1363 environment.insert_type_to_constructors( 1364 name.clone(), 1365 TypeVariantConstructors::new(constructors_data, type_parameters, opaque, hydrator), 1366 ); 1367 1368 Ok(()) 1369 } 1370 1371 fn register_types_from_custom_type( 1372 &mut self, 1373 t: &UntypedCustomType, 1374 environment: &mut Environment<'a>, 1375 ) -> Result<(), Error> { 1376 let CustomType { 1377 name, 1378 name_location, 1379 publicity, 1380 parameters, 1381 location, 1382 deprecation, 1383 opaque, 1384 constructors, 1385 documentation, 1386 .. 1387 } = t; 1388 // We exit early here as we don't yet have a good way to handle the two 1389 // duplicate definitions in the later pass of the analyser which 1390 // register the constructor values for the types. The latter would end up 1391 // overwriting the former, but here in type registering we keep the 1392 // former. I think we want to really keep the former both times. 1393 // The fact we can't straightforwardly do this indicated to me that we 1394 // could improve our approach here somewhat. 1395 environment.assert_unique_type_name(name, *location)?; 1396 1397 self.check_name_case(*name_location, name, Named::Type); 1398 1399 let mut hydrator = Hydrator::new(); 1400 let parameters = self.make_type_vars(parameters, &mut hydrator, environment); 1401 1402 hydrator.clear_ridgid_type_names(); 1403 1404 // We check is the type comes from an internal module and restrict its 1405 // publicity. 1406 let publicity = match publicity { 1407 // It's important we only restrict the publicity of public types. 1408 Publicity::Public if self.package_config.is_internal_module(&self.module_name) => { 1409 Publicity::Internal { 1410 attribute_location: None, 1411 } 1412 } 1413 // If a type is private we don't want to make it internal just because 1414 // it comes from an internal module, so in that case the publicity is 1415 // left unchanged. 1416 Publicity::Public | Publicity::Private | Publicity::Internal { .. } => *publicity, 1417 }; 1418 1419 let type_ = Arc::new(Type::Named { 1420 publicity, 1421 package: environment.current_package.clone(), 1422 module: self.module_name.to_owned(), 1423 name: name.clone(), 1424 arguments: parameters.clone(), 1425 inferred_variant: None, 1426 }); 1427 let _ = self.hydrators.insert(name.clone(), hydrator); 1428 environment 1429 .insert_type_constructor( 1430 name.clone(), 1431 TypeConstructor { 1432 origin: *location, 1433 module: self.module_name.clone(), 1434 deprecation: deprecation.clone(), 1435 parameters, 1436 publicity, 1437 type_, 1438 documentation: documentation.as_ref().map(|(_, doc)| doc.clone()), 1439 }, 1440 ) 1441 .expect("name uniqueness checked above"); 1442 1443 environment.names.named_type_in_scope( 1444 environment.current_module.clone(), 1445 name.clone(), 1446 name.clone(), 1447 ); 1448 1449 environment 1450 .references 1451 .register_type(name.clone(), EntityKind::Type, *location, publicity); 1452 1453 environment.references.register_type_reference( 1454 environment.current_module.clone(), 1455 name.clone(), 1456 name, 1457 *name_location, 1458 ReferenceKind::Definition, 1459 ); 1460 1461 if *opaque && constructors.is_empty() { 1462 self.problems.warning(Warning::OpaqueExternalType { 1463 location: *location, 1464 }); 1465 } 1466 1467 if *opaque && publicity.is_private() { 1468 self.problems.error(Error::PrivateOpaqueType { 1469 location: SrcSpan { 1470 start: location.start, 1471 end: location.start + 6, 1472 }, 1473 }); 1474 } 1475 1476 Ok(()) 1477 } 1478 1479 fn register_type_alias(&mut self, t: &UntypedTypeAlias, environment: &mut Environment<'_>) { 1480 let TypeAlias { 1481 location, 1482 publicity, 1483 parameters: arguments, 1484 alias: name, 1485 name_location, 1486 type_ast: resolved_type, 1487 deprecation, 1488 type_: _, 1489 documentation, 1490 } = t; 1491 1492 // A type alias must not have the same name as any other type in the module. 1493 if let Err(error) = environment.assert_unique_type_name(name, *location) { 1494 self.problems.error(error); 1495 // A type already exists with the name so we cannot continue and 1496 // register this new type with the same name. 1497 return; 1498 } 1499 1500 self.check_name_case(*name_location, name, Named::TypeAlias); 1501 1502 environment 1503 .references 1504 .register_type(name.clone(), EntityKind::Type, *location, *publicity); 1505 1506 // Use the hydrator to convert the AST into a type, erroring if the AST was invalid 1507 // in some fashion. 1508 let mut hydrator = Hydrator::new(); 1509 let parameters = self.make_type_vars(arguments, &mut hydrator, environment); 1510 let arity = parameters.len(); 1511 let tryblock = || { 1512 hydrator.disallow_new_type_variables(); 1513 let type_ = hydrator.type_from_ast(resolved_type, environment, &mut self.problems)?; 1514 1515 environment 1516 .names 1517 .type_in_scope(name.clone(), type_.as_ref(), &parameters); 1518 1519 // Insert the alias so that it can be used by other code. 1520 environment.insert_type_constructor( 1521 name.clone(), 1522 TypeConstructor { 1523 origin: *location, 1524 module: self.module_name.clone(), 1525 parameters: parameters.clone(), 1526 type_: type_.clone(), 1527 deprecation: deprecation.clone(), 1528 publicity: *publicity, 1529 documentation: documentation.as_ref().map(|(_, doc)| doc.clone()), 1530 }, 1531 )?; 1532 1533 let alias = TypeAliasConstructor { 1534 origin: *location, 1535 module: self.module_name.clone(), 1536 type_, 1537 publicity: *publicity, 1538 deprecation: deprecation.clone(), 1539 documentation: documentation.as_ref().map(|(_, doc)| doc.clone()), 1540 arity, 1541 parameters, 1542 }; 1543 1544 environment.names.maybe_register_reexport_alias( 1545 &environment.current_package, 1546 name, 1547 &alias, 1548 ); 1549 1550 environment.insert_type_alias(name.clone(), alias)?; 1551 1552 if let Some(name) = hydrator.unused_type_variables().next() { 1553 return Err(Error::UnusedTypeAliasParameter { 1554 location: *location, 1555 name: name.clone(), 1556 }); 1557 } 1558 1559 Ok(()) 1560 }; 1561 let result = tryblock(); 1562 self.record_if_error(result); 1563 } 1564 1565 fn make_type_vars( 1566 &mut self, 1567 arguments: &[SpannedString], 1568 hydrator: &mut Hydrator, 1569 environment: &mut Environment<'_>, 1570 ) -> Vec<Arc<Type>> { 1571 arguments 1572 .iter() 1573 .map(|(location, name)| { 1574 self.check_name_case(*location, name, Named::TypeVariable); 1575 match hydrator.add_type_variable(name, environment) { 1576 Ok(t) => t, 1577 Err(t) => { 1578 self.problems.error(Error::DuplicateTypeParameter { 1579 location: *location, 1580 name: name.clone(), 1581 }); 1582 t 1583 } 1584 } 1585 }) 1586 .collect() 1587 } 1588 1589 fn record_if_error(&mut self, result: Result<(), Error>) { 1590 if let Err(error) = result { 1591 self.problems.error(error); 1592 } 1593 } 1594 1595 fn register_value_from_function( 1596 &mut self, 1597 f: &UntypedFunction, 1598 environment: &mut Environment<'_>, 1599 ) { 1600 let Function { 1601 name, 1602 arguments, 1603 location, 1604 return_annotation, 1605 publicity, 1606 documentation, 1607 external_erlang, 1608 external_javascript, 1609 external_cranelift, 1610 deprecation, 1611 end_position: _, 1612 body: _, 1613 body_start: _, 1614 return_type: _, 1615 implementations, 1616 purity, 1617 } = f; 1618 let (name_location, name) = name.as_ref().expect("A module's function must be named"); 1619 1620 self.check_name_case(*name_location, name, Named::Function); 1621 // If the function's name matches an unqualified import, emit a warning: 1622 self.check_shadow_import(name, f.location, environment); 1623 1624 environment.references.register_value( 1625 name.clone(), 1626 EntityKind::Function, 1627 *location, 1628 *publicity, 1629 ); 1630 1631 let mut builder = FieldMapBuilder::new(arguments.len() as u32); 1632 for Arg { 1633 names, location, .. 1634 } in arguments.iter() 1635 { 1636 check_argument_names(names, &mut self.problems); 1637 1638 if let Err(error) = builder.add(names.get_label(), *location) { 1639 self.problems.error(error); 1640 } 1641 } 1642 let field_map = builder.finish(); 1643 let mut hydrator = Hydrator::new(); 1644 1645 // When external implementations are present then the type annotations 1646 // must be given in full, so we disallow holes in the annotations. 1647 hydrator.permit_holes(external_erlang.is_none() && external_javascript.is_none()); 1648 1649 let arguments_types = arguments 1650 .iter() 1651 .map(|argument| { 1652 match hydrator.type_from_option_ast( 1653 &argument.annotation, 1654 environment, 1655 &mut self.problems, 1656 ) { 1657 Ok(type_) => type_, 1658 Err(error) => { 1659 self.problems.error(error); 1660 environment.new_unbound_var() 1661 } 1662 } 1663 }) 1664 .collect(); 1665 1666 let return_type = 1667 match hydrator.type_from_option_ast(return_annotation, environment, &mut self.problems) 1668 { 1669 Ok(type_) => type_, 1670 Err(error) => { 1671 self.problems.error(error); 1672 environment.new_unbound_var() 1673 } 1674 }; 1675 1676 let type_ = fn_(arguments_types, return_type); 1677 let _ = self.hydrators.insert(name.clone(), hydrator); 1678 1679 let variant = ValueConstructorVariant::ModuleFn { 1680 documentation: documentation.as_ref().map(|(_, doc)| doc.clone()), 1681 name: name.clone(), 1682 field_map, 1683 external_erlang: external_erlang 1684 .as_ref() 1685 .map(|(m, f, _)| (m.clone(), f.clone())), 1686 external_javascript: external_javascript 1687 .as_ref() 1688 .map(|(m, f, _)| (m.clone(), f.clone())), 1689 external_cranelift: external_cranelift 1690 .as_ref() 1691 .map(|(m, f, _)| (m.clone(), f.clone())), 1692 module: environment.current_module.clone(), 1693 arity: arguments.len(), 1694 location: *location, 1695 implementations: *implementations, 1696 purity: *purity, 1697 }; 1698 environment.insert_variable( 1699 name.clone(), 1700 variant, 1701 type_, 1702 *publicity, 1703 deprecation.clone(), 1704 ); 1705 } 1706 1707 fn check_for_type_leaks(&mut self, value: &ValueConstructor) { 1708 // A private value doesn't export anything so it can't leak anything. 1709 if value.publicity.is_private() { 1710 return; 1711 } 1712 1713 // If a private or internal value references a private type 1714 if let Some(leaked) = value.type_.find_private_type() { 1715 self.problems.error(Error::PrivateTypeLeak { 1716 location: value.variant.definition_location(), 1717 leaked, 1718 }); 1719 } 1720 } 1721 1722 fn check_name_case(&mut self, location: SrcSpan, name: &EcoString, kind: Named) { 1723 if let Err(error) = check_name_case(location, name, kind) { 1724 self.problems.error(error); 1725 } 1726 } 1727 1728 fn track_feature_usage(&mut self, feature_kind: FeatureKind, location: SrcSpan) { 1729 let minimum_required_version = feature_kind.required_version(); 1730 1731 // Then if the required version is not in the specified version for the 1732 // range we emit a warning highlighting the usage of the feature. 1733 if let Some(gleam_version) = &self.package_config.gleam_version 1734 && let Some(lowest_allowed_version) = gleam_version.lowest_version() 1735 { 1736 // There is a version in the specified range that is lower than 1737 // the one required by this feature! This means that the 1738 // specified range is wrong and would allow someone to run a 1739 // compiler that is too old to know of this feature. 1740 if minimum_required_version > lowest_allowed_version { 1741 self.problems 1742 .warning(Warning::FeatureRequiresHigherGleamVersion { 1743 location, 1744 feature_kind, 1745 minimum_required_version: minimum_required_version.clone(), 1746 wrongfully_allowed_version: lowest_allowed_version, 1747 }); 1748 } 1749 } 1750 1751 if minimum_required_version > self.minimum_required_version { 1752 self.minimum_required_version = minimum_required_version; 1753 } 1754 } 1755 1756 fn check_shadow_import( 1757 &mut self, 1758 name: &EcoString, 1759 location: SrcSpan, 1760 environment: &mut Environment<'_>, 1761 ) { 1762 if environment.unqualified_imported_names.contains_key(name) { 1763 self.problems 1764 .warning(Warning::TopLevelDefinitionShadowsImport { 1765 location, 1766 name: name.clone(), 1767 }); 1768 } 1769 } 1770} 1771 1772fn validate_module_name(name: &EcoString) -> Result<(), Error> { 1773 if is_prelude_module(name) { 1774 return Err(Error::ReservedModuleName { name: name.clone() }); 1775 } 1776 for segment in name.split('/') { 1777 if crate::parse::lexer::string_to_keyword(segment).is_some() { 1778 return Err(Error::KeywordInModuleName { 1779 name: name.clone(), 1780 keyword: segment.into(), 1781 }); 1782 } 1783 } 1784 Ok(()) 1785} 1786 1787fn target_function_implementation<'a>( 1788 target: Target, 1789 external_erlang: &'a Option<(EcoString, EcoString, SrcSpan)>, 1790 external_javascript: &'a Option<(EcoString, EcoString, SrcSpan)>, 1791 external_cranelift: &'a Option<(EcoString, EcoString, SrcSpan)>, 1792) -> &'a Option<(EcoString, EcoString, SrcSpan)> { 1793 match target { 1794 Target::Erlang => external_erlang, 1795 Target::JavaScript => external_javascript, 1796 Target::Cranelift => external_cranelift, 1797 } 1798} 1799 1800fn analyse_type_alias(t: UntypedTypeAlias, environment: &mut Environment<'_>) -> TypedTypeAlias { 1801 let TypeAlias { 1802 documentation: doc, 1803 location, 1804 publicity, 1805 alias, 1806 name_location, 1807 parameters: arguments, 1808 type_ast: resolved_type, 1809 deprecation, 1810 .. 1811 } = t; 1812 1813 // There could be no type alias registered if it was invalid in some way. 1814 // analysis aims to be fault tolerant to get the best possible feedback for 1815 // the programmer in the language server, so the analyser gets here even 1816 // though there was previously errors. 1817 let type_ = match environment.get_type_constructor(&None, &alias) { 1818 Ok(constructor) => constructor.type_.clone(), 1819 Err(_) => environment.new_generic_var(), 1820 }; 1821 1822 TypeAlias { 1823 documentation: doc, 1824 location, 1825 publicity, 1826 alias, 1827 name_location, 1828 parameters: arguments, 1829 type_ast: resolved_type, 1830 type_, 1831 deprecation, 1832 } 1833} 1834 1835pub fn infer_bit_array_option<UntypedValue, TypedValue, Typer>( 1836 segment_option: BitArrayOption<UntypedValue>, 1837 mut type_check: Typer, 1838) -> Result<BitArrayOption<TypedValue>, Error> 1839where 1840 Typer: FnMut(UntypedValue, Arc<Type>) -> Result<TypedValue, Error>, 1841{ 1842 match segment_option { 1843 BitArrayOption::Size { 1844 value, 1845 location, 1846 short_form, 1847 .. 1848 } => { 1849 let value = type_check(*value, int())?; 1850 Ok(BitArrayOption::Size { 1851 location, 1852 short_form, 1853 value: Box::new(value), 1854 }) 1855 } 1856 1857 BitArrayOption::Unit { location, value } => Ok(BitArrayOption::Unit { location, value }), 1858 1859 BitArrayOption::Bytes { location } => Ok(BitArrayOption::Bytes { location }), 1860 BitArrayOption::Int { location } => Ok(BitArrayOption::Int { location }), 1861 BitArrayOption::Float { location } => Ok(BitArrayOption::Float { location }), 1862 BitArrayOption::Bits { location } => Ok(BitArrayOption::Bits { location }), 1863 BitArrayOption::Utf8 { location } => Ok(BitArrayOption::Utf8 { location }), 1864 BitArrayOption::Utf16 { location } => Ok(BitArrayOption::Utf16 { location }), 1865 BitArrayOption::Utf32 { location } => Ok(BitArrayOption::Utf32 { location }), 1866 BitArrayOption::Utf8Codepoint { location } => { 1867 Ok(BitArrayOption::Utf8Codepoint { location }) 1868 } 1869 BitArrayOption::Utf16Codepoint { location } => { 1870 Ok(BitArrayOption::Utf16Codepoint { location }) 1871 } 1872 BitArrayOption::Utf32Codepoint { location } => { 1873 Ok(BitArrayOption::Utf32Codepoint { location }) 1874 } 1875 BitArrayOption::Signed { location } => Ok(BitArrayOption::Signed { location }), 1876 BitArrayOption::Unsigned { location } => Ok(BitArrayOption::Unsigned { location }), 1877 BitArrayOption::Big { location } => Ok(BitArrayOption::Big { location }), 1878 BitArrayOption::Little { location } => Ok(BitArrayOption::Little { location }), 1879 BitArrayOption::Native { location } => Ok(BitArrayOption::Native { location }), 1880 } 1881} 1882 1883fn generalise_module_constant( 1884 constant: ModuleConstant<Arc<Type>>, 1885 environment: &mut Environment<'_>, 1886 module_name: &EcoString, 1887) -> TypedModuleConstant { 1888 let ModuleConstant { 1889 documentation: doc, 1890 location, 1891 name, 1892 name_location, 1893 annotation, 1894 publicity, 1895 value, 1896 type_, 1897 deprecation, 1898 implementations, 1899 } = constant; 1900 let type_ = type_::generalise(type_); 1901 let variant = ValueConstructorVariant::ModuleConstant { 1902 documentation: doc.as_ref().map(|(_, doc)| doc.clone()), 1903 location, 1904 literal: *value.clone(), 1905 module: module_name.clone(), 1906 implementations, 1907 name: name.clone(), 1908 }; 1909 environment.insert_variable( 1910 name.clone(), 1911 variant.clone(), 1912 type_.clone(), 1913 publicity, 1914 deprecation.clone(), 1915 ); 1916 1917 environment.insert_module_value( 1918 name.clone(), 1919 ValueConstructor { 1920 publicity, 1921 variant, 1922 deprecation: deprecation.clone(), 1923 type_: type_.clone(), 1924 }, 1925 ); 1926 1927 ModuleConstant { 1928 documentation: doc, 1929 location, 1930 name, 1931 name_location, 1932 annotation, 1933 publicity, 1934 value, 1935 type_, 1936 deprecation, 1937 implementations, 1938 } 1939} 1940 1941fn generalise_function( 1942 function: TypedFunction, 1943 environment: &mut Environment<'_>, 1944 module_name: &EcoString, 1945) -> TypedFunction { 1946 let Function { 1947 documentation: doc, 1948 location, 1949 name, 1950 publicity, 1951 deprecation, 1952 arguments, 1953 body, 1954 return_annotation, 1955 end_position: end_location, 1956 body_start, 1957 return_type, 1958 external_erlang, 1959 external_javascript, 1960 external_cranelift, 1961 implementations, 1962 purity, 1963 } = function; 1964 1965 let (name_location, name) = name.expect("Function in a definition must be named"); 1966 1967 // Lookup the inferred function information 1968 let function = environment 1969 .get_variable(&name) 1970 .expect("Could not find preregistered type for function"); 1971 let field_map = function.field_map().cloned(); 1972 let type_ = function.type_.clone(); 1973 1974 let type_ = type_::generalise(type_); 1975 1976 // Insert the function into the module's interface 1977 let variant = ValueConstructorVariant::ModuleFn { 1978 documentation: doc.as_ref().map(|(_, doc)| doc.clone()), 1979 name: name.clone(), 1980 field_map, 1981 external_erlang: external_erlang 1982 .as_ref() 1983 .map(|(m, f, _)| (m.clone(), f.clone())), 1984 external_javascript: external_javascript 1985 .as_ref() 1986 .map(|(m, f, _)| (m.clone(), f.clone())), 1987 external_cranelift: external_javascript 1988 .as_ref() 1989 .map(|(m, f, _)| (m.clone(), f.clone())), 1990 module: module_name.clone(), 1991 arity: arguments.len(), 1992 location, 1993 implementations, 1994 purity, 1995 }; 1996 environment.insert_variable( 1997 name.clone(), 1998 variant.clone(), 1999 type_.clone(), 2000 publicity, 2001 deprecation.clone(), 2002 ); 2003 environment.insert_module_value( 2004 name.clone(), 2005 ValueConstructor { 2006 publicity, 2007 deprecation: deprecation.clone(), 2008 type_, 2009 variant, 2010 }, 2011 ); 2012 2013 Function { 2014 documentation: doc, 2015 location, 2016 name: Some((name_location, name)), 2017 publicity, 2018 deprecation, 2019 arguments, 2020 end_position: end_location, 2021 body_start, 2022 return_annotation, 2023 return_type, 2024 body, 2025 external_erlang, 2026 external_javascript, 2027 external_cranelift, 2028 implementations, 2029 purity, 2030 } 2031} 2032 2033fn assert_unique_name( 2034 names: &mut HashMap<EcoString, SrcSpan>, 2035 name: &EcoString, 2036 location: SrcSpan, 2037) -> Result<(), Error> { 2038 match names.insert(name.clone(), location) { 2039 Some(previous_location) => Err(Error::DuplicateName { 2040 location_a: location, 2041 location_b: previous_location, 2042 name: name.clone(), 2043 }), 2044 None => Ok(()), 2045 } 2046} 2047 2048struct Accessors { 2049 shared_accessors: HashMap<EcoString, RecordAccessor>, 2050 variant_specific_accessors: Vec<HashMap<EcoString, RecordAccessor>>, 2051 positional_accessors: Vec<Vec<Arc<Type>>>, 2052} 2053 2054fn custom_type_accessors(constructors: &[TypeValueConstructor]) -> Result<Accessors, Error> { 2055 let accessors = get_compatible_record_fields(constructors); 2056 2057 let mut shared_accessors = HashMap::with_capacity(accessors.len()); 2058 2059 for accessor in accessors { 2060 let _ = shared_accessors.insert(accessor.label.clone(), accessor); 2061 } 2062 2063 let mut variant_specific_accessors = Vec::with_capacity(constructors.len()); 2064 let mut positional_accessors = Vec::with_capacity(constructors.len()); 2065 2066 for constructor in constructors { 2067 let mut fields = HashMap::with_capacity(constructor.parameters.len()); 2068 let mut positional_fields = Vec::new(); 2069 2070 for (index, parameter) in constructor.parameters.iter().enumerate() { 2071 if let Some(label) = &parameter.label { 2072 _ = fields.insert( 2073 label.clone(), 2074 RecordAccessor { 2075 index: index as u64, 2076 label: label.clone(), 2077 type_: parameter.type_.clone(), 2078 documentation: parameter.documentation.clone(), 2079 }, 2080 ); 2081 } else { 2082 positional_fields.push(parameter.type_.clone()); 2083 } 2084 } 2085 variant_specific_accessors.push(fields); 2086 positional_accessors.push(positional_fields); 2087 } 2088 2089 Ok(Accessors { 2090 shared_accessors, 2091 variant_specific_accessors, 2092 positional_accessors, 2093 }) 2094} 2095 2096/// Returns the fields that have the same label and type across all variants of 2097/// the given type. 2098fn get_compatible_record_fields(constructors: &[TypeValueConstructor]) -> Vec<RecordAccessor> { 2099 let mut compatible = vec![]; 2100 2101 let first = match constructors.first() { 2102 Some(first) => first, 2103 None => return compatible, 2104 }; 2105 2106 'next_argument: for (index, first_parameter) in first.parameters.iter().enumerate() { 2107 // Fields without labels do not have accessors 2108 let first_label = match first_parameter.label.as_ref() { 2109 Some(label) => label, 2110 None => continue 'next_argument, 2111 }; 2112 2113 let mut documentation = if constructors.len() == 1 { 2114 // If there is only one constructor, we simply show the documentation 2115 // for the field. 2116 first_parameter.documentation.clone() 2117 } else { 2118 // If there are multiple constructors, we show the documentation of 2119 // this field for each of the variants. 2120 first_parameter 2121 .documentation 2122 .as_ref() 2123 .map(|field_documentation| { 2124 eco_format!("## {}\n\n{}", first.name, field_documentation) 2125 }) 2126 }; 2127 2128 // Check each variant to see if they have an field in the same position 2129 // with the same label and the same type 2130 for constructor in constructors.iter().skip(1) { 2131 // The field must exist in all variants 2132 let parameter = match constructor.parameters.get(index) { 2133 Some(argument) => argument, 2134 None => continue 'next_argument, 2135 }; 2136 2137 // The labels must be the same 2138 if parameter 2139 .label 2140 .as_ref() 2141 .is_none_or(|arg_label| arg_label != first_label) 2142 { 2143 continue 'next_argument; 2144 } 2145 2146 // The types must be the same 2147 if !parameter.type_.same_as(&first_parameter.type_) { 2148 continue 'next_argument; 2149 } 2150 2151 if let Some(field_documentation) = &parameter.documentation { 2152 let field_documentation = 2153 eco_format!("## {}\n\n{}", constructor.name, field_documentation); 2154 2155 match &mut documentation { 2156 None => { 2157 documentation = Some(field_documentation); 2158 } 2159 Some(documentation) => { 2160 documentation.push('\n'); 2161 documentation.push_str(&field_documentation); 2162 } 2163 } 2164 } 2165 } 2166 2167 // The previous loop did not find any incompatible fields in the other 2168 // variants so this field is compatible across variants and we should 2169 // generate an accessor for it. 2170 2171 compatible.push(RecordAccessor { 2172 index: index as u64, 2173 label: first_label.clone(), 2174 type_: first_parameter.type_.clone(), 2175 documentation, 2176 }); 2177 } 2178 2179 compatible 2180} 2181 2182/// Given a type, return a list of all the types it depends on 2183fn get_type_dependencies(type_: &TypeAst) -> Vec<EcoString> { 2184 let mut deps = Vec::with_capacity(1); 2185 2186 match type_ { 2187 TypeAst::Var(TypeAstVar { .. }) => (), 2188 TypeAst::Hole(TypeAstHole { .. }) => (), 2189 TypeAst::Constructor(TypeAstConstructor { 2190 name, arguments, .. 2191 }) => { 2192 deps.push(match name { 2193 ast::TypeAstConstructorName::Unqualified { name, .. } => name.clone(), 2194 ast::TypeAstConstructorName::Qualified { 2195 module, 2196 name: Some((name, _)), 2197 .. 2198 } => format!("{module}.{name}").into(), 2199 ast::TypeAstConstructorName::Qualified { 2200 module, name: None, .. 2201 } => format!("{module}.").into(), 2202 }); 2203 2204 for arg in arguments { 2205 deps.extend(get_type_dependencies(arg)); 2206 } 2207 } 2208 TypeAst::Fn(TypeAstFn { 2209 arguments, return_, .. 2210 }) => { 2211 for arg in arguments { 2212 deps.extend(get_type_dependencies(arg)); 2213 } 2214 deps.extend(get_type_dependencies(return_)); 2215 } 2216 TypeAst::Tuple(TypeAstTuple { elements, .. }) => { 2217 for element in elements { 2218 deps.extend(get_type_dependencies(element)); 2219 } 2220 } 2221 } 2222 2223 deps 2224} 2225 2226fn sorted_type_aliases(aliases: &Vec<UntypedTypeAlias>) -> Result<Vec<&UntypedTypeAlias>, Error> { 2227 let mut deps: Vec<(EcoString, Vec<EcoString>)> = Vec::with_capacity(aliases.len()); 2228 2229 for alias in aliases { 2230 deps.push((alias.alias.clone(), get_type_dependencies(&alias.type_ast))); 2231 } 2232 2233 let sorted_deps = dep_tree::toposort_deps(deps).map_err(|err| { 2234 let dep_tree::Error::Cycle(cycle) = err; 2235 2236 let last = cycle.last().expect("Cycle should not be empty"); 2237 let alias = aliases 2238 .iter() 2239 .find(|alias| alias.alias == *last) 2240 .expect("Could not find alias for cycle"); 2241 2242 Error::RecursiveTypeAlias { 2243 cycle, 2244 location: alias.location, 2245 } 2246 })?; 2247 2248 Ok(aliases 2249 .iter() 2250 .sorted_by_key(|alias| sorted_deps.iter().position(|x| x == &alias.alias)) 2251 .collect()) 2252}