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