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

Configure Feed

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

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