Thread down environment module from cli down to the type-checker
We simply provide a flag with a free-form output which acts as
the module to lookup in the 'env' folder. The strategy is to replace
the environment module name on-the-fly when a user tries to import
'env'.
If the environment isn't found, an 'UnknownModule' error is raised
(which I will slightly adjust in a following commits to something more
related to environment)
There are few important consequences to this design which may not seem
immediately obvious:
1. We parse and type-check every env modules, even if they aren't
used. This ensures that code doesn't break with a compilation error
simply because people forgot to type-check a given env.
Note that compilation could still fail because the env module
itself could provide an invalid API. So it only prevents each
modules to be independently wrong when taken in isolation.
2. Technically, this also means that one can import env modules in
other env modules by their names. I don't know if it's a good or
bad idea at this point but it doesn't really do any wrong;
dependencies and cycles are handlded all-the-same.
This commit is contained in:
@@ -21,6 +21,9 @@ pub const BACKPASS_VARIABLE: &str = "_backpass";
|
||||
pub const CAPTURE_VARIABLE: &str = "_capture";
|
||||
pub const PIPE_VARIABLE: &str = "_pipe";
|
||||
|
||||
pub const ENV_MODULE: &str = "env";
|
||||
pub const DEFAULT_ENV_MODULE: &str = "default";
|
||||
|
||||
pub type TypedModule = Module<TypeInfo, TypedDefinition>;
|
||||
pub type UntypedModule = Module<(), UntypedDefinition>;
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ macro_rules! aiken_fn {
|
||||
$module_types,
|
||||
$crate::ast::Tracing::silent(),
|
||||
&mut warnings,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ fn check_module(
|
||||
&module_types,
|
||||
Tracing::All(TraceLevel::Verbose),
|
||||
&mut warnings,
|
||||
None,
|
||||
)
|
||||
.expect("extra dependency did not compile");
|
||||
module_types.insert(package.clone(), typed_module.type_info.clone());
|
||||
@@ -50,6 +51,7 @@ fn check_module(
|
||||
&module_types,
|
||||
tracing,
|
||||
&mut warnings,
|
||||
None,
|
||||
);
|
||||
|
||||
result
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
ast::{
|
||||
Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind,
|
||||
self, Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind,
|
||||
RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition, TypedFunction,
|
||||
TypedPattern, UnqualifiedImport, UntypedArg, UntypedDefinition, UntypedFunction, Use,
|
||||
Validator, PIPE_VARIABLE,
|
||||
@@ -80,11 +80,33 @@ pub struct Environment<'a> {
|
||||
/// A mapping from known annotations to their resolved type.
|
||||
pub annotations: HashMap<Annotation, Rc<Type>>,
|
||||
|
||||
/// The user-defined target environment referred to as the module 'env'.
|
||||
pub target_env: Option<&'a str>,
|
||||
|
||||
/// Warnings
|
||||
pub warnings: &'a mut Vec<Warning>,
|
||||
}
|
||||
|
||||
impl<'a> Environment<'a> {
|
||||
pub fn find_module(&self, fragments: &[String], location: Span) -> Result<&'a TypeInfo, Error> {
|
||||
let mut name = fragments.join("/");
|
||||
|
||||
if name == ast::ENV_MODULE {
|
||||
name = self
|
||||
.target_env
|
||||
.unwrap_or(ast::DEFAULT_ENV_MODULE)
|
||||
.to_string()
|
||||
}
|
||||
|
||||
self.importable_modules
|
||||
.get(&name)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
location,
|
||||
name,
|
||||
imported_modules: self.imported_modules.keys().cloned().collect(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn close_scope(&mut self, data: ScopeResetData) {
|
||||
let unused = self
|
||||
.entity_usages
|
||||
@@ -705,6 +727,7 @@ impl<'a> Environment<'a> {
|
||||
current_kind: &'a ModuleKind,
|
||||
importable_modules: &'a HashMap<String, TypeInfo>,
|
||||
warnings: &'a mut Vec<Warning>,
|
||||
target_env: Option<&'a str>,
|
||||
) -> Self {
|
||||
let prelude = importable_modules
|
||||
.get("aiken")
|
||||
@@ -731,6 +754,7 @@ impl<'a> Environment<'a> {
|
||||
annotations: HashMap::new(),
|
||||
warnings,
|
||||
entity_usages: vec![HashMap::new()],
|
||||
target_env,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,17 +796,7 @@ impl<'a> Environment<'a> {
|
||||
location,
|
||||
package: _,
|
||||
}) => {
|
||||
let name = module.join("/");
|
||||
|
||||
// Find imported module
|
||||
let module_info =
|
||||
self.importable_modules
|
||||
.get(&name)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
location: *location,
|
||||
name: name.clone(),
|
||||
imported_modules: self.imported_modules.keys().cloned().collect(),
|
||||
})?;
|
||||
let module_info = self.find_module(module, *location)?;
|
||||
|
||||
if module_info.kind.is_validator()
|
||||
&& (self.current_kind.is_lib()
|
||||
@@ -791,7 +805,7 @@ impl<'a> Environment<'a> {
|
||||
{
|
||||
return Err(Error::ValidatorImported {
|
||||
location: *location,
|
||||
name,
|
||||
name: module.join("/"),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ use crate::{
|
||||
use std::{borrow::Borrow, collections::HashMap, ops::Deref, rc::Rc};
|
||||
|
||||
impl UntypedModule {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn infer(
|
||||
mut self,
|
||||
id_gen: &IdGenerator,
|
||||
@@ -27,11 +28,12 @@ impl UntypedModule {
|
||||
modules: &HashMap<String, TypeInfo>,
|
||||
tracing: Tracing,
|
||||
warnings: &mut Vec<Warning>,
|
||||
env: Option<&str>,
|
||||
) -> Result<TypedModule, Error> {
|
||||
let module_name = self.name.clone();
|
||||
let docs = std::mem::take(&mut self.docs);
|
||||
let mut environment =
|
||||
Environment::new(id_gen.clone(), &module_name, &kind, modules, warnings);
|
||||
Environment::new(id_gen.clone(), &module_name, &kind, modules, warnings, env);
|
||||
|
||||
let mut type_names = HashMap::with_capacity(self.definitions.len());
|
||||
let mut value_names = HashMap::with_capacity(self.definitions.len());
|
||||
@@ -574,18 +576,7 @@ fn infer_definition(
|
||||
unqualified,
|
||||
package: _,
|
||||
}) => {
|
||||
let name = module.join("/");
|
||||
|
||||
// Find imported module
|
||||
let module_info =
|
||||
environment
|
||||
.importable_modules
|
||||
.get(&name)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
location,
|
||||
name,
|
||||
imported_modules: environment.imported_modules.keys().cloned().collect(),
|
||||
})?;
|
||||
let module_info = environment.find_module(&module, location)?;
|
||||
|
||||
Ok(Definition::Use(Use {
|
||||
location,
|
||||
|
||||
Reference in New Issue
Block a user