Fix ordinal index on pairs

This commit is contained in:
KtorZ 2024-04-18 17:51:00 +02:00 committed by Kasey
parent 2cb2c7fa1f
commit 7cb548a749
4 changed files with 96 additions and 22 deletions

View File

@ -2349,3 +2349,52 @@ fn partial_eq_callback_return() {
Err((_, Error::CouldNotUnify { .. })) Err((_, Error::CouldNotUnify { .. }))
)); ));
} }
#[test]
fn pair_access_on_call() {
let source_code = r#"
use aiken/builtin
pub fn list_at(xs: List<a>, index: Int) -> a {
if index == 0 {
builtin.head_list(xs)
} else {
list_at(builtin.tail_list(xs), index - 1)
}
}
fn foo() {
[list_at([Pair(1, 2)], 0).2nd, ..[1, 2]]
}
"#;
assert!(check(parse(source_code)).is_ok())
}
#[test]
fn pair_index_out_of_bound() {
let source_code = r#"
pub fn foo() {
Pair(1, 2).3rd
}
"#;
assert!(matches!(
dbg!(check_validator(parse(source_code))),
Err((_, Error::PairIndexOutOfBound { .. }))
))
}
#[test]
fn not_indexable() {
let source_code = r#"
pub fn foo() {
"foo".1st
}
"#;
assert!(matches!(
dbg!(check_validator(parse(source_code))),
Err((_, Error::NotIndexable { .. }))
))
}

View File

@ -508,18 +508,16 @@ If you really meant to return that last expression, try to replace it with the f
name: String, name: String,
}, },
#[error( #[error("I tripped over an attempt to access elements on something that isn't indexable.\n")]
"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::indexable"))]
#[diagnostic(help( #[diagnostic(help(
r#"Because you used a tuple-index on an element, I assumed it had to be a tuple but instead I found something of type: r#"Because you used an ordinal index on an element, I assumed it had to be a tuple or a pair but instead I found something of type:
{type_info}"#, {type_info}"#,
type_info = tipo.to_pretty(0).if_supports_color(Stdout, |s| s.red()) type_info = tipo.to_pretty(0).if_supports_color(Stdout, |s| s.red())
))] ))]
NotATuple { NotIndexable {
#[label] #[label]
location: Span, location: Span,
tipo: Rc<Type>, tipo: Rc<Type>,
@ -675,12 +673,25 @@ You can help me by providing a type-annotation for 'x', as such:
#[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types#tuples"))] #[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types#tuples"))]
#[diagnostic(code("invalid::tuple_index"))] #[diagnostic(code("invalid::tuple_index"))]
TupleIndexOutOfBound { TupleIndexOutOfBound {
#[label] #[label("out of bounds")]
location: Span, location: Span,
index: usize, index: usize,
size: usize, size: usize,
}, },
#[error(
"I discovered an attempt to access the {} element of a {}.\n",
Ordinal(*index + 1).to_string().if_supports_color(Stdout, |s| s.purple()),
"Pair".if_supports_color(Stdout, |s| s.bright_blue()).if_supports_color(Stdout, |s| s.bold()),
)]
#[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types#pairs"))]
#[diagnostic(code("invalid::pair_index"))]
PairIndexOutOfBound {
#[label("out of bounds")]
location: Span,
index: usize,
},
#[error( #[error(
"I tripped over the following labeled argument: {}.\n", "I tripped over the following labeled argument: {}.\n",
label.if_supports_color(Stdout, |s| s.purple()) label.if_supports_color(Stdout, |s| s.purple())
@ -1035,7 +1046,7 @@ impl ExtraData for Error {
| Error::MissingVarInAlternativePattern { .. } | Error::MissingVarInAlternativePattern { .. }
| Error::MultiValidatorEqualArgs { .. } | Error::MultiValidatorEqualArgs { .. }
| Error::NonLocalClauseGuardVariable { .. } | Error::NonLocalClauseGuardVariable { .. }
| Error::NotATuple { .. } | Error::NotIndexable { .. }
| Error::NotExhaustivePatternMatch { .. } | Error::NotExhaustivePatternMatch { .. }
| Error::NotFn { .. } | Error::NotFn { .. }
| Error::PositionalArgumentAfterLabeled { .. } | Error::PositionalArgumentAfterLabeled { .. }
@ -1045,6 +1056,7 @@ impl ExtraData for Error {
| Error::RecursiveType { .. } | Error::RecursiveType { .. }
| Error::RedundantMatchClause { .. } | Error::RedundantMatchClause { .. }
| Error::TupleIndexOutOfBound { .. } | Error::TupleIndexOutOfBound { .. }
| Error::PairIndexOutOfBound { .. }
| Error::UnexpectedLabeledArg { .. } | Error::UnexpectedLabeledArg { .. }
| Error::UnexpectedLabeledArgInPattern { .. } | Error::UnexpectedLabeledArgInPattern { .. }
| Error::UnknownLabels { .. } | Error::UnknownLabels { .. }

View File

@ -2065,13 +2065,13 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
fn infer_tuple_index( fn infer_tuple_index(
&mut self, &mut self,
tuple: UntypedExpr, tuple_or_pair: UntypedExpr,
index: usize, index: usize,
location: Span, location: Span,
) -> Result<TypedExpr, Error> { ) -> Result<TypedExpr, Error> {
let tuple = self.infer(tuple)?; let tuple_or_pair = self.infer(tuple_or_pair)?;
let tipo = match *collapse_links(tuple.tipo()) { let tipo = match *collapse_links(tuple_or_pair.tipo()) {
Type::Tuple { Type::Tuple {
ref elems, ref elems,
alias: _, alias: _,
@ -2087,9 +2087,22 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Ok(elems[index].clone()) Ok(elems[index].clone())
} }
} }
_ => Err(Error::NotATuple { Type::Pair {
ref fst,
ref snd,
alias: _,
} => {
if index == 0 {
Ok(fst.clone())
} else if index == 1 {
Ok(snd.clone())
} else {
Err(Error::PairIndexOutOfBound { location, index })
}
}
_ => Err(Error::NotIndexable {
location, location,
tipo: tuple.tipo(), tipo: tuple_or_pair.tipo(),
}), }),
}?; }?;
@ -2097,7 +2110,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
location, location,
tipo, tipo,
index, index,
tuple: Box::new(tuple), tuple: Box::new(tuple_or_pair),
}) })
} }

View File

@ -2159,7 +2159,7 @@ fn acceptance_test_23_to_list() {
} }
test to_list_2() { test to_list_2() {
to_list(fixture_1()) == [Pair("foo", 42).2nd, Pair("bar", 14)] to_list(fixture_1()) == [Pair("foo", 42), Pair("bar", 14)]
} }
"#; "#;