Fork of daniellemaywood.uk/gleam — Wasm codegen work
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(), ¶meters);
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) = ¶meter.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) = ¶meter.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}