Merge branch 'main' into avoid-adjacent-sequence-fusions
This commit is contained in:
commit
0bca89908f
|
@ -5,6 +5,7 @@
|
|||
### Added
|
||||
|
||||
- **aiken**: New `-S` flag on `check` and `build` that blocks the printing of warnings but it still shows the total warning count. @rvcas
|
||||
- **aiken-lang**: Allow types to be used as namespaces for constructors. Importing each constructor variants independently is no longer required in neither pattern-matches nor value construction. One can simply use the type name as a prefix/namespace now. @KtorZ
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -17,6 +18,7 @@
|
|||
|
||||
- **aiken-lang**: Formatter was removing comments from function type annotation args @rvcas
|
||||
- **aiken-lang**: Parser wrongly merged two adjacent sequences together, effectively fusioning scopes. @KtorZ
|
||||
- **aiken-lang**: Fix hint when suggesting to use named fields, wrongly suggesting args in lexicographical order instead of definition order. @KtorZ
|
||||
|
||||
## v1.1.13 - 2025-02-26
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ authors = [
|
|||
"Kasey White <kwhitemsg@gmail.com>",
|
||||
"KtorZ <matthias.benkort@gmail.com>",
|
||||
]
|
||||
rust-version = "1.70.0"
|
||||
rust-version = "1.80.0"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -1535,8 +1535,8 @@ impl BinOp {
|
|||
}
|
||||
}
|
||||
|
||||
pub type UntypedPattern = Pattern<(), ()>;
|
||||
pub type TypedPattern = Pattern<PatternConstructor, Rc<Type>>;
|
||||
pub type UntypedPattern = Pattern<(), (), Namespace>;
|
||||
pub type TypedPattern = Pattern<PatternConstructor, Rc<Type>, String>;
|
||||
|
||||
impl TypedPattern {
|
||||
pub fn var(name: &str) -> Self {
|
||||
|
@ -1654,7 +1654,13 @@ impl TypedPattern {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Pattern<Constructor, Type> {
|
||||
pub enum Namespace {
|
||||
Module(String),
|
||||
Type(Option<String>, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Pattern<Constructor, Type, NamespaceKind> {
|
||||
Int {
|
||||
location: Span,
|
||||
value: String,
|
||||
|
@ -1707,7 +1713,7 @@ pub enum Pattern<Constructor, Type> {
|
|||
location: Span,
|
||||
name: String,
|
||||
arguments: Vec<CallArg<Self>>,
|
||||
module: Option<String>,
|
||||
module: Option<NamespaceKind>,
|
||||
constructor: Constructor,
|
||||
spread_location: Option<Span>,
|
||||
tipo: Type,
|
||||
|
@ -1725,7 +1731,7 @@ pub enum Pattern<Constructor, Type> {
|
|||
},
|
||||
}
|
||||
|
||||
impl<A, B> Pattern<A, B> {
|
||||
impl<A, B, C> Pattern<A, B, C> {
|
||||
pub fn location(&self) -> Span {
|
||||
match self {
|
||||
Pattern::Assign { pattern, .. } => pattern.location(),
|
||||
|
@ -2201,22 +2207,23 @@ impl<T: Default> AssignmentKind<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type MultiPattern<PatternConstructor, Type> = Vec<Pattern<PatternConstructor, Type>>;
|
||||
pub type MultiPattern<PatternConstructor, Type, NamespaceKind> =
|
||||
Vec<Pattern<PatternConstructor, Type, NamespaceKind>>;
|
||||
|
||||
pub type UntypedMultiPattern = MultiPattern<(), ()>;
|
||||
pub type TypedMultiPattern = MultiPattern<PatternConstructor, Rc<Type>>;
|
||||
pub type UntypedMultiPattern = MultiPattern<(), (), Namespace>;
|
||||
pub type TypedMultiPattern = MultiPattern<PatternConstructor, Rc<Type>, String>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct UntypedClause {
|
||||
pub location: Span,
|
||||
pub patterns: Vec1<Pattern<(), ()>>,
|
||||
pub patterns: Vec1<UntypedPattern>,
|
||||
pub then: UntypedExpr,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct TypedClause {
|
||||
pub location: Span,
|
||||
pub pattern: Pattern<PatternConstructor, Rc<Type>>,
|
||||
pub pattern: TypedPattern,
|
||||
pub then: TypedExpr,
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::{
|
|||
},
|
||||
IdGenerator,
|
||||
};
|
||||
use std::{collections::BTreeSet, sync::LazyLock};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
|
@ -25,6 +26,16 @@ use uplc::{
|
|||
pub const PRELUDE: &str = "aiken";
|
||||
pub const BUILTIN: &str = "aiken/builtin";
|
||||
|
||||
pub static INTERNAL_FUNCTIONS: LazyLock<BTreeSet<&'static str>> = LazyLock::new(|| {
|
||||
let mut set = BTreeSet::new();
|
||||
set.insert("diagnostic");
|
||||
set.insert("do_from_int");
|
||||
set.insert("encode_base16");
|
||||
set.insert("enumerate");
|
||||
set.insert("from_int");
|
||||
set
|
||||
});
|
||||
|
||||
/// Build a prelude that can be injected
|
||||
/// into a compiler pipeline
|
||||
pub fn prelude(id_gen: &IdGenerator) -> TypeInfo {
|
||||
|
|
|
@ -2,16 +2,15 @@ pub(crate) use crate::{
|
|||
ast::{
|
||||
self, Annotation, ArgBy, ArgName, AssignmentKind, AssignmentPattern, BinOp, Bls12_381Point,
|
||||
ByteArrayFormatPreference, CallArg, Curve, DataType, DataTypeKey, DefinitionLocation,
|
||||
Located, LogicalOpChainKind, ParsedCallArg, Pattern, RecordConstructorArg,
|
||||
RecordUpdateSpread, Span, TraceKind, TypedArg, TypedAssignmentKind, TypedClause,
|
||||
TypedDataType, TypedIfBranch, TypedPattern, TypedRecordUpdateArg, UnOp, UntypedArg,
|
||||
UntypedAssignmentKind, UntypedClause, UntypedIfBranch, UntypedRecordUpdateArg,
|
||||
Located, LogicalOpChainKind, ParsedCallArg, RecordConstructorArg, RecordUpdateSpread, Span,
|
||||
TraceKind, TypedArg, TypedAssignmentKind, TypedClause, TypedDataType, TypedIfBranch,
|
||||
TypedPattern, TypedRecordUpdateArg, UnOp, UntypedArg, UntypedAssignmentKind, UntypedClause,
|
||||
UntypedIfBranch, UntypedRecordUpdateArg,
|
||||
},
|
||||
parser::token::Base,
|
||||
tipo::{
|
||||
check_replaceable_opaque_type, convert_opaque_type, lookup_data_type_by_tipo,
|
||||
ModuleValueConstructor, PatternConstructor, Type, TypeVar, ValueConstructor,
|
||||
ValueConstructorVariant,
|
||||
ModuleValueConstructor, Type, TypeVar, ValueConstructor, ValueConstructorVariant,
|
||||
},
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
|
@ -109,7 +108,7 @@ pub enum TypedExpr {
|
|||
location: Span,
|
||||
tipo: Rc<Type>,
|
||||
value: Box<Self>,
|
||||
pattern: Pattern<PatternConstructor, Rc<Type>>,
|
||||
pattern: TypedPattern,
|
||||
kind: TypedAssignmentKind,
|
||||
},
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
ast::{
|
||||
Annotation, ArgBy, ArgName, ArgVia, AssignmentKind, AssignmentPattern, BinOp,
|
||||
ByteArrayFormatPreference, CallArg, CurveType, DataType, Definition, Function,
|
||||
LogicalOpChainKind, ModuleConstant, OnTestFailure, Pattern, RecordConstructor,
|
||||
LogicalOpChainKind, ModuleConstant, Namespace, OnTestFailure, Pattern, RecordConstructor,
|
||||
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg,
|
||||
TypedValidator, UnOp, UnqualifiedImport, UntypedArg, UntypedArgVia, UntypedAssignmentKind,
|
||||
UntypedClause, UntypedDefinition, UntypedFunction, UntypedIfBranch, UntypedModule,
|
||||
|
@ -1202,7 +1202,7 @@ impl<'comments> Formatter<'comments> {
|
|||
&mut self,
|
||||
name: &'a str,
|
||||
args: &'a [CallArg<UntypedPattern>],
|
||||
module: &'a Option<String>,
|
||||
module: &'a Option<Namespace>,
|
||||
spread_location: Option<Span>,
|
||||
is_record: bool,
|
||||
) -> Document<'a> {
|
||||
|
@ -1217,7 +1217,15 @@ impl<'comments> Formatter<'comments> {
|
|||
}
|
||||
|
||||
let name = match module {
|
||||
Some(m) => m.to_doc().append(".").append(name),
|
||||
Some(Namespace::Module(m)) | Some(Namespace::Type(None, m)) => {
|
||||
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(),
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::Chain;
|
||||
use crate::{
|
||||
expr::UntypedExpr,
|
||||
ast::well_known,
|
||||
parser::{token::Token, ParseError},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
@ -8,27 +8,13 @@ use chumsky::prelude::*;
|
|||
pub(crate) fn parser() -> impl Parser<Token, Chain, Error = ParseError> {
|
||||
just(Token::Dot)
|
||||
.ignore_then(choice((
|
||||
select! { Token::Else => "else".to_string() },
|
||||
select! { Token::Else => well_known::VALIDATOR_ELSE.to_string() },
|
||||
select! { Token::Name { name } => name, },
|
||||
select! { Token::UpName { name } => name, },
|
||||
)))
|
||||
.map_with_span(Chain::FieldAccess)
|
||||
}
|
||||
|
||||
pub(crate) fn constructor() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
||||
select! {Token::Name { name } => name}
|
||||
.map_with_span(|module, span| (module, span))
|
||||
.then_ignore(just(Token::Dot))
|
||||
.then(select! {Token::UpName { name } => name})
|
||||
.map_with_span(|((module, m_span), name), span| UntypedExpr::FieldAccess {
|
||||
location: span,
|
||||
label: name,
|
||||
container: Box::new(UntypedExpr::Var {
|
||||
location: m_span,
|
||||
name: module,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_expr;
|
||||
|
|
|
@ -4,6 +4,7 @@ pub(crate) mod call;
|
|||
pub(crate) mod field_access;
|
||||
pub(crate) mod tuple_index;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Chain {
|
||||
Call(Vec<ParsedCallArg>, Span),
|
||||
FieldAccess(String, Span),
|
||||
|
|
|
@ -53,7 +53,6 @@ pub fn chain_start<'a>(
|
|||
pair(expression.clone()),
|
||||
record_update(expression.clone()),
|
||||
record(expression.clone()),
|
||||
field_access::constructor(),
|
||||
and_or_chain(expression.clone()),
|
||||
var(),
|
||||
tuple(expression.clone()),
|
||||
|
|
|
@ -16,6 +16,12 @@ pub fn parser(
|
|||
.map_with_span(|module, span: ast::Span| (module, span))
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not()
|
||||
.then(
|
||||
select! {Token::UpName { name } => name}
|
||||
.map_with_span(|name, span| (name, span))
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not(),
|
||||
)
|
||||
.then(select! {Token::UpName { name } => name}.map_with_span(|name, span| (name, span)))
|
||||
.then(
|
||||
choice((
|
||||
|
@ -117,6 +123,12 @@ pub fn parser(
|
|||
.map_with_span(|module, span| (module, span))
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not()
|
||||
.then(
|
||||
select! {Token::UpName { name } => name}
|
||||
.map_with_span(|name, span| (name, span))
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not(),
|
||||
)
|
||||
.then(select! {Token::UpName { name } => name}.map_with_span(|name, span| (name, span)))
|
||||
.then(
|
||||
select! {Token::Name {name} => name}
|
||||
|
@ -157,21 +169,43 @@ pub fn parser(
|
|||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||
),
|
||||
))
|
||||
.map_with_span(|((module, (name, n_span)), arguments), span| {
|
||||
let fun = if let Some((module, m_span)) = module {
|
||||
.map_with_span(
|
||||
|(((module, namespace), (label, label_span)), arguments), span| {
|
||||
let fun = match (module, namespace) {
|
||||
(Some((module, module_span)), Some((namespace, namespace_span))) => {
|
||||
UntypedExpr::FieldAccess {
|
||||
location: m_span.union(n_span),
|
||||
label: name,
|
||||
location: module_span.union(namespace_span).union(label_span),
|
||||
label,
|
||||
container: Box::new(UntypedExpr::FieldAccess {
|
||||
location: module_span.union(namespace_span),
|
||||
label: namespace,
|
||||
container: Box::new(UntypedExpr::Var {
|
||||
location: m_span,
|
||||
location: module_span,
|
||||
name: module,
|
||||
}),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
UntypedExpr::Var {
|
||||
location: n_span,
|
||||
name,
|
||||
}
|
||||
(None, Some((namespace, namespace_span))) => UntypedExpr::FieldAccess {
|
||||
location: namespace_span.union(label_span),
|
||||
label,
|
||||
container: Box::new(UntypedExpr::Var {
|
||||
location: namespace_span,
|
||||
name: namespace,
|
||||
}),
|
||||
},
|
||||
(Some((module, module_span)), None) => UntypedExpr::FieldAccess {
|
||||
location: module_span.union(label_span),
|
||||
label,
|
||||
container: Box::new(UntypedExpr::Var {
|
||||
location: module_span,
|
||||
name: module,
|
||||
}),
|
||||
},
|
||||
(None, None) => UntypedExpr::Var {
|
||||
location: label_span,
|
||||
name: label,
|
||||
},
|
||||
};
|
||||
|
||||
UntypedExpr::Call {
|
||||
|
@ -179,7 +213,8 @@ pub fn parser(
|
|||
fun: Box::new(fun),
|
||||
location: span,
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,13 +1,55 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast::{CallArg, Span, UntypedPattern},
|
||||
ast::{CallArg, Namespace, Span, UntypedPattern},
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
|
||||
pub fn parser(
|
||||
pattern: Recursive<'_, Token, UntypedPattern, ParseError>,
|
||||
) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ {
|
||||
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 }
|
||||
.then(
|
||||
just(Token::Dot).ignore_then(
|
||||
select! {Token::UpName { name } => name}.then(args(pattern.clone())),
|
||||
),
|
||||
)
|
||||
.map_with_span(
|
||||
|(namespace, (name, (arguments, spread_location, is_record))), span| {
|
||||
UntypedPattern::Constructor {
|
||||
is_record,
|
||||
location: span,
|
||||
name,
|
||||
arguments,
|
||||
module: Some(Namespace::Type(None, namespace)),
|
||||
constructor: (),
|
||||
spread_location,
|
||||
tipo: (),
|
||||
}
|
||||
},
|
||||
),
|
||||
select! {Token::UpName { name } => name}
|
||||
.then(args(pattern))
|
||||
.map_with_span(
|
||||
|
@ -23,7 +65,8 @@ pub fn parser(
|
|||
tipo: (),
|
||||
}
|
||||
},
|
||||
)
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn args(
|
||||
|
@ -102,4 +145,9 @@ mod tests {
|
|||
fn constructor_module_select() {
|
||||
assert_pattern!("module.Foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn constructor_type_select() {
|
||||
assert_pattern!("Foo.Bar");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ pub use var::parser as var;
|
|||
pub fn parser() -> impl Parser<Token, UntypedPattern, Error = ParseError> {
|
||||
recursive(|pattern| {
|
||||
choice((
|
||||
var(pattern.clone()),
|
||||
pair(pattern.clone()),
|
||||
constructor(pattern.clone()),
|
||||
var(pattern.clone()),
|
||||
discard(),
|
||||
int(),
|
||||
bytearray(),
|
||||
|
|
|
@ -8,8 +8,10 @@ Constructor {
|
|||
name: "Foo",
|
||||
arguments: [],
|
||||
module: Some(
|
||||
Module(
|
||||
"module",
|
||||
),
|
||||
),
|
||||
constructor: (),
|
||||
spread_location: None,
|
||||
tipo: (),
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/pattern/constructor.rs
|
||||
description: "Code:\n\nFoo.Bar"
|
||||
---
|
||||
Constructor {
|
||||
is_record: false,
|
||||
location: 0..7,
|
||||
name: "Bar",
|
||||
arguments: [],
|
||||
module: Some(
|
||||
Type(
|
||||
None,
|
||||
"Foo",
|
||||
),
|
||||
),
|
||||
constructor: (),
|
||||
spread_location: None,
|
||||
tipo: (),
|
||||
}
|
|
@ -9,7 +9,9 @@ use crate::{
|
|||
pub fn parser(
|
||||
expression: Recursive<'_, Token, UntypedPattern, ParseError>,
|
||||
) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ {
|
||||
select! { Token::Name {name} => name }
|
||||
select! {
|
||||
Token::Name {name} => name,
|
||||
}
|
||||
.then(
|
||||
just(Token::Dot)
|
||||
.ignore_then(
|
||||
|
@ -24,7 +26,7 @@ pub fn parser(
|
|||
location: span,
|
||||
name: c_name,
|
||||
arguments,
|
||||
module: Some(name),
|
||||
module: Some(crate::ast::Namespace::Module(name)),
|
||||
constructor: (),
|
||||
spread_location,
|
||||
tipo: (),
|
||||
|
|
|
@ -11,15 +11,23 @@ use crate::{
|
|||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
const DEFAULT_MODULE_NAME: &str = "my_module";
|
||||
const DEFAULT_PACKAGE: &str = "test/project";
|
||||
|
||||
fn parse(source_code: &str) -> UntypedModule {
|
||||
parse_as(source_code, DEFAULT_MODULE_NAME)
|
||||
}
|
||||
|
||||
fn parse_as(source_code: &str, name: &str) -> UntypedModule {
|
||||
let kind = ModuleKind::Lib;
|
||||
let (ast, _) = parser::module(source_code, kind).expect("Failed to parse module");
|
||||
let (mut ast, _) = parser::module(source_code, kind).expect("Failed to parse module");
|
||||
ast.name = name.to_string();
|
||||
ast
|
||||
}
|
||||
|
||||
fn check_module(
|
||||
ast: UntypedModule,
|
||||
extra: Vec<(String, UntypedModule)>,
|
||||
extra: Vec<UntypedModule>,
|
||||
kind: ModuleKind,
|
||||
tracing: Tracing,
|
||||
) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
|
||||
|
@ -31,27 +39,32 @@ fn check_module(
|
|||
module_types.insert("aiken".to_string(), builtins::prelude(&id_gen));
|
||||
module_types.insert("aiken/builtin".to_string(), builtins::plutus(&id_gen));
|
||||
|
||||
for (package, module) in extra {
|
||||
for module in extra {
|
||||
let mut warnings = vec![];
|
||||
|
||||
if module.name == DEFAULT_MODULE_NAME {
|
||||
panic!("passed extra modules with default name! Use 'parse_as' to define tests instead of 'parse'.");
|
||||
}
|
||||
|
||||
let typed_module = module
|
||||
.infer(
|
||||
&id_gen,
|
||||
kind,
|
||||
&package,
|
||||
DEFAULT_PACKAGE,
|
||||
&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());
|
||||
|
||||
module_types.insert(typed_module.name.clone(), typed_module.type_info.clone());
|
||||
}
|
||||
|
||||
let result = ast.infer(
|
||||
&id_gen,
|
||||
kind,
|
||||
"test/project",
|
||||
DEFAULT_PACKAGE,
|
||||
&module_types,
|
||||
tracing,
|
||||
&mut warnings,
|
||||
|
@ -76,7 +89,7 @@ fn check_with_verbosity(
|
|||
|
||||
fn check_with_deps(
|
||||
ast: UntypedModule,
|
||||
extra: Vec<(String, UntypedModule)>,
|
||||
extra: Vec<UntypedModule>,
|
||||
) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
|
||||
check_module(ast, extra, ModuleKind::Lib, Tracing::verbose())
|
||||
}
|
||||
|
@ -2254,6 +2267,524 @@ fn allow_expect_into_opaque_type_constructor_without_typecasting_in_module() {
|
|||
assert!(check(parse(source_code)).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_imported_type_as_namespace_for_patterns() {
|
||||
let dependency = r#"
|
||||
pub type Credential {
|
||||
VerificationKey(ByteArray)
|
||||
Script(ByteArray)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use cardano/address.{Credential, Script, VerificationKey}
|
||||
|
||||
pub fn compare(left: Credential, right: Credential) -> Ordering {
|
||||
when left is {
|
||||
Script(left) ->
|
||||
when right is {
|
||||
Script(right) -> Equal
|
||||
_ -> Less
|
||||
}
|
||||
VerificationKey(left) ->
|
||||
when right is {
|
||||
Script(_) -> Greater
|
||||
VerificationKey(right) -> Equal
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(
|
||||
parse(source_code),
|
||||
vec![(parse_as(dependency, "cardano/address"))],
|
||||
);
|
||||
|
||||
assert!(matches!(result, Ok(..)), "{result:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_type_as_namespace_for_patterns() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
A { a: Int }
|
||||
B
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use thing.{Foo}
|
||||
|
||||
fn bar(foo: Foo) {
|
||||
when foo is {
|
||||
Foo.A { a } -> a > 10
|
||||
Foo.B -> False
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "thing"))]);
|
||||
|
||||
assert!(matches!(result, Ok(..)), "{result:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_nested_type_as_namespace_for_patterns() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
A { a: Int }
|
||||
B
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo.{Foo}
|
||||
|
||||
fn bar(x: Foo) {
|
||||
when x is {
|
||||
foo.Foo.A { a } -> a > 10
|
||||
foo.Foo.B -> False
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(matches!(result, Ok(..)), "{result:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_opaque_type_as_namespace_for_patterns_fails() {
|
||||
let dependency = r#"
|
||||
pub opaque type Foo {
|
||||
A { a: Int }
|
||||
B
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use thing.{Foo}
|
||||
|
||||
fn bar(foo: Foo) {
|
||||
when foo is {
|
||||
Foo.A { a } -> a > 10
|
||||
Foo.B -> False
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "thing"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownTypeConstructor { name, .. })) if name == "A" && warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_wrong_type_as_namespace_for_patterns_fails() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
A { a: Int }
|
||||
B
|
||||
}
|
||||
|
||||
pub type Bar {
|
||||
C
|
||||
D
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use thing.{Foo}
|
||||
|
||||
fn bar(foo: Foo) {
|
||||
when foo is {
|
||||
Foo.A { .. } -> True
|
||||
Foo.D -> False
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "thing"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownTypeConstructor { name, .. })) if name == "D" && warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_type_as_namespace_for_constructors() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
I { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo.{Foo}
|
||||
|
||||
test my_test() {
|
||||
and {
|
||||
Foo.I { i: 42 } == foo.I(42),
|
||||
foo.B(True) == Foo.B(True),
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(matches!(result, Ok(..)), "{result:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_type_as_nested_namespace_for_constructors() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
I { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo
|
||||
|
||||
test my_test() {
|
||||
trace foo.Foo.I { i: 42 }
|
||||
trace foo.Foo.B(False)
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
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 { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo/bar
|
||||
|
||||
test my_test() {
|
||||
trace bar.Foo.I { i: 42 }
|
||||
trace bar.Foo.B(True)
|
||||
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 { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo as bar
|
||||
|
||||
test my_test() {
|
||||
trace bar.Foo.I { i: 42 }
|
||||
trace bar.Foo.B(True)
|
||||
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#"
|
||||
pub type Foo {
|
||||
I { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo.{Foo}
|
||||
|
||||
test my_test() {
|
||||
Foo.I(42) == Foo.A
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownTypeConstructor { name, .. })) if name == "A" && warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_wrong_type_as_namespace() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
I { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
|
||||
pub type Bar {
|
||||
S { s: String }
|
||||
L(List<Int>)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo.{Foo}
|
||||
|
||||
test my_test() {
|
||||
trace Foo.S(@"wut")
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownTypeConstructor { name, .. })) if name == "S" && warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_wrong_nested_type_as_namespace() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
I { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
|
||||
pub type Bar {
|
||||
S { s: String }
|
||||
L(List<Int>)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo
|
||||
|
||||
test my_test() {
|
||||
trace foo.Foo.S(@"wut")
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownTypeConstructor { name, .. })) if name == "S" && warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_private_type_as_nested_namespace_fails() {
|
||||
let dependency = r#"
|
||||
type Foo {
|
||||
I { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo
|
||||
|
||||
test my_test() {
|
||||
trace foo.Foo.I { i: 42 }
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownModuleType { name, .. })) if name == "Foo" && warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_opaque_type_as_namespace_for_constructors_fails() {
|
||||
let dependency = r#"
|
||||
pub opaque type Foo {
|
||||
I { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo.{Foo}
|
||||
|
||||
test my_test() {
|
||||
trace Foo.I(42)
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownTypeConstructor { name, .. })) if name == "I" && warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_opaque_type_as_nested_namespace_for_constructors_fails() {
|
||||
let dependency = r#"
|
||||
pub opaque type Foo {
|
||||
I { i: Int }
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo
|
||||
|
||||
test my_test() {
|
||||
trace foo.Foo.I(42)
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownTypeConstructor { name, .. })) if name == "I" && warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[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 invalid_type_field_access_chain() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
I(Int)
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo.{Foo}
|
||||
|
||||
test my_test() {
|
||||
trace Foo.I.Int(42)
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::InvalidFieldAccess { .. })) if warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_type_field_access_chain_2() {
|
||||
let dependency = r#"
|
||||
pub type Foo {
|
||||
I(Int)
|
||||
B(Bool)
|
||||
}
|
||||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo.{Foo}
|
||||
|
||||
test my_test() {
|
||||
trace Foo.i(42)
|
||||
Void
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
|
||||
|
||||
assert!(
|
||||
matches!(
|
||||
&result,
|
||||
Err((warnings, Error::UnknownTypeConstructor { .. })) if warnings.is_empty(),
|
||||
),
|
||||
"{result:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn forbid_importing_or_using_opaque_constructors() {
|
||||
let dependency = r#"
|
||||
|
@ -2264,7 +2795,7 @@ fn forbid_importing_or_using_opaque_constructors() {
|
|||
"#;
|
||||
|
||||
let source_code = r#"
|
||||
use foo/thing.{Thing, Foo}
|
||||
use thing.{Thing, Foo}
|
||||
|
||||
fn bar(thing: Thing) {
|
||||
expect Foo(a) = thing
|
||||
|
@ -2273,15 +2804,12 @@ fn forbid_importing_or_using_opaque_constructors() {
|
|||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check_with_deps(
|
||||
parse(source_code),
|
||||
vec![("foo/thing".to_string(), parse(dependency))],
|
||||
),
|
||||
check_with_deps(parse(source_code), vec![(parse_as(dependency, "thing"))],),
|
||||
Err((_, Error::UnknownModuleField { .. })),
|
||||
));
|
||||
|
||||
let source_code = r#"
|
||||
use foo/thing.{Thing}
|
||||
use thing.{Thing}
|
||||
|
||||
fn bar(thing: Thing) {
|
||||
expect Foo(a) = thing
|
||||
|
@ -2290,10 +2818,7 @@ fn forbid_importing_or_using_opaque_constructors() {
|
|||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check_with_deps(
|
||||
parse(source_code),
|
||||
vec![("foo/thing".to_string(), parse(dependency))],
|
||||
),
|
||||
check_with_deps(parse(source_code), vec![(parse_as(dependency, "thing"))],),
|
||||
Err((_, Error::UnknownTypeConstructor { .. })),
|
||||
));
|
||||
}
|
||||
|
@ -3701,3 +4226,56 @@ fn unused_record_fields_4() {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unused_record_fields_5() {
|
||||
let source_code = r#"
|
||||
pub type Foo {
|
||||
b_is_before_a: Bool,
|
||||
a_is_after_b: Bool,
|
||||
}
|
||||
|
||||
test confusing() {
|
||||
let Foo(a, b) = Foo(True, True)
|
||||
a || b
|
||||
}
|
||||
"#;
|
||||
|
||||
let result = check_validator(parse(source_code));
|
||||
assert!(result.is_ok());
|
||||
|
||||
let (warnings, _) = result.unwrap();
|
||||
assert_eq!(
|
||||
warnings[0],
|
||||
Warning::UnusedRecordFields {
|
||||
location: Span::create(137, 9),
|
||||
suggestion: UntypedPattern::Constructor {
|
||||
is_record: true,
|
||||
location: Span::create(137, 9),
|
||||
name: "Foo".to_string(),
|
||||
arguments: vec![
|
||||
CallArg {
|
||||
label: Some("b_is_before_a".to_string()),
|
||||
location: Span::create(141, 13),
|
||||
value: Pattern::Var {
|
||||
location: Span::create(141, 1),
|
||||
name: "a".to_string()
|
||||
}
|
||||
},
|
||||
CallArg {
|
||||
label: Some("a_is_after_b".to_string()),
|
||||
location: Span::create(144, 12),
|
||||
value: Pattern::Var {
|
||||
location: Span::create(144, 1),
|
||||
name: "b".to_string()
|
||||
}
|
||||
}
|
||||
],
|
||||
module: None,
|
||||
constructor: (),
|
||||
spread_location: None,
|
||||
tipo: ()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1449,3 +1449,26 @@ fn capture_right_hand_side_assign() {
|
|||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn types_as_namespace() {
|
||||
assert_format!(
|
||||
r#"
|
||||
use foo.{ Foo }
|
||||
|
||||
fn predicate(val) {
|
||||
when val is {
|
||||
Foo.I(n) -> n >= 14
|
||||
foo.Foo.B(bytes) -> bytes == "aiken"
|
||||
}
|
||||
}
|
||||
|
||||
test my_test() {
|
||||
and {
|
||||
predicate(foo.Foo.I(42)),
|
||||
predicate(Foo.b("aiken"))
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/tests/format.rs
|
||||
description: "Code:\n\nuse foo.{ Foo }\n\nfn predicate(val) {\n when val is {\n Foo.I(n) -> n >= 14\n foo.Foo.B(bytes) -> bytes == \"aiken\"\n }\n}\n\ntest my_test() {\n and {\n predicate(foo.Foo.I(42)),\n predicate(Foo.b(\"aiken\"))\n }\n}\n"
|
||||
---
|
||||
use foo.{Foo}
|
||||
|
||||
fn predicate(val) {
|
||||
when val is {
|
||||
Foo.I(n) -> n >= 14
|
||||
foo.Foo.B(bytes) -> bytes == "aiken"
|
||||
}
|
||||
}
|
||||
|
||||
test my_test() {
|
||||
and {
|
||||
predicate(foo.Foo.I(42)),
|
||||
predicate(Foo.b("aiken")),
|
||||
}
|
||||
}
|
|
@ -8,9 +8,9 @@ use super::{
|
|||
use crate::{
|
||||
ast::{
|
||||
self, Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind,
|
||||
RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition, TypedFunction,
|
||||
TypedPattern, TypedValidator, UnqualifiedImport, UntypedArg, UntypedDefinition,
|
||||
UntypedFunction, Use, Validator, PIPE_VARIABLE,
|
||||
Namespace, RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition,
|
||||
TypedFunction, TypedPattern, TypedValidator, UnqualifiedImport, UntypedArg,
|
||||
UntypedDefinition, UntypedFunction, Use, Validator, PIPE_VARIABLE,
|
||||
},
|
||||
tipo::{fields::FieldMap, TypeAliasAnnotation},
|
||||
IdGenerator,
|
||||
|
@ -91,6 +91,19 @@ pub struct Environment<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Environment<'a> {
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub fn err_unknown_module(&self, name: String, location: Span) -> Error {
|
||||
Error::UnknownModule {
|
||||
name,
|
||||
location,
|
||||
known_modules: self
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub fn find_module(&self, fragments: &[String], location: Span) -> Result<&'a TypeInfo, Error> {
|
||||
let mut name = fragments.join("/");
|
||||
|
@ -118,11 +131,7 @@ impl<'a> Environment<'a> {
|
|||
.collect(),
|
||||
}
|
||||
} else {
|
||||
Error::UnknownModule {
|
||||
location,
|
||||
name,
|
||||
known_modules: self.importable_modules.keys().cloned().collect(),
|
||||
}
|
||||
self.err_unknown_module(name, location)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -372,13 +381,69 @@ 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(|| self.err_unknown_module(name.to_string(), location))
|
||||
}
|
||||
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub fn get_fully_qualified_value_constructor(
|
||||
&self,
|
||||
(module_name, module_location): (&str, Span),
|
||||
(type_name, type_location): (&str, Span),
|
||||
(value, value_location): (&str, Span),
|
||||
) -> Result<&ValueConstructor, Error> {
|
||||
let module = self
|
||||
.importable_modules
|
||||
.get(module_name)
|
||||
.ok_or_else(|| self.err_unknown_module(module_name.to_string(), module_location))?;
|
||||
|
||||
let constructors =
|
||||
module
|
||||
.types_constructors
|
||||
.get(type_name)
|
||||
.ok_or_else(|| Error::UnknownModuleType {
|
||||
location: type_location,
|
||||
name: type_name.to_string(),
|
||||
module_name: module.name.clone(),
|
||||
type_constructors: module.types.keys().map(|t| t.to_string()).collect(),
|
||||
})?;
|
||||
|
||||
let unknown_type_constructor = || Error::UnknownTypeConstructor {
|
||||
location: value_location,
|
||||
name: value.to_string(),
|
||||
constructors: constructors.clone(),
|
||||
};
|
||||
|
||||
if !constructors.iter().any(|s| s.as_str() == value) {
|
||||
return Err(unknown_type_constructor());
|
||||
}
|
||||
|
||||
module
|
||||
.values
|
||||
.get(value)
|
||||
.ok_or_else(unknown_type_constructor)
|
||||
}
|
||||
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub fn get_type_constructor_mut(
|
||||
&mut self,
|
||||
name: &str,
|
||||
location: Span,
|
||||
) -> Result<&mut TypeConstructor, Error> {
|
||||
let types = self.module_types.keys().map(|t| t.to_string()).collect();
|
||||
let types = self.known_type_names();
|
||||
|
||||
let constructor = self
|
||||
.module_types
|
||||
|
@ -407,22 +472,14 @@ impl<'a> Environment<'a> {
|
|||
.ok_or_else(|| Error::UnknownType {
|
||||
location,
|
||||
name: name.to_string(),
|
||||
types: self.module_types.keys().map(|t| t.to_string()).collect(),
|
||||
types: self.known_type_names(),
|
||||
}),
|
||||
|
||||
Some(m) => {
|
||||
let (_, module) =
|
||||
self.imported_modules
|
||||
let (_, module) = self
|
||||
.imported_modules
|
||||
.get(m)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
location,
|
||||
name: name.to_string(),
|
||||
known_modules: self
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
})?;
|
||||
.ok_or_else(|| self.err_unknown_module(name.to_string(), location))?;
|
||||
|
||||
self.unused_modules.remove(m);
|
||||
|
||||
|
@ -443,7 +500,7 @@ impl<'a> Environment<'a> {
|
|||
#[allow(clippy::result_large_err)]
|
||||
pub fn get_value_constructor(
|
||||
&mut self,
|
||||
module: Option<&String>,
|
||||
module: Option<&Namespace>,
|
||||
name: &str,
|
||||
location: Span,
|
||||
) -> Result<&ValueConstructor, Error> {
|
||||
|
@ -457,18 +514,53 @@ impl<'a> Environment<'a> {
|
|||
constructors: self.local_constructor_names(),
|
||||
}),
|
||||
|
||||
Some(m) => {
|
||||
let (_, module) =
|
||||
self.imported_modules
|
||||
.get(m)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
name: m.to_string(),
|
||||
known_modules: self
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
location,
|
||||
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(|| {
|
||||
self.err_unknown_module(module_name.to_string(), module_location)
|
||||
})?;
|
||||
|
||||
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 parent_type = self.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(), type_location),
|
||||
(t, type_location),
|
||||
(name, location.map(|start, end| (start + t.len() + 1, end))),
|
||||
)
|
||||
}
|
||||
|
||||
Some(Namespace::Module(m)) => {
|
||||
let (_, module) = self.imported_modules.get(m).ok_or_else(|| {
|
||||
self.err_unknown_module(m.to_string(), Span::create(location.start, m.len()))
|
||||
})?;
|
||||
|
||||
self.unused_modules.remove(m);
|
||||
|
@ -728,10 +820,28 @@ impl<'a> Environment<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get a list of known type names, for suggestions in errors.
|
||||
pub fn known_type_names(&self) -> Vec<String> {
|
||||
self.module_types
|
||||
.keys()
|
||||
.filter_map(|t| {
|
||||
// Avoid leaking special internal types in error hints.
|
||||
if t.starts_with("__") {
|
||||
None
|
||||
} else {
|
||||
Some(t.to_string())
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn local_value_names(&self) -> Vec<String> {
|
||||
self.scope
|
||||
.keys()
|
||||
.filter(|&t| PIPE_VARIABLE != t)
|
||||
// Avoid leaking internal functions in error hints.
|
||||
.filter(|&t| !crate::builtins::INTERNAL_FUNCTIONS.contains(t.as_str()))
|
||||
.filter(|&t| !t.starts_with("__") && !TypeConstructor::might_be(t))
|
||||
.map(|t| t.to_string())
|
||||
.collect()
|
||||
}
|
||||
|
@ -739,7 +849,9 @@ impl<'a> Environment<'a> {
|
|||
pub fn local_constructor_names(&self) -> Vec<String> {
|
||||
self.scope
|
||||
.keys()
|
||||
.filter(|&t| t.chars().next().unwrap_or_default().is_uppercase())
|
||||
// Avoid leaking internal constructors in error hints.
|
||||
.filter(|&t| !t.starts_with("__"))
|
||||
.filter(|&t| TypeConstructor::might_be(t))
|
||||
.map(|t| t.to_string())
|
||||
.collect()
|
||||
}
|
||||
|
@ -1816,7 +1928,7 @@ impl<'a> Environment<'a> {
|
|||
.get(name)
|
||||
.ok_or_else(|| Error::UnknownType {
|
||||
name: name.to_string(),
|
||||
types: self.module_types.keys().map(|t| t.to_string()).collect(),
|
||||
types: self.known_type_names(),
|
||||
location,
|
||||
})?
|
||||
.iter()
|
||||
|
@ -1840,15 +1952,7 @@ impl<'a> Environment<'a> {
|
|||
let module = self
|
||||
.importable_modules
|
||||
.get(full_module_name)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
location,
|
||||
name: name.to_string(),
|
||||
known_modules: self
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
})?;
|
||||
.ok_or_else(|| self.err_unknown_module(name.to_string(), location))?;
|
||||
|
||||
self.unused_modules.remove(full_module_name);
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use super::Type;
|
||||
use crate::{
|
||||
ast::{Annotation, BinOp, CallArg, LogicalOpChainKind, Span, UntypedFunction, UntypedPattern},
|
||||
ast::{
|
||||
Annotation, BinOp, CallArg, LogicalOpChainKind, Namespace, Span, UntypedFunction,
|
||||
UntypedPattern,
|
||||
},
|
||||
error::ExtraData,
|
||||
expr::{self, AssignmentPattern, UntypedAssignmentKind, UntypedExpr},
|
||||
format::Formatter,
|
||||
|
@ -395,7 +398,7 @@ From there, you can define 'increment', a function that takes a single argument
|
|||
expected: usize,
|
||||
given: Vec<CallArg<UntypedPattern>>,
|
||||
name: String,
|
||||
module: Option<String>,
|
||||
module: Option<Namespace>,
|
||||
is_record: bool,
|
||||
},
|
||||
|
||||
|
@ -718,7 +721,7 @@ Perhaps, try the following:
|
|||
label: String,
|
||||
name: String,
|
||||
args: Vec<CallArg<UntypedPattern>>,
|
||||
module: Option<String>,
|
||||
module: Option<Namespace>,
|
||||
spread_location: Option<Span>,
|
||||
},
|
||||
|
||||
|
@ -805,7 +808,7 @@ Perhaps, try the following:
|
|||
},
|
||||
|
||||
#[error(
|
||||
"I looked for '{}' in '{}' but couldn't find it.\n",
|
||||
"I looked for '{}' in module '{}' but couldn't find it.\n",
|
||||
name.if_supports_color(Stdout, |s| s.purple()),
|
||||
module_name.if_supports_color(Stdout, |s| s.purple())
|
||||
)]
|
||||
|
@ -819,7 +822,7 @@ Perhaps, try the following:
|
|||
)
|
||||
))]
|
||||
UnknownModuleType {
|
||||
#[label("unknown import")]
|
||||
#[label("not exported?")]
|
||||
location: Span,
|
||||
name: String,
|
||||
module_name: String,
|
||||
|
@ -1076,7 +1079,7 @@ The best thing to do from here is to remove it."#))]
|
|||
available_purposes: Vec<String>,
|
||||
},
|
||||
|
||||
#[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(help(
|
||||
"When referring to a validator handler via record access, you must refer to one of the declared handlers{}{}",
|
||||
|
@ -1092,7 +1095,7 @@ The best thing to do from here is to remove it."#))]
|
|||
available_handlers: Vec<String>,
|
||||
},
|
||||
|
||||
#[error("I caught an extraneous fallback handler in an already exhaustive validator\n")]
|
||||
#[error("I caught an extraneous fallback handler in an already exhaustive validator.\n")]
|
||||
#[diagnostic(code("extraneous::fallback"))]
|
||||
#[diagnostic(help(
|
||||
"Validator handlers must be exhaustive and either cover all purposes, or provide a fallback handler. Here, you have successfully covered all script purposes with your handler, but left an extraneous fallback branch. I cannot let that happen, but removing it for you would probably be deemed rude. So please, remove the fallback."
|
||||
|
@ -1101,6 +1104,16 @@ The best thing to do from here is to remove it."#))]
|
|||
#[label("redundant fallback handler")]
|
||||
fallback: Span,
|
||||
},
|
||||
|
||||
#[error("I was stopped by a suspicious field access chain.\n")]
|
||||
#[diagnostic(code("invalid::field_access"))]
|
||||
#[diagnostic(help(
|
||||
"It seems like you've got things mixed up a little here? You can only access fields exported by modules or, by types within those modules. Double-check the culprit field access chain, there's likely something wrong about it."
|
||||
))]
|
||||
InvalidFieldAccess {
|
||||
#[label("invalid field access")]
|
||||
location: Span,
|
||||
},
|
||||
}
|
||||
|
||||
impl ExtraData for Error {
|
||||
|
@ -1163,7 +1176,8 @@ impl ExtraData for Error {
|
|||
| Error::UnknownValidatorHandler { .. }
|
||||
| Error::UnexpectedValidatorFallback { .. }
|
||||
| Error::IncorrectBenchmarkArity { .. }
|
||||
| Error::MustInferFirst { .. } => None,
|
||||
| Error::MustInferFirst { .. }
|
||||
| Error::InvalidFieldAccess { .. } => None,
|
||||
|
||||
Error::UnknownType { name, .. }
|
||||
| Error::UnknownTypeConstructor { name, .. }
|
||||
|
@ -1274,7 +1288,7 @@ fn suggest_pattern(
|
|||
expected: usize,
|
||||
name: &str,
|
||||
given: &[CallArg<UntypedPattern>],
|
||||
module: &Option<String>,
|
||||
module: &Option<Namespace>,
|
||||
is_record: bool,
|
||||
) -> Option<String> {
|
||||
if expected > given.len() {
|
||||
|
@ -1309,7 +1323,7 @@ fn suggest_generic(name: &str, expected: usize) -> String {
|
|||
fn suggest_constructor_pattern(
|
||||
name: &str,
|
||||
args: &[CallArg<UntypedPattern>],
|
||||
module: &Option<String>,
|
||||
module: &Option<Namespace>,
|
||||
spread_location: Option<Span>,
|
||||
) -> String {
|
||||
let fixed_args = args
|
||||
|
@ -1527,13 +1541,14 @@ fn suggest_import_constructor() -> String {
|
|||
│ {keyword_pub} {keyword_type} {type_Pet} {{ │ {keyword_use} aiken/pet.{{{type_Pet}, {variant_Dog}}}
|
||||
│ {variant_Cat} │
|
||||
│ {variant_Dog} │ {keyword_fn} foo(pet: {type_Pet}) {{
|
||||
│ }} │ {keyword_when} pet {keyword_is} {{
|
||||
│ pet.{variant_Cat} -> // ...
|
||||
│ {variant_Fox} │ {keyword_when} pet {keyword_is} {{
|
||||
│ }} │ pet.{variant_Cat} -> // ...
|
||||
│ {variant_Dog} -> // ...
|
||||
│ {type_Pet}.{variant_Fox} -> // ...
|
||||
│ }}
|
||||
│ }}
|
||||
|
||||
You must import its constructors explicitly to use them, or prefix them with the module's name.
|
||||
You must import its constructors explicitly to use them, or prefix them with the module or type's name.
|
||||
"#
|
||||
, keyword_fn = "fn".if_supports_color(Stdout, |s| s.yellow())
|
||||
, keyword_is = "is".if_supports_color(Stdout, |s| s.yellow())
|
||||
|
@ -1550,6 +1565,9 @@ fn suggest_import_constructor() -> String {
|
|||
, variant_Dog = "Dog"
|
||||
.if_supports_color(Stdout, |s| s.bright_blue())
|
||||
.if_supports_color(Stdout, |s| s.bold())
|
||||
, variant_Fox = "Fox"
|
||||
.if_supports_color(Stdout, |s| s.bright_blue())
|
||||
.if_supports_color(Stdout, |s| s.bold())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,11 +11,11 @@ use super::{
|
|||
use crate::{
|
||||
ast::{
|
||||
self, Annotation, ArgName, AssignmentKind, AssignmentPattern, BinOp, Bls12_381Point,
|
||||
ByteArrayFormatPreference, CallArg, Curve, Function, IfBranch, LogicalOpChainKind, Pattern,
|
||||
RecordUpdateSpread, Span, TraceKind, TraceLevel, Tracing, TypedArg, TypedCallArg,
|
||||
TypedClause, TypedIfBranch, TypedPattern, TypedRecordUpdateArg, TypedValidator, UnOp,
|
||||
UntypedArg, UntypedAssignmentKind, UntypedClause, UntypedFunction, UntypedIfBranch,
|
||||
UntypedPattern, UntypedRecordUpdateArg,
|
||||
ByteArrayFormatPreference, CallArg, Curve, Function, IfBranch, LogicalOpChainKind,
|
||||
Namespace, Pattern, RecordUpdateSpread, Span, TraceKind, TraceLevel, Tracing, TypedArg,
|
||||
TypedCallArg, TypedClause, TypedIfBranch, TypedPattern, TypedRecordUpdateArg,
|
||||
TypedValidator, UnOp, UntypedArg, UntypedAssignmentKind, UntypedClause, UntypedFunction,
|
||||
UntypedIfBranch, UntypedPattern, UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::{from_default_function, BUILTIN},
|
||||
expr::{FnStyle, TypedExpr, UntypedExpr},
|
||||
|
@ -404,7 +404,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
module_alias,
|
||||
label,
|
||||
..
|
||||
} => (Some(module_alias), label),
|
||||
} => (Some(Namespace::Module(module_alias.to_string())), label),
|
||||
|
||||
TypedExpr::Var { name, .. } => (None, name),
|
||||
|
||||
|
@ -413,7 +413,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
|
||||
Ok(self
|
||||
.environment
|
||||
.get_value_constructor(module, name, location)?
|
||||
.get_value_constructor(module.as_ref(), name, location)?
|
||||
.field_map())
|
||||
}
|
||||
|
||||
|
@ -792,12 +792,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
args: Vec<UntypedRecordUpdateArg>,
|
||||
location: Span,
|
||||
) -> Result<TypedExpr, Error> {
|
||||
let (module, name): (Option<String>, String) = match self.infer(constructor.clone())? {
|
||||
let (module, name): (Option<Namespace>, String) = match self.infer(constructor.clone())? {
|
||||
TypedExpr::ModuleSelect {
|
||||
module_alias,
|
||||
label,
|
||||
..
|
||||
} => (Some(module_alias), label),
|
||||
} => (Some(Namespace::Module(module_alias)), label),
|
||||
|
||||
TypedExpr::Var { name, .. } => (None, name),
|
||||
|
||||
|
@ -1068,6 +1068,69 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
return shortcircuit;
|
||||
}
|
||||
|
||||
// In case where we find an uppercase var name in a record access chain, we treat the type
|
||||
// as a namespace and lookup the next constructor as if it were imported from the module's
|
||||
// the type originally belong to.
|
||||
match container {
|
||||
UntypedExpr::Var {
|
||||
name: ref type_name,
|
||||
location: type_location,
|
||||
} if TypeConstructor::might_be(type_name) => {
|
||||
return self.infer_type_constructor_access(
|
||||
(type_name, type_location),
|
||||
(
|
||||
&label,
|
||||
access_location.map(|start, end| (start + type_name.len() + 1, end)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
UntypedExpr::FieldAccess {
|
||||
location: type_location,
|
||||
label: ref type_name,
|
||||
container: ref type_container,
|
||||
} if TypeConstructor::might_be(type_name) => {
|
||||
if let UntypedExpr::Var {
|
||||
name: ref module_name,
|
||||
location: module_location,
|
||||
} = type_container.as_ref()
|
||||
{
|
||||
if TypeConstructor::might_be(module_name) {
|
||||
return Err(Error::InvalidFieldAccess {
|
||||
location: access_location,
|
||||
});
|
||||
}
|
||||
|
||||
// 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(|| {
|
||||
self.environment
|
||||
.err_unknown_module(module_name.to_string(), *module_location)
|
||||
})?;
|
||||
|
||||
return self.infer_inner_type_constructor_access(
|
||||
(module.name.as_str(), *module_location),
|
||||
(
|
||||
type_name,
|
||||
type_location.map(|start, end| (start + module_name.len() + 1, end)),
|
||||
),
|
||||
(
|
||||
&label,
|
||||
access_location.map(|start, end| {
|
||||
(start + module_name.len() + type_name.len() + 2, end)
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
|
||||
// Attempt to infer the container as a record access. If that fails, we may be shadowing the name
|
||||
// of an imported module, so attempt to infer the container as a module access.
|
||||
// TODO: Remove this cloning
|
||||
|
@ -1075,7 +1138,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Ok(record_access) => Ok(record_access),
|
||||
|
||||
Err(err) => match container {
|
||||
UntypedExpr::Var { name, location } => {
|
||||
UntypedExpr::Var { name, location } if !TypeConstructor::might_be(&name) => {
|
||||
let module_access =
|
||||
self.infer_module_access(&name, label, &location, access_location);
|
||||
|
||||
|
@ -1106,15 +1169,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
.environment
|
||||
.imported_modules
|
||||
.get(module_alias)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
name: module_alias.to_string(),
|
||||
location: *module_location,
|
||||
known_modules: self
|
||||
.environment
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
.ok_or_else(|| {
|
||||
self.environment
|
||||
.err_unknown_module(module_alias.to_string(), *module_location)
|
||||
})?;
|
||||
|
||||
let constructor =
|
||||
|
@ -1162,6 +1219,58 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::result_large_err)]
|
||||
fn infer_type_constructor_access(
|
||||
&mut self,
|
||||
(type_name, type_location): (&str, Span),
|
||||
(label, label_location): (&str, Span),
|
||||
) -> Result<TypedExpr, Error> {
|
||||
self.environment.increment_usage(type_name);
|
||||
|
||||
let parent_type = self
|
||||
.environment
|
||||
.module_types
|
||||
.get(type_name)
|
||||
.ok_or_else(|| Error::UnknownType {
|
||||
location: type_location,
|
||||
name: type_name.to_string(),
|
||||
types: self.environment.known_type_names(),
|
||||
})?;
|
||||
|
||||
let module_name = parent_type.module.clone();
|
||||
|
||||
self.infer_inner_type_constructor_access(
|
||||
(module_name.as_str(), type_location),
|
||||
(type_name, type_location),
|
||||
(label, label_location),
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::result_large_err)]
|
||||
fn infer_inner_type_constructor_access(
|
||||
&mut self,
|
||||
(module_name, module_location): (&str, Span),
|
||||
(type_name, type_location): (&str, Span),
|
||||
(label, label_location): (&str, Span),
|
||||
) -> Result<TypedExpr, Error> {
|
||||
self.environment.get_fully_qualified_value_constructor(
|
||||
(module_name, module_location),
|
||||
(type_name, type_location),
|
||||
(label, label_location),
|
||||
)?;
|
||||
|
||||
self.environment.unused_modules.remove(module_name);
|
||||
|
||||
self.infer_module_access(
|
||||
&self
|
||||
.environment
|
||||
.local_module_name(module_name, module_location)?,
|
||||
label.to_string(),
|
||||
&type_location,
|
||||
label_location,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::result_large_err)]
|
||||
fn infer_record_access(
|
||||
&mut self,
|
||||
|
@ -1169,9 +1278,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
label: String,
|
||||
location: Span,
|
||||
) -> Result<TypedExpr, Error> {
|
||||
// Infer the type of the (presumed) record
|
||||
// Infer the type of the (presumed) record.
|
||||
let record = self.infer(record)?;
|
||||
|
||||
self.infer_known_record_access(record, label, location)
|
||||
}
|
||||
|
||||
|
@ -2563,15 +2671,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
.environment
|
||||
.imported_modules
|
||||
.get(module_name)
|
||||
.ok_or_else(|| Error::UnknownModule {
|
||||
location: *location,
|
||||
name: module_name.to_string(),
|
||||
known_modules: self
|
||||
.environment
|
||||
.importable_modules
|
||||
.keys()
|
||||
.map(|t| t.to_string())
|
||||
.collect(),
|
||||
.ok_or_else(|| {
|
||||
self.environment
|
||||
.err_unknown_module(module_name.to_string(), *location)
|
||||
})?;
|
||||
|
||||
module
|
||||
|
|
|
@ -17,7 +17,12 @@ use crate::{
|
|||
tipo::{expr::infer_function, Span, Type, TypeVar},
|
||||
IdGenerator,
|
||||
};
|
||||
use std::{borrow::Borrow, collections::HashMap, ops::Deref, rc::Rc};
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
collections::{BTreeSet, HashMap},
|
||||
ops::Deref,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
impl UntypedModule {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -116,8 +121,14 @@ impl UntypedModule {
|
|||
.module_types
|
||||
.retain(|_, info| info.public && info.module == module_name);
|
||||
|
||||
let own_types = environment.module_types.keys().collect::<BTreeSet<_>>();
|
||||
|
||||
environment.module_values.retain(|_, info| info.public);
|
||||
|
||||
environment
|
||||
.module_types_constructors
|
||||
.retain(|k, _| own_types.contains(k));
|
||||
|
||||
environment
|
||||
.accessors
|
||||
.retain(|_, accessors| accessors.public);
|
||||
|
|
|
@ -6,7 +6,7 @@ use super::{
|
|||
hydrator::Hydrator,
|
||||
PatternConstructor, Type, ValueConstructorVariant,
|
||||
};
|
||||
use crate::ast::{CallArg, Pattern, Span, TypedPattern, UntypedPattern};
|
||||
use crate::ast::{CallArg, Namespace, Pattern, Span, TypedPattern, UntypedPattern};
|
||||
use itertools::Itertools;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
|
@ -467,7 +467,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
let arguments = field_map
|
||||
.fields
|
||||
.iter()
|
||||
.sorted_by(|(a, _), (b, _)| a.cmp(b))
|
||||
.sorted_by(|(_, (a, _)), (_, (b, _))| a.cmp(b))
|
||||
.zip(pattern_args.iter())
|
||||
.filter_map(|((field, (_, _)), arg)| {
|
||||
if arg.value.is_discard() {
|
||||
|
@ -570,7 +570,12 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
|
||||
Ok(Pattern::Constructor {
|
||||
location,
|
||||
module,
|
||||
// NOTE:
|
||||
// Type namespaces are completely erased during type-check.
|
||||
module: match module {
|
||||
None | Some(Namespace::Type(..)) => None,
|
||||
Some(Namespace::Module(m)) => Some(m),
|
||||
},
|
||||
name,
|
||||
arguments: pattern_args,
|
||||
constructor,
|
||||
|
@ -601,7 +606,12 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
|
||||
Ok(Pattern::Constructor {
|
||||
location,
|
||||
module,
|
||||
// NOTE:
|
||||
// Type namespaces are completely erased during type-check.
|
||||
module: match module {
|
||||
None | Some(Namespace::Type(..)) => None,
|
||||
Some(Namespace::Module(m)) => Some(m),
|
||||
},
|
||||
name,
|
||||
arguments: vec![],
|
||||
constructor,
|
||||
|
|
|
@ -731,7 +731,7 @@ impl Warning {
|
|||
|
||||
impl Debug for Warning {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
default_miette_handler(0)
|
||||
default_miette_handler(1)
|
||||
.debug(
|
||||
&DisplayWarning {
|
||||
title: &self.to_string(),
|
||||
|
|
Loading…
Reference in New Issue