ensure import resolution is done according to local bindings
Might it be from a module that has multiple path fragments or one that is aliased. Signed-off-by: KtorZ <matthias.benkort@gmail.com>
This commit is contained in:
parent
983902fca8
commit
2adc1fab66
|
@ -2296,7 +2296,7 @@ fn use_imported_type_as_namespace_for_patterns() {
|
|||
"#;
|
||||
|
||||
let result = check_with_deps(
|
||||
dbg!(parse(source_code)),
|
||||
parse(source_code),
|
||||
vec![(parse_as(dependency, "cardano/address"))],
|
||||
);
|
||||
|
||||
|
@ -2443,6 +2443,52 @@ fn use_type_as_nested_namespace_for_constructors() {
|
|||
assert!(matches!(result, Ok(..)), "{result:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_type_as_nested_namespace_for_constructors_from_multi_level_module() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
I(Int)
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo/bar
|
||||
|
||||
test my_test() {
|
||||
trace bar.Foo.I(42)
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo/bar"))]);
|
||||
|
||||
assert!(matches!(result, Ok(..)), "{result:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_type_as_nested_namespace_for_constructors_from_module_alias() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
I(Int)
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo as bar
|
||||
|
||||
test my_test() {
|
||||
trace bar.Foo.I(42)
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(matches!(result, Ok(..)), "{result:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_type_as_namespace_unknown_constructor() {
|
||||
let dependency = r#"
|
||||
|
@ -2626,6 +2672,33 @@ fn use_opaque_type_as_nested_namespace_for_constructors_fails() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_non_imported_module_as_namespace() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
I(Int)
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
test my_test() {
|
||||
trace foo.Foo.I(14)
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownModule { name, .. })) if name == "foo" && warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn forbid_importing_or_using_opaque_constructors() {
|
||||
let dependency = r#"
|
||||
|
|
|
@ -372,6 +372,31 @@ impl<'a> Environment<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get an imported module's actual name in the current module, from its fully qualified module
|
||||
/// name.
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub fn local_module_name(&self, name: &str, location: Span) -> Result<String, Error> {
|
||||
self.imported_modules
|
||||
.iter()
|
||||
.filter_map(|(k, module)| {
|
||||
if module.1.name == name {
|
||||
Some(k.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.next()
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
location,
|
||||
name: name.to_string(),
|
||||
known_modules: self
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub fn get_fully_qualified_value_constructor(
|
||||
&self,
|
||||
|
@ -379,8 +404,8 @@ impl<'a> Environment<'a> {
|
|||
(type_name, type_location): (&str, Span),
|
||||
(value, value_location): (&str, Span),
|
||||
) -> Result<&ValueConstructor, Error> {
|
||||
let (_, module) =
|
||||
self.imported_modules
|
||||
let module =
|
||||
self.importable_modules
|
||||
.get(module_name)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
location: module_location,
|
||||
|
|
|
@ -1095,8 +1095,25 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
location: module_location,
|
||||
} = type_container.as_ref()
|
||||
{
|
||||
// Lookup the module using the declared name (which may have been rebind with
|
||||
// 'as'), to obtain its _full unambiguous name_.
|
||||
let (_, module) = self
|
||||
.environment
|
||||
.imported_modules
|
||||
.get(module_name)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
location: *module_location,
|
||||
name: module_name.to_string(),
|
||||
known_modules: self
|
||||
.environment
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
})?;
|
||||
|
||||
return self.infer_inner_type_constructor_access(
|
||||
(module_name, *module_location),
|
||||
(module.name.as_str(), *module_location),
|
||||
(
|
||||
type_name,
|
||||
type_location.map(|start, end| (start + module_name.len() + 1, end)),
|
||||
|
@ -1251,7 +1268,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
self.environment.unused_modules.remove(module_name);
|
||||
|
||||
self.infer_module_access(
|
||||
module_name,
|
||||
&self
|
||||
.environment
|
||||
.local_module_name(module_name, module_location)?,
|
||||
label.to_string(),
|
||||
&type_location,
|
||||
label_location,
|
||||
|
|
Loading…
Reference in New Issue