Handle importing validator handler into test module.
This commit is contained in:
parent
5dfa3e7cca
commit
7aefa85de1
|
@ -844,7 +844,7 @@ Perhaps, try the following:
|
||||||
}
|
}
|
||||||
))]
|
))]
|
||||||
UnknownModuleValue {
|
UnknownModuleValue {
|
||||||
#[label("unknown import")]
|
#[label("not exported by {module_name}?")]
|
||||||
location: Span,
|
location: Span,
|
||||||
name: String,
|
name: String,
|
||||||
module_name: String,
|
module_name: String,
|
||||||
|
@ -941,16 +941,17 @@ The best thing to do from here is to remove it."#))]
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
"I discovered an attempt to import a validator module: '{}'\n",
|
"I discovered an attempt to import a validator module in a library: '{}'\n",
|
||||||
name.if_supports_color(Stdout, |s| s.purple())
|
name.if_supports_color(Stdout, |s| s.purple())
|
||||||
)]
|
)]
|
||||||
#[diagnostic(code("illegal::import"))]
|
#[diagnostic(code("illegal::import"))]
|
||||||
#[diagnostic(help(
|
#[diagnostic(help(
|
||||||
"If you are trying to share code defined in a validator then move it to a library module under {}",
|
"If you are trying to share code defined in a validator then move it to a library module under {}.\nIf, however, you are trying to import a validator for testing, make sure that your test module doesn't export any definition using the {} keyword.",
|
||||||
"lib/".if_supports_color(Stdout, |s| s.purple()))
|
"lib/".if_supports_color(Stdout, |s| s.purple()),
|
||||||
)]
|
"pub".if_supports_color(Stdout, |s| s.cyan())
|
||||||
|
))]
|
||||||
ValidatorImported {
|
ValidatorImported {
|
||||||
#[label("validator")]
|
#[label("imported validator")]
|
||||||
location: Span,
|
location: Span,
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
@ -1074,7 +1075,8 @@ The best thing to do from here is to remove it."#))]
|
||||||
#[error("I could not find an appropriate handler in the validator definition\n")]
|
#[error("I could not find an appropriate handler in the validator definition\n")]
|
||||||
#[diagnostic(code("unknown::handler"))]
|
#[diagnostic(code("unknown::handler"))]
|
||||||
#[diagnostic(help(
|
#[diagnostic(help(
|
||||||
"When referring to a validator handler via record access, you must refer to one of the declared handlers:\n{}",
|
"When referring to a validator handler via record access, you must refer to one of the declared handlers{}{}",
|
||||||
|
if available_handlers.is_empty() { "." } else { ":\n" },
|
||||||
available_handlers
|
available_handlers
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| format!("-> {}", p.if_supports_color(Stdout, |s| s.green())))
|
.map(|p| format!("-> {}", p.if_supports_color(Stdout, |s| s.green())))
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::{
|
||||||
expr::{FnStyle, TypedExpr, UntypedExpr},
|
expr::{FnStyle, TypedExpr, UntypedExpr},
|
||||||
format,
|
format,
|
||||||
parser::token::Base,
|
parser::token::Base,
|
||||||
tipo::{fields::FieldMap, DefaultFunction, PatternConstructor, TypeVar},
|
tipo::{fields::FieldMap, DefaultFunction, ModuleKind, PatternConstructor, TypeVar},
|
||||||
IdGenerator,
|
IdGenerator,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -920,23 +920,24 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_field_access(
|
fn infer_validator_handler_access(
|
||||||
&mut self,
|
&mut self,
|
||||||
container: UntypedExpr,
|
container: &UntypedExpr,
|
||||||
label: String,
|
label: &str,
|
||||||
access_location: Span,
|
access_location: Span,
|
||||||
) -> Result<TypedExpr, Error> {
|
) -> Option<Result<TypedExpr, Error>> {
|
||||||
if let UntypedExpr::Var { ref name, location } = container {
|
match container {
|
||||||
|
UntypedExpr::Var { name, location } => {
|
||||||
if let Some((_, available_handlers)) = self
|
if let Some((_, available_handlers)) = self
|
||||||
.environment
|
.environment
|
||||||
.module_validators
|
.module_validators
|
||||||
.get(name.as_str())
|
.get(name.as_str())
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
return self
|
return Some(
|
||||||
.infer_var(
|
self.infer_var(
|
||||||
TypedValidator::handler_name(name.as_str(), label.as_str()),
|
TypedValidator::handler_name(name.as_str(), label),
|
||||||
location,
|
*location,
|
||||||
)
|
)
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
Error::UnknownVariable { .. } => Error::UnknownValidatorHandler {
|
Error::UnknownVariable { .. } => Error::UnknownValidatorHandler {
|
||||||
|
@ -944,8 +945,111 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
available_handlers,
|
available_handlers,
|
||||||
},
|
},
|
||||||
_ => err,
|
_ => err,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UntypedExpr::FieldAccess {
|
||||||
|
label: name,
|
||||||
|
container,
|
||||||
|
location,
|
||||||
|
} => {
|
||||||
|
if let UntypedExpr::Var {
|
||||||
|
name: ref module,
|
||||||
|
location: module_location,
|
||||||
|
} = container.as_ref()
|
||||||
|
{
|
||||||
|
match self.environment.imported_modules.get(module) {
|
||||||
|
Some((_, info)) if info.kind == ModuleKind::Validator => {
|
||||||
|
let has_validator = info
|
||||||
|
.values
|
||||||
|
.keys()
|
||||||
|
.any(|k| k.split(".").next() == Some(name));
|
||||||
|
|
||||||
|
let value_constructors = info
|
||||||
|
.values
|
||||||
|
.keys()
|
||||||
|
.map(|k| k.split(".").next().unwrap_or(k).to_string())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
return Some(
|
||||||
|
self.infer_module_access(
|
||||||
|
module,
|
||||||
|
TypedValidator::handler_name(name, label),
|
||||||
|
location,
|
||||||
|
access_location,
|
||||||
|
)
|
||||||
|
.and_then(|access| {
|
||||||
|
let export_values = self
|
||||||
|
.environment
|
||||||
|
.module_values
|
||||||
|
.iter()
|
||||||
|
.any(|(_, constructor)| constructor.public);
|
||||||
|
let export_functions = self
|
||||||
|
.environment
|
||||||
|
.module_functions
|
||||||
|
.iter()
|
||||||
|
.any(|(_, function)| function.public);
|
||||||
|
let export_validators =
|
||||||
|
!self.environment.module_validators.is_empty();
|
||||||
|
|
||||||
|
if export_values || export_functions || export_validators {
|
||||||
|
return Err(Error::ValidatorImported {
|
||||||
|
location: location
|
||||||
|
.map(|_start, end| (module_location.end, end)),
|
||||||
|
name: name.to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(access)
|
||||||
|
})
|
||||||
|
.map_err(|err| match err {
|
||||||
|
Error::UnknownModuleValue { .. } => {
|
||||||
|
if has_validator {
|
||||||
|
Error::UnknownValidatorHandler {
|
||||||
|
location: access_location
|
||||||
|
.map(|_start, end| (location.end, end)),
|
||||||
|
available_handlers: Vec::new(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error::UnknownModuleValue {
|
||||||
|
location: location
|
||||||
|
.map(|_start, end| (module_location.end, end)),
|
||||||
|
name: name.to_string(),
|
||||||
|
module_name: module.to_string(),
|
||||||
|
value_constructors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => err,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infer_field_access(
|
||||||
|
&mut self,
|
||||||
|
container: UntypedExpr,
|
||||||
|
label: String,
|
||||||
|
access_location: Span,
|
||||||
|
) -> Result<TypedExpr, Error> {
|
||||||
|
// NOTE: Before we actually resolve the field access, we try to short-circuit the access if
|
||||||
|
// we detect a validator handler access. This can happen in two cases:
|
||||||
|
//
|
||||||
|
// - Either it is a direct access from a validator in the same module.
|
||||||
|
// - Or it is an attempt to pull a handler from an imported validator module.
|
||||||
|
if let Some(shortcircuit) =
|
||||||
|
self.infer_validator_handler_access(&container, &label, access_location)
|
||||||
|
{
|
||||||
|
return shortcircuit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to infer the container as a record access. If that fails, we may be shadowing the name
|
// Attempt to infer the container as a record access. If that fails, we may be shadowing the name
|
||||||
|
|
Loading…
Reference in New Issue