Fix display of 'UnknownLabels'
This is a bit annoying as we are forced to use #[related] here which isn't quite what we want. Ideally, this would use #[diagnostic_source] but, there's a bug upstream. See: zkat/miette#172.
This commit is contained in:
parent
d905f24e7f
commit
bb360cd7c8
|
@ -7,18 +7,49 @@ use crate::{
|
||||||
pretty::Documentable,
|
pretty::Documentable,
|
||||||
};
|
};
|
||||||
use indoc::formatdoc;
|
use indoc::formatdoc;
|
||||||
use miette::Diagnostic;
|
use miette::{Diagnostic, LabeledSpan};
|
||||||
use ordinal::Ordinal;
|
use ordinal::Ordinal;
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, fmt::Display, sync::Arc};
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Diagnostic)]
|
#[derive(Debug, thiserror::Error, Diagnostic)]
|
||||||
#[error("Something is wrong around here...")]
|
#[error("Something is possibly wrong here...")]
|
||||||
pub struct Snippet {
|
pub struct Snippet {
|
||||||
#[label]
|
#[label]
|
||||||
pub location: Span,
|
pub location: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
#[error(
|
||||||
|
"I don't know some of the labels used in this expression. I've highlighted them just below."
|
||||||
|
)]
|
||||||
|
pub struct UnknownLabels {
|
||||||
|
pub unknown: Vec<Span>,
|
||||||
|
pub valid: Vec<String>,
|
||||||
|
pub supplied: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Diagnostic for UnknownLabels {
|
||||||
|
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||||
|
Some(Box::new(formatdoc! {
|
||||||
|
r#"Here's a list of all the (valid) labels that I know of:
|
||||||
|
|
||||||
|
{known_labels}"#
|
||||||
|
, known_labels = self.valid
|
||||||
|
.iter()
|
||||||
|
.map(|s| format!("─▶ {}", s.yellow()))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
|
||||||
|
Some(Box::new(self.unknown.iter().map(|l| {
|
||||||
|
LabeledSpan::new_with_span(Some("?".to_string()), *l)
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, Diagnostic)]
|
#[derive(Debug, thiserror::Error, Diagnostic)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("I found two function arguments both called '{}'.\n", label.purple())]
|
#[error("I found two function arguments both called '{}'.\n", label.purple())]
|
||||||
|
@ -114,7 +145,7 @@ You can use '{discard}' and numbers to distinguish between similar names.
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I found a data type that has a function type in it. This is not allowed.")]
|
#[error("I found a data type that has a function type in it. This is not allowed.\n")]
|
||||||
#[diagnostic(code("illegal::function_in_type"))]
|
#[diagnostic(code("illegal::function_in_type"))]
|
||||||
#[diagnostic(help("Data-types can't hold functions. If you want to define method-like functions, group the type definition and the methods under a common namespace in a standalone module."))]
|
#[diagnostic(help("Data-types can't hold functions. If you want to define method-like functions, group the type definition and the methods under a common namespace in a standalone module."))]
|
||||||
FunctionTypeInData {
|
FunctionTypeInData {
|
||||||
|
@ -122,7 +153,7 @@ You can use '{discard}' and numbers to distinguish between similar names.
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I found a discarded expression not bound to a variable.")]
|
#[error("I found a discarded expression not bound to a variable.\n")]
|
||||||
#[diagnostic(code("implicit_discard"))]
|
#[diagnostic(code("implicit_discard"))]
|
||||||
#[diagnostic(help("A function can contain a sequence of expressions. However, any expression but the last one must be assign to a variable using the {keyword_let} keyword. If you really wish to discard an expression that is unused, you can assign it to '{discard}'."
|
#[diagnostic(help("A function can contain a sequence of expressions. However, any expression but the last one must be assign to a variable using the {keyword_let} keyword. If you really wish to discard an expression that is unused, you can assign it to '{discard}'."
|
||||||
, keyword_let = "let".yellow()
|
, keyword_let = "let".yellow()
|
||||||
|
@ -133,7 +164,7 @@ You can use '{discard}' and numbers to distinguish between similar names.
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I discovered a function which is ending with an assignment.")]
|
#[error("I discovered a function which is ending with an assignment.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/functions#named-functions"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/functions#named-functions"))]
|
||||||
#[diagnostic(code("illegal::return"))]
|
#[diagnostic(code("illegal::return"))]
|
||||||
#[diagnostic(help(r#"In Aiken, functions must return an explicit result in the form of an expression. While assignments are technically speaking expressions, they aren't allowed to be the last expression of a function because they convey a different meaning and this could be error-prone.
|
#[diagnostic(help(r#"In Aiken, functions must return an explicit result in the form of an expression. While assignments are technically speaking expressions, they aren't allowed to be the last expression of a function because they convey a different meaning and this could be error-prone.
|
||||||
|
@ -267,7 +298,7 @@ Perhaps, try the following:
|
||||||
given: usize,
|
given: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I realized that a given 'when/is' expression is non-exhaustive.")]
|
#[error("I realized that a given 'when/is' expression is non-exhaustive.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/control-flow#matching"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/control-flow#matching"))]
|
||||||
#[diagnostic(code("non_exhaustive_pattern_match"))]
|
#[diagnostic(code("non_exhaustive_pattern_match"))]
|
||||||
#[diagnostic(help(r#"When clauses must be exhaustive -- that is, they must cover all possible cases of the type they match. While it is recommended to have an explicit branch for each constructor, you can also use the wildcard '{discard}' as a last branch to match any remaining result.
|
#[diagnostic(help(r#"When clauses must be exhaustive -- that is, they must cover all possible cases of the type they match. While it is recommended to have an explicit branch for each constructor, you can also use the wildcard '{discard}' as a last branch to match any remaining result.
|
||||||
|
@ -288,7 +319,7 @@ In this particular instance, the following cases are missing:
|
||||||
unmatched: Vec<String>,
|
unmatched: Vec<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I tripped over a call attempt on something that isn't a function.")]
|
#[error("I tripped over a call attempt on something that isn't a function.\n")]
|
||||||
#[diagnostic(code("illegal::invoke"))]
|
#[diagnostic(code("illegal::invoke"))]
|
||||||
#[diagnostic(help(r#"It seems like you're trying to call something that isn't a function. I am inferring the following type:
|
#[diagnostic(help(r#"It seems like you're trying to call something that isn't a function. I am inferring the following type:
|
||||||
|
|
||||||
|
@ -302,7 +333,7 @@ In this particular instance, the following cases are missing:
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
"I realized the module '{}' contains the keyword '{}', which is forbidden.",
|
"I realized the module '{}' contains the keyword '{}', which is forbidden.\n",
|
||||||
name.purple(),
|
name.purple(),
|
||||||
keyword.purple()
|
keyword.purple()
|
||||||
)]
|
)]
|
||||||
|
@ -323,7 +354,7 @@ In this particular instance, the following cases are missing:
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I discovered a positional argument after a label argument.")]
|
#[error("I discovered a positional argument after a label argument.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/functions#labeled-arguments"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/functions#labeled-arguments"))]
|
||||||
#[diagnostic(code("unexpected::positional_argument"))]
|
#[diagnostic(code("unexpected::positional_argument"))]
|
||||||
#[diagnostic(help(r#"You can mix positional and labeled arguments, but you must put all positional arguments (i.e. without label) at the front.
|
#[diagnostic(help(r#"You can mix positional and labeled arguments, but you must put all positional arguments (i.e. without label) at the front.
|
||||||
|
@ -335,7 +366,7 @@ To fix this, you'll need to either turn that argument as a labeled argument, or
|
||||||
labeled_arg_location: Span,
|
labeled_arg_location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I caught a private value trying to escape.")]
|
#[error("I caught a private value trying to escape.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/modules"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/modules"))]
|
||||||
#[diagnostic(code("private_leak"))]
|
#[diagnostic(code("private_leak"))]
|
||||||
#[diagnostic(help(r#"I found a public value that is making use of a private type. This would prevent other modules from actually using that value because they wouldn't know what this type refer to.
|
#[diagnostic(help(r#"I found a public value that is making use of a private type. This would prevent other modules from actually using that value because they wouldn't know what this type refer to.
|
||||||
|
@ -354,7 +385,7 @@ Maybe you meant to turn it public using the '{keyword_pub}' keyword?"#
|
||||||
leaked: Type,
|
leaked: Type,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I couldn't figure out the type of a record you're trying to access.")]
|
#[error("I couldn't figure out the type of a record you're trying to access.\n")]
|
||||||
#[diagnostic(url(
|
#[diagnostic(url(
|
||||||
"https://aiken-lang.org/language-tour/variables-and-constants#type-annotations"
|
"https://aiken-lang.org/language-tour/variables-and-constants#type-annotations"
|
||||||
))]
|
))]
|
||||||
|
@ -381,7 +412,7 @@ You can help me by providing a type-annotation for 'x', as such:
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I tripped over an invalid constructor in a record update.")]
|
#[error("I tripped over an invalid constructor in a record update.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
||||||
#[diagnostic(code("illegal::record_update"))]
|
#[diagnostic(code("illegal::record_update"))]
|
||||||
RecordUpdateInvalidConstructor {
|
RecordUpdateInvalidConstructor {
|
||||||
|
@ -433,31 +464,16 @@ Perhaps, try the following:
|
||||||
|
|
||||||
// TODO: Seems like we can't really trigger this error because we allow type holes everywhere
|
// TODO: Seems like we can't really trigger this error because we allow type holes everywhere
|
||||||
// anyway. We need to revise that perhaps.
|
// anyway. We need to revise that perhaps.
|
||||||
#[error("I stumbled upon an unexpected type hole.")]
|
#[error("I stumbled upon an unexpected type hole.\n")]
|
||||||
#[diagnostic(code("unexpected::type_hole"))]
|
#[diagnostic(code("unexpected::type_hole"))]
|
||||||
UnexpectedTypeHole {
|
UnexpectedTypeHole {
|
||||||
#[label]
|
#[label]
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I tripped over some unknown labels in a pattern or function.")]
|
#[error("I tripped over some unknown labels in a pattern or function.\n")]
|
||||||
#[diagnostic(code("unknown::labels"))]
|
#[diagnostic(code("unknown::labels"))]
|
||||||
#[diagnostic(help(r#"I don't know some of the labels used in this expression. I've highlighted them just above.
|
UnknownLabels(#[related] Vec<UnknownLabels>),
|
||||||
|
|
||||||
Here's a list of all the (valid) labels that I know of:
|
|
||||||
|
|
||||||
{known_labels}"#
|
|
||||||
, known_labels = valid
|
|
||||||
.iter()
|
|
||||||
.map(|s| format!("─▶ {s}"))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("")
|
|
||||||
))]
|
|
||||||
UnknownLabels {
|
|
||||||
unknown: Vec<(String, Span)>,
|
|
||||||
valid: Vec<String>,
|
|
||||||
supplied: Vec<String>,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("I stumbled upon a reference to an unknown module: '{}'\n", name.purple())]
|
#[error("I stumbled upon a reference to an unknown module: '{}'\n", name.purple())]
|
||||||
#[diagnostic(code("unknown::module"))]
|
#[diagnostic(code("unknown::module"))]
|
||||||
|
@ -473,7 +489,7 @@ Here's a list of all the (valid) labels that I know of:
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
"I found an unknown import '{}' from module '{}'",
|
"I found an unknown import '{}' from module '{}'.\n",
|
||||||
name.purple(),
|
name.purple(),
|
||||||
module_name.purple()
|
module_name.purple()
|
||||||
)]
|
)]
|
||||||
|
@ -532,7 +548,7 @@ Here's a list of all the (valid) labels that I know of:
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
"I looked for the field '{}' in a record of type '{}' couldn't find it.",
|
"I looked for the field '{}' in a record of type '{}' couldn't find it.\n",
|
||||||
label.purple(),
|
label.purple(),
|
||||||
typ.to_pretty(4).purple()
|
typ.to_pretty(4).purple()
|
||||||
)]
|
)]
|
||||||
|
@ -597,7 +613,7 @@ Here's a list of all the (valid) labels that I know of:
|
||||||
constructors: Vec<String>,
|
constructors: Vec<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I discovered a redundant spread operator.")]
|
#[error("I discovered a redundant spread operator.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/control-flow#destructuring"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/control-flow#destructuring"))]
|
||||||
#[diagnostic(code("unexpected::spread_operator"))]
|
#[diagnostic(code("unexpected::spread_operator"))]
|
||||||
#[diagnostic(help(r#"The spread operator comes in handy when matching on some fields of a constructor. However, here you've matched all {arity} fields of the constructor which makes the spread operator redundant.
|
#[diagnostic(help(r#"The spread operator comes in handy when matching on some fields of a constructor. However, here you've matched all {arity} fields of the constructor which makes the spread operator redundant.
|
||||||
|
@ -609,7 +625,7 @@ The best thing to do from here is to remove it."#))]
|
||||||
arity: usize,
|
arity: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I tripped over a record-update on a data-type with more than one constructor.")]
|
#[error("I tripped over a record-update on a data-type with more than one constructor.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
||||||
#[diagnostic(code("illegal::record_update"))]
|
#[diagnostic(code("illegal::record_update"))]
|
||||||
UpdateMultiConstructorType {
|
UpdateMultiConstructorType {
|
||||||
|
@ -617,7 +633,7 @@ The best thing to do from here is to remove it."#))]
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I struggled to unify the types of two expressions.")]
|
#[error("I struggled to unify the types of two expressions.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types"))]
|
||||||
#[diagnostic(code("type_mismatch"))]
|
#[diagnostic(code("type_mismatch"))]
|
||||||
#[diagnostic(help("{}", suggest_unify(expected, given, situation, rigid_type_names)))]
|
#[diagnostic(help("{}", suggest_unify(expected, given, situation, rigid_type_names)))]
|
||||||
|
@ -652,7 +668,7 @@ The best thing to do from here is to remove it."#))]
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I realized the variable '{}' was mentioned more than once in an alternative pattern.\n \n", name.purple())]
|
#[error("I realized the variable '{}' was mentioned more than once in an alternative pattern.\n", name.purple())]
|
||||||
#[diagnostic(url(
|
#[diagnostic(url(
|
||||||
"https://aiken-lang.org/language-tour/control-flow#alternative-clause-patterns"
|
"https://aiken-lang.org/language-tour/control-flow#alternative-clause-patterns"
|
||||||
))]
|
))]
|
||||||
|
@ -663,7 +679,7 @@ The best thing to do from here is to remove it."#))]
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I almost got caught in an infinite cycle of type definitions.")]
|
#[error("I almost got caught in an infinite cycle of type definitions.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#type-aliases"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#type-aliases"))]
|
||||||
#[diagnostic(code("cycle"))]
|
#[diagnostic(code("cycle"))]
|
||||||
CyclicTypeDefinitions {
|
CyclicTypeDefinitions {
|
||||||
|
@ -671,7 +687,7 @@ The best thing to do from here is to remove it."#))]
|
||||||
errors: Vec<Snippet>,
|
errors: Vec<Snippet>,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I almost got caught in an endless loop while inferring a recursive type.")]
|
#[error("I almost got caught in an endless loop while inferring a recursive type.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#type-annotations"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#type-annotations"))]
|
||||||
#[diagnostic(code("missing::type_annotation"))]
|
#[diagnostic(code("missing::type_annotation"))]
|
||||||
#[diagnostic(help("I have several aptitudes, but inferring recursive types isn't one them. It is still possible to define recursive types just fine, but I will need a little help in the form of type annotation to infer their types should they show up."))]
|
#[diagnostic(help("I have several aptitudes, but inferring recursive types isn't one them. It is still possible to define recursive types just fine, but I will need a little help in the form of type annotation to infer their types should they show up."))]
|
||||||
|
@ -680,7 +696,9 @@ The best thing to do from here is to remove it."#))]
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I tripped over an attempt to access tuple elements on something else than a tuple.")]
|
#[error(
|
||||||
|
"I tripped over an attempt to access tuple elements on something else than a tuple.\n"
|
||||||
|
)]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types#tuples"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types#tuples"))]
|
||||||
#[diagnostic(code("illegal::tuple_index"))]
|
#[diagnostic(code("illegal::tuple_index"))]
|
||||||
#[diagnostic(help(r#"Because you used a tuple-index on an element, I assumed it had to be a tuple or some kind, but instead I found:
|
#[diagnostic(help(r#"Because you used a tuple-index on an element, I assumed it had to be a tuple or some kind, but instead I found:
|
||||||
|
@ -695,7 +713,7 @@ The best thing to do from here is to remove it."#))]
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
"I discovered an attempt to access the {} element of a {}-tuple.",
|
"I discovered an attempt to access the {} element of a {}-tuple.\n",
|
||||||
Ordinal(*index + 1).to_string().purple(),
|
Ordinal(*index + 1).to_string().purple(),
|
||||||
size.purple()
|
size.purple()
|
||||||
)]
|
)]
|
||||||
|
@ -1013,7 +1031,7 @@ fn suggest_import_constructor() -> String {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, thiserror::Error, Diagnostic)]
|
#[derive(Debug, PartialEq, Clone, thiserror::Error, Diagnostic)]
|
||||||
pub enum Warning {
|
pub enum Warning {
|
||||||
#[error("I found a todo left in the code.")]
|
#[error("I found a todo left in the code.\n")]
|
||||||
#[diagnostic(help("You probably want to replace that one with real code... eventually."))]
|
#[diagnostic(help("You probably want to replace that one with real code... eventually."))]
|
||||||
#[diagnostic(code("todo"))]
|
#[diagnostic(code("todo"))]
|
||||||
Todo {
|
Todo {
|
||||||
|
@ -1023,7 +1041,9 @@ pub enum Warning {
|
||||||
tipo: Arc<Type>,
|
tipo: Arc<Type>,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I realized the following expression returned a result that is implicitly discarded.")]
|
#[error(
|
||||||
|
"I realized the following expression returned a result that is implicitly discarded.\n"
|
||||||
|
)]
|
||||||
#[diagnostic(help(
|
#[diagnostic(help(
|
||||||
"You can use the '_' symbol should you want to explicitly discard a result."
|
"You can use the '_' symbol should you want to explicitly discard a result."
|
||||||
))]
|
))]
|
||||||
|
@ -1033,21 +1053,21 @@ pub enum Warning {
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I found a literal that is unused.")]
|
#[error("I found a literal that is unused.\n")]
|
||||||
#[diagnostic(code("unused::literal"))]
|
#[diagnostic(code("unused::literal"))]
|
||||||
UnusedLiteral {
|
UnusedLiteral {
|
||||||
#[label]
|
#[label]
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I found a public definition in a validator module.\nDefinitions in validator modules do not need to be public.")]
|
#[error("I found a public definition in a validator module.\nDefinitions in validator modules do not need to be public.\n")]
|
||||||
#[diagnostic(code("redundant::pub"))]
|
#[diagnostic(code("redundant::pub"))]
|
||||||
PubInValidatorModule {
|
PubInValidatorModule {
|
||||||
#[label]
|
#[label]
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I found a record update with no fields; effectively updating nothing.")]
|
#[error("I found a record update with no fields; effectively updating nothing.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
||||||
#[diagnostic(code("record_update::no_fields"))]
|
#[diagnostic(code("record_update::no_fields"))]
|
||||||
NoFieldsRecordUpdate {
|
NoFieldsRecordUpdate {
|
||||||
|
@ -1055,7 +1075,7 @@ pub enum Warning {
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("I found a record update using all fields; thus redundant.")]
|
#[error("I found a record update using all fields; thus redundant.\n")]
|
||||||
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#record-updates"))]
|
||||||
#[diagnostic(code("record_update::all_fields"))]
|
#[diagnostic(code("record_update::all_fields"))]
|
||||||
AllFieldsRecordUpdate {
|
AllFieldsRecordUpdate {
|
||||||
|
|
|
@ -955,7 +955,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
|
|
||||||
let then = clause_typer.infer(then)?;
|
let then = clause_typer.infer(then)?;
|
||||||
|
|
||||||
Ok((guard, then, typed_pattern, typed_alternatives))
|
Ok::<_, Error>((guard, then, typed_pattern, typed_alternatives))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Clause {
|
Ok(Clause {
|
||||||
|
@ -1942,7 +1942,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
let subject = self.in_new_scope(|subject_typer| {
|
let subject = self.in_new_scope(|subject_typer| {
|
||||||
let subject = subject_typer.infer(subject)?;
|
let subject = subject_typer.infer(subject)?;
|
||||||
|
|
||||||
Ok(subject)
|
Ok::<_, Error>(subject)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
subject_types.push(subject.tipo());
|
subject_types.push(subject.tipo());
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::error::Error;
|
use super::error::{Error, UnknownLabels};
|
||||||
use crate::ast::{CallArg, Span};
|
use crate::ast::{CallArg, Span};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -106,20 +106,16 @@ impl FieldMap {
|
||||||
|
|
||||||
let (position, duplicate_location) = match self.fields.get(label) {
|
let (position, duplicate_location) = match self.fields.get(label) {
|
||||||
None => {
|
None => {
|
||||||
unknown_labels.push((label.clone(), location));
|
unknown_labels.push(location);
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(&p) => p,
|
Some(&p) => p,
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the argument is already in the right place
|
// If the argument is already in the right place
|
||||||
if position == i {
|
if position == i {
|
||||||
seen_labels.insert(label.clone());
|
seen_labels.insert(label.clone());
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
} else {
|
} else {
|
||||||
if seen_labels.contains(label) {
|
if seen_labels.contains(label) {
|
||||||
|
@ -139,13 +135,13 @@ impl FieldMap {
|
||||||
if unknown_labels.is_empty() {
|
if unknown_labels.is_empty() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let valid = self.fields.keys().map(|t| t.to_string()).collect();
|
let valid = self.fields.keys().map(|t| t.to_string()).sorted().collect();
|
||||||
|
|
||||||
Err(Error::UnknownLabels {
|
Err(Error::UnknownLabels(vec![UnknownLabels {
|
||||||
valid,
|
valid,
|
||||||
unknown: unknown_labels,
|
unknown: unknown_labels,
|
||||||
supplied: seen_labels.into_iter().collect(),
|
supplied: seen_labels.into_iter().collect(),
|
||||||
})
|
}]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,7 @@ fn infer_definition(
|
||||||
|
|
||||||
let safe_to_generalise = !expr_typer.ungeneralised_function_used;
|
let safe_to_generalise = !expr_typer.ungeneralised_function_used;
|
||||||
|
|
||||||
Ok((tipo, args, body, safe_to_generalise))
|
Ok::<_, Error>((tipo, args, body, safe_to_generalise))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Assert that the inferred type matches the type of any recursive call
|
// Assert that the inferred type matches the type of any recursive call
|
||||||
|
|
|
@ -531,7 +531,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
||||||
|
|
||||||
let value = self.unify(value, typ.clone(), None)?;
|
let value = self.unify(value, typ.clone(), None)?;
|
||||||
|
|
||||||
Ok(CallArg {
|
Ok::<_, Error>(CallArg {
|
||||||
value,
|
value,
|
||||||
location,
|
location,
|
||||||
label,
|
label,
|
||||||
|
|
Loading…
Reference in New Issue