also support using Types as namespace when nested in module.
Signed-off-by: KtorZ <matthias.benkort@gmail.com>
This commit is contained in:
parent
2adc1fab66
commit
b8f42dd555
|
@ -1656,7 +1656,7 @@ impl TypedPattern {
|
||||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum Namespace {
|
pub enum Namespace {
|
||||||
Module(String),
|
Module(String),
|
||||||
Type(String),
|
Type(Option<String>, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
|
|
|
@ -1217,9 +1217,15 @@ impl<'comments> Formatter<'comments> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = match module {
|
let name = match module {
|
||||||
Some(Namespace::Module(m)) | Some(Namespace::Type(m)) => {
|
Some(Namespace::Module(m)) | Some(Namespace::Type(None, m)) => {
|
||||||
m.to_doc().append(".").append(name)
|
m.to_doc().append(".").append(name)
|
||||||
}
|
}
|
||||||
|
Some(Namespace::Type(Some(m), c)) => m
|
||||||
|
.to_doc()
|
||||||
|
.append(".")
|
||||||
|
.append(c.as_str())
|
||||||
|
.append(".")
|
||||||
|
.append(name),
|
||||||
None => name.to_doc(),
|
None => name.to_doc(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,27 @@ pub fn parser(
|
||||||
pattern: Recursive<'_, Token, UntypedPattern, ParseError>,
|
pattern: Recursive<'_, Token, UntypedPattern, ParseError>,
|
||||||
) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ {
|
) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ {
|
||||||
choice((
|
choice((
|
||||||
|
select! { Token::Name { name } => name }
|
||||||
|
.then(just(Token::Dot).ignore_then(select! {Token::UpName { name } => name}))
|
||||||
|
.then(
|
||||||
|
just(Token::Dot).ignore_then(
|
||||||
|
select! {Token::UpName { name } => name}.then(args(pattern.clone())),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.map_with_span(
|
||||||
|
|((module, namespace), (name, (arguments, spread_location, is_record))), span| {
|
||||||
|
UntypedPattern::Constructor {
|
||||||
|
is_record,
|
||||||
|
location: span,
|
||||||
|
name,
|
||||||
|
arguments,
|
||||||
|
module: Some(Namespace::Type(Some(module), namespace)),
|
||||||
|
constructor: (),
|
||||||
|
spread_location,
|
||||||
|
tipo: (),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
select! { Token::UpName { name } => name }
|
select! { Token::UpName { name } => name }
|
||||||
.then(
|
.then(
|
||||||
just(Token::Dot).ignore_then(
|
just(Token::Dot).ignore_then(
|
||||||
|
@ -22,7 +43,7 @@ pub fn parser(
|
||||||
location: span,
|
location: span,
|
||||||
name,
|
name,
|
||||||
arguments,
|
arguments,
|
||||||
module: Some(Namespace::Type(namespace)),
|
module: Some(Namespace::Type(None, namespace)),
|
||||||
constructor: (),
|
constructor: (),
|
||||||
spread_location,
|
spread_location,
|
||||||
tipo: (),
|
tipo: (),
|
||||||
|
|
|
@ -27,9 +27,9 @@ pub use var::parser as var;
|
||||||
pub fn parser() -> impl Parser<Token, UntypedPattern, Error = ParseError> {
|
pub fn parser() -> impl Parser<Token, UntypedPattern, Error = ParseError> {
|
||||||
recursive(|pattern| {
|
recursive(|pattern| {
|
||||||
choice((
|
choice((
|
||||||
var(pattern.clone()),
|
|
||||||
pair(pattern.clone()),
|
pair(pattern.clone()),
|
||||||
constructor(pattern.clone()),
|
constructor(pattern.clone()),
|
||||||
|
var(pattern.clone()),
|
||||||
discard(),
|
discard(),
|
||||||
int(),
|
int(),
|
||||||
bytearray(),
|
bytearray(),
|
||||||
|
|
|
@ -9,6 +9,7 @@ Constructor {
|
||||||
arguments: [],
|
arguments: [],
|
||||||
module: Some(
|
module: Some(
|
||||||
Type(
|
Type(
|
||||||
|
None,
|
||||||
"Foo",
|
"Foo",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -2328,6 +2328,31 @@ fn use_type_as_namespace_for_patterns() {
|
||||||
assert!(matches!(result, Ok(..)), "{result:#?}");
|
assert!(matches!(result, Ok(..)), "{result:#?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn use_nested_type_as_namespace_for_patterns() {
|
||||||
|
let dependency = r#"
|
||||||
|
pub type Foo {
|
||||||
|
A
|
||||||
|
B
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let source_code = r#"
|
||||||
|
use foo.{Foo}
|
||||||
|
|
||||||
|
fn bar(x: Foo) {
|
||||||
|
when x is {
|
||||||
|
foo.Foo.A -> True
|
||||||
|
foo.Foo.B -> False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||||
|
|
||||||
|
assert!(matches!(result, Ok(..)), "{result:#?}");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn use_opaque_type_as_namespace_for_patterns_fails() {
|
fn use_opaque_type_as_namespace_for_patterns_fails() {
|
||||||
let dependency = r#"
|
let dependency = r#"
|
||||||
|
|
|
@ -529,7 +529,42 @@ impl<'a> Environment<'a> {
|
||||||
constructors: self.local_constructor_names(),
|
constructors: self.local_constructor_names(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Some(Namespace::Type(t)) => {
|
Some(Namespace::Type(Some(module_name), t)) => {
|
||||||
|
let module_location = location.map(|start, _| (start, start + module_name.len()));
|
||||||
|
|
||||||
|
// Lookup the module using the declared name (which may have been rebind with
|
||||||
|
// 'as'), to obtain its _full unambiguous name_.
|
||||||
|
let (_, module) =
|
||||||
|
self.imported_modules
|
||||||
|
.get(module_name)
|
||||||
|
.ok_or_else(|| Error::UnknownModule {
|
||||||
|
location: module_location,
|
||||||
|
name: module_name.to_string(),
|
||||||
|
known_modules: self
|
||||||
|
.importable_modules
|
||||||
|
.keys()
|
||||||
|
.map(|t| t.to_string())
|
||||||
|
.collect(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let type_location = Span::create(module_location.end + 1, t.len());
|
||||||
|
|
||||||
|
let parent_type = module.types.get(t).ok_or_else(|| Error::UnknownType {
|
||||||
|
location: type_location,
|
||||||
|
name: t.to_string(),
|
||||||
|
types: self.known_type_names(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.unused_modules.remove(&parent_type.module);
|
||||||
|
|
||||||
|
self.get_fully_qualified_value_constructor(
|
||||||
|
(parent_type.module.as_str(), module_location),
|
||||||
|
(t, type_location),
|
||||||
|
(name, location.map(|_, end| (type_location.end + 1, end))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Namespace::Type(None, t)) => {
|
||||||
let type_location = location.map(|start, _| (start, start + t.len()));
|
let type_location = location.map(|start, _| (start, start + t.len()));
|
||||||
|
|
||||||
let parent_type = self.module_types.get(t).ok_or_else(|| Error::UnknownType {
|
let parent_type = self.module_types.get(t).ok_or_else(|| Error::UnknownType {
|
||||||
|
@ -558,7 +593,7 @@ impl<'a> Environment<'a> {
|
||||||
.keys()
|
.keys()
|
||||||
.map(|t| t.to_string())
|
.map(|t| t.to_string())
|
||||||
.collect(),
|
.collect(),
|
||||||
location,
|
location: Span::create(location.start, m.len()),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.unused_modules.remove(m);
|
self.unused_modules.remove(m);
|
||||||
|
|
|
@ -573,7 +573,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// Type namespaces are completely erased during type-check.
|
// Type namespaces are completely erased during type-check.
|
||||||
module: match module {
|
module: match module {
|
||||||
None | Some(Namespace::Type(_)) => None,
|
None | Some(Namespace::Type(..)) => None,
|
||||||
Some(Namespace::Module(m)) => Some(m),
|
Some(Namespace::Module(m)) => Some(m),
|
||||||
},
|
},
|
||||||
name,
|
name,
|
||||||
|
@ -609,7 +609,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// Type namespaces are completely erased during type-check.
|
// Type namespaces are completely erased during type-check.
|
||||||
module: match module {
|
module: match module {
|
||||||
None | Some(Namespace::Type(_)) => None,
|
None | Some(Namespace::Type(..)) => None,
|
||||||
Some(Namespace::Module(m)) => Some(m),
|
Some(Namespace::Module(m)) => Some(m),
|
||||||
},
|
},
|
||||||
name,
|
name,
|
||||||
|
|
Loading…
Reference in New Issue