chore: Add error when type casting without annotation
Also implement and test most of assert. Finishing last few cases.
This commit is contained in:
parent
fc88028034
commit
60736b4a54
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue