chore: Add error when type casting without annotation

Also implement and test most of assert. Finishing last few cases.
This commit is contained in:
Kasey White 2023-01-28 02:40:53 -05:00
parent fc88028034
commit 60736b4a54
5 changed files with 681 additions and 255 deletions

View File

@ -204,8 +204,8 @@ pub enum Air {
FieldsExpose { FieldsExpose {
scope: Vec<u64>, scope: Vec<u64>,
count: usize,
indices: Vec<(usize, String, Arc<Type>)>, indices: Vec<(usize, String, Arc<Type>)>,
check_last_item: bool,
}, },
// ListAccess // ListAccess
@ -214,6 +214,7 @@ pub enum Air {
tipo: Arc<Type>, tipo: Arc<Type>,
names: Vec<String>, names: Vec<String>,
tail: bool, tail: bool,
check_last_item: bool,
}, },
ListExpose { ListExpose {
@ -228,6 +229,7 @@ pub enum Air {
scope: Vec<u64>, scope: Vec<u64>,
names: Vec<String>, names: Vec<String>,
tipo: Arc<Type>, tipo: Arc<Type>,
check_last_item: bool,
}, },
TupleIndex { TupleIndex {

View File

@ -4,7 +4,7 @@ use indexmap::{IndexMap, IndexSet};
use itertools::Itertools; use itertools::Itertools;
use uplc::{ use uplc::{
ast::{ ast::{
builder::{apply_wrap, if_else}, builder::{apply_wrap, choose_list, if_else},
Constant as UplcConstant, Name, Term, Type as UplcType, Constant as UplcConstant, Name, Term, Type as UplcType,
}, },
builtins::DefaultFunction, builtins::DefaultFunction,
@ -482,6 +482,7 @@ pub fn list_access_to_uplc(
current_index: usize, current_index: usize,
term: Term<Name>, term: Term<Name>,
tipo: &Type, tipo: &Type,
check_last_item: bool,
) -> Term<Name> { ) -> Term<Name> {
let (first, names) = names.split_first().unwrap(); let (first, names) = names.split_first().unwrap();
@ -546,30 +547,6 @@ pub fn list_access_to_uplc(
} else if names.is_empty() { } else if names.is_empty() {
// Maybe check list is actually empty or should we leave that to when .. is only // Maybe check list is actually empty or should we leave that to when .. is only
// this would replace term.into() if we decide to // this would replace term.into() if we decide to
// body: choose_list(
// apply_wrap(
// Term::Builtin(DefaultFunction::TailList).force_wrap(),
// Term::Var(Name {
// text: format!(
// "tail_index_{}_{}",
// current_index, id_list[current_index]
// ),
// unique: 0.into(),
// }),
// ),
// term,
// apply_wrap(
// apply_wrap(
// Term::Builtin(DefaultFunction::Trace).force_wrap(),
// Term::Constant(UplcConstant::String(
// "List contains more items".to_string(),
// )),
// ),
// Term::Delay(Term::Error.into()),
// )
// .force_wrap(),
// )
// .into(),
Term::Lambda { Term::Lambda {
parameter_name: Name { parameter_name: Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]), text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
@ -581,7 +558,34 @@ pub fn list_access_to_uplc(
text: first.clone(), text: first.clone(),
unique: 0.into(), unique: 0.into(),
}, },
body: term.into(), body: if check_last_item {
choose_list(
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Var(Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
}),
),
term,
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::Trace).force_wrap(),
Term::Constant(UplcConstant::String(
"List/Tuple contains more items than it should".to_string(),
)),
),
Term::Delay(Term::Error.into()),
)
.force_wrap(),
)
.into()
} else {
term.into()
},
}, },
apply_wrap( apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(), Term::Builtin(DefaultFunction::HeadList).force_wrap(),
@ -606,7 +610,15 @@ pub fn list_access_to_uplc(
unique: 0.into(), unique: 0.into(),
}, },
body: apply_wrap( body: apply_wrap(
list_access_to_uplc(names, id_list, tail, current_index + 1, term, tipo), list_access_to_uplc(
names,
id_list,
tail,
current_index + 1,
term,
tipo,
check_last_item,
),
apply_wrap( apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(), Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Var(Name { Term::Var(Name {
@ -1078,6 +1090,7 @@ pub fn monomorphize(
tipo, tipo,
names, names,
tail, tail,
check_last_item,
} => { } => {
if tipo.is_generic() { if tipo.is_generic() {
let mut tipo = tipo.clone(); let mut tipo = tipo.clone();
@ -1088,6 +1101,7 @@ pub fn monomorphize(
names, names,
tipo, tipo,
tail, tail,
check_last_item,
}; };
needs_variant = true; needs_variant = true;
} }
@ -1359,8 +1373,8 @@ pub fn monomorphize(
} }
Air::FieldsExpose { Air::FieldsExpose {
scope, scope,
count,
indices, indices,
check_last_item,
} => { } => {
let mut new_indices = vec![]; let mut new_indices = vec![];
for (ind, name, tipo) in indices { for (ind, name, tipo) in indices {
@ -1375,8 +1389,8 @@ pub fn monomorphize(
} }
new_air[index] = Air::FieldsExpose { new_air[index] = Air::FieldsExpose {
scope, scope,
count,
indices: new_indices, indices: new_indices,
check_last_item,
}; };
} }
Air::RecordUpdate { Air::RecordUpdate {
@ -1407,12 +1421,22 @@ pub fn monomorphize(
tipo, tipo,
}; };
} }
Air::TupleAccessor { scope, names, tipo } => { Air::TupleAccessor {
scope,
names,
tipo,
check_last_item,
} => {
if tipo.is_generic() { if tipo.is_generic() {
let mut tipo = tipo.clone(); let mut tipo = tipo.clone();
find_generics_to_replace(&mut tipo, &generic_types); find_generics_to_replace(&mut tipo, &generic_types);
new_air[index] = Air::TupleAccessor { scope, names, tipo }; new_air[index] = Air::TupleAccessor {
scope,
names,
tipo,
check_last_item,
};
needs_variant = true; needs_variant = true;
} }
} }

View File

@ -724,6 +724,15 @@ The best thing to do from here is to remove it."#))]
location: Span, location: Span,
name: String, name: String,
}, },
#[error("I discovered a type cast from Data without an annotation")]
#[diagnostic(code("illegal::type_cast"))]
#[diagnostic(help("Try adding an annotation...\n\n{}", format_suggestion(value)))]
CastDataNoAnn {
#[label]
location: Span,
value: UntypedExpr,
},
} }
impl Error { impl Error {

View File

@ -807,8 +807,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
annotation: &Option<Annotation>, annotation: &Option<Annotation>,
location: Span, location: Span,
) -> Result<TypedExpr, Error> { ) -> Result<TypedExpr, Error> {
let value = self.in_new_scope(|value_typer| value_typer.infer(value))?; let typed_value = self.in_new_scope(|value_typer| value_typer.infer(value.clone()))?;
let mut value_typ = value.tipo(); let mut value_typ = typed_value.tipo();
// Check that any type annotation is accurate. // Check that any type annotation is accurate.
let pattern = if let Some(ann) = annotation { let pattern = if let Some(ann) = annotation {
@ -819,7 +819,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
self.unify( self.unify(
ann_typ.clone(), ann_typ.clone(),
value_typ.clone(), value_typ.clone(),
value.type_defining_location(), typed_value.type_defining_location(),
)?; )?;
value_typ = ann_typ.clone(); value_typ = ann_typ.clone();
@ -831,6 +831,24 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Some(ann_typ), Some(ann_typ),
)? )?
} else { } else {
if value_typ.is_data() {
return Err(Error::CastDataNoAnn {
location,
value: UntypedExpr::Assignment {
location,
value: value.into(),
pattern,
kind,
annotation: Some(Annotation::Constructor {
location: Span::empty(),
module: None,
name: "Type".to_string(),
arguments: vec![],
}),
},
});
}
// Ensure the pattern matches the type of the value // Ensure the pattern matches the type of the value
PatternTyper::new(self.environment, &self.hydrator).unify( PatternTyper::new(self.environment, &self.hydrator).unify(
pattern, pattern,
@ -860,7 +878,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
tipo: value_typ, tipo: value_typ,
kind, kind,
pattern, pattern,
value: Box::new(value), value: Box::new(typed_value),
}) })
} }

File diff suppressed because it is too large Load Diff