Rework 'compact' mode for traces
- Trace-if-false are now completely discarded in compact mode. - Only the label (i.e. first trace argument) is preserved. - When compiling with tracing _compact_, the first label MUST unify to a string. This shouldn't be an issue generally speaking and would enforce that traces follow the pattern ``` label: arg_0[, arg_1, ..., arg_n] ``` Note that what isn't obvious with these changes is that we now support what the "emit" keyword was trying to achieve; as we compile now with user-defined traces only, and in compact mode to only keep event labels in the final contract; while allowing larger payloads with verbose tracing.
This commit is contained in:
parent
a9d782e206
commit
d6fd37c80e
|
@ -1957,6 +1957,10 @@ pub enum TraceLevel {
|
|||
}
|
||||
|
||||
impl Tracing {
|
||||
pub fn verbose() -> Self {
|
||||
Tracing::All(TraceLevel::Verbose)
|
||||
}
|
||||
|
||||
pub fn silent() -> Self {
|
||||
Tracing::All(TraceLevel::Silent)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ fn check_module(
|
|||
ast: UntypedModule,
|
||||
extra: Vec<(String, UntypedModule)>,
|
||||
kind: ModuleKind,
|
||||
tracing: Tracing,
|
||||
) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
|
||||
let id_gen = IdGenerator::new();
|
||||
|
||||
|
@ -47,7 +48,7 @@ fn check_module(
|
|||
kind,
|
||||
"test/project",
|
||||
&module_types,
|
||||
Tracing::All(TraceLevel::Verbose),
|
||||
tracing,
|
||||
&mut warnings,
|
||||
);
|
||||
|
||||
|
@ -57,20 +58,27 @@ fn check_module(
|
|||
}
|
||||
|
||||
fn check(ast: UntypedModule) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
|
||||
check_module(ast, Vec::new(), ModuleKind::Lib)
|
||||
check_module(ast, Vec::new(), ModuleKind::Lib, Tracing::verbose())
|
||||
}
|
||||
|
||||
fn check_with_verbosity(
|
||||
ast: UntypedModule,
|
||||
level: TraceLevel,
|
||||
) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
|
||||
check_module(ast, Vec::new(), ModuleKind::Lib, Tracing::All(level))
|
||||
}
|
||||
|
||||
fn check_with_deps(
|
||||
ast: UntypedModule,
|
||||
extra: Vec<(String, UntypedModule)>,
|
||||
) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
|
||||
check_module(ast, extra, ModuleKind::Lib)
|
||||
check_module(ast, extra, ModuleKind::Lib, Tracing::verbose())
|
||||
}
|
||||
|
||||
fn check_validator(
|
||||
ast: UntypedModule,
|
||||
) -> Result<(Vec<Warning>, TypedModule), (Vec<Warning>, Error)> {
|
||||
check_module(ast, Vec::new(), ModuleKind::Validator)
|
||||
check_module(ast, Vec::new(), ModuleKind::Validator, Tracing::verbose())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1288,8 +1296,32 @@ fn trace_non_strings() {
|
|||
True
|
||||
}
|
||||
"#;
|
||||
assert!(check(parse(source_code)).is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_string_label_compact() {
|
||||
let source_code = r#"
|
||||
test foo() {
|
||||
trace @"foo": [1,2,3]
|
||||
True
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(check(parse(source_code)).is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_non_string_label_compact() {
|
||||
let source_code = r#"
|
||||
test foo() {
|
||||
trace(14 + 42)
|
||||
True
|
||||
}
|
||||
"#;
|
||||
|
||||
assert!(matches!(
|
||||
check(parse(source_code)),
|
||||
check_with_verbosity(parse(source_code), TraceLevel::Compact),
|
||||
Err((_, Error::CouldNotUnify { .. }))
|
||||
))
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ use crate::{
|
|||
},
|
||||
expr::{FnStyle, TypedExpr, UntypedExpr},
|
||||
format,
|
||||
line_numbers::LineNumbers,
|
||||
tipo::{fields::FieldMap, DefaultFunction, PatternConstructor, TypeVar},
|
||||
IdGenerator,
|
||||
};
|
||||
|
@ -41,7 +40,6 @@ pub(crate) fn infer_function(
|
|||
module_name: &str,
|
||||
hydrators: &mut HashMap<String, Hydrator>,
|
||||
environment: &mut Environment<'_>,
|
||||
lines: &LineNumbers,
|
||||
tracing: Tracing,
|
||||
) -> Result<Function<Rc<Type>, TypedExpr, TypedArg>, Error> {
|
||||
if let Some(typed_fun) = environment.inferred_functions.get(&fun.name) {
|
||||
|
@ -122,7 +120,7 @@ pub(crate) fn infer_function(
|
|||
.remove(name)
|
||||
.unwrap_or_else(|| panic!("Could not find hydrator for fn {name}"));
|
||||
|
||||
let mut expr_typer = ExprTyper::new(environment, lines, tracing);
|
||||
let mut expr_typer = ExprTyper::new(environment, tracing);
|
||||
expr_typer.hydrator = hydrator;
|
||||
expr_typer.not_yet_inferred = BTreeSet::from_iter(hydrators.keys().cloned());
|
||||
|
||||
|
@ -155,12 +153,11 @@ pub(crate) fn infer_function(
|
|||
environment.current_module,
|
||||
hydrators,
|
||||
environment,
|
||||
lines,
|
||||
tracing,
|
||||
)?;
|
||||
|
||||
// Then, try again the entire function definition.
|
||||
return infer_function(fun, module_name, hydrators, environment, lines, tracing);
|
||||
return infer_function(fun, module_name, hydrators, environment, tracing);
|
||||
}
|
||||
|
||||
let (arguments, body, return_type) = inferred?;
|
||||
|
@ -223,8 +220,6 @@ pub(crate) fn infer_function(
|
|||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ExprTyper<'a, 'b> {
|
||||
pub(crate) lines: &'a LineNumbers,
|
||||
|
||||
pub(crate) environment: &'a mut Environment<'b>,
|
||||
|
||||
// We tweak the tracing behavior during type-check. Traces are either kept or left out of the
|
||||
|
@ -244,18 +239,13 @@ pub(crate) struct ExprTyper<'a, 'b> {
|
|||
}
|
||||
|
||||
impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||
pub fn new(
|
||||
environment: &'a mut Environment<'b>,
|
||||
lines: &'a LineNumbers,
|
||||
tracing: Tracing,
|
||||
) -> Self {
|
||||
pub fn new(environment: &'a mut Environment<'b>, tracing: Tracing) -> Self {
|
||||
Self {
|
||||
hydrator: Hydrator::new(),
|
||||
not_yet_inferred: BTreeSet::new(),
|
||||
environment,
|
||||
tracing,
|
||||
ungeneralised_function_used: false,
|
||||
lines,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -681,25 +671,16 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
.to_pretty_string(999)
|
||||
),
|
||||
}),
|
||||
TraceLevel::Compact => Some(TypedExpr::String {
|
||||
location,
|
||||
tipo: string(),
|
||||
value: self
|
||||
.lines
|
||||
.line_and_column_number(location.start)
|
||||
.expect("Spans are within bounds.")
|
||||
.to_string(),
|
||||
}),
|
||||
TraceLevel::Silent => None,
|
||||
TraceLevel::Compact | TraceLevel::Silent => None,
|
||||
};
|
||||
|
||||
let typed_value = self.infer(value)?;
|
||||
|
||||
self.unify(bool(), typed_value.tipo(), typed_value.location(), false)?;
|
||||
|
||||
match self.tracing.trace_level(false) {
|
||||
TraceLevel::Silent => Ok(typed_value),
|
||||
TraceLevel::Verbose | TraceLevel::Compact => Ok(TypedExpr::If {
|
||||
match text {
|
||||
None => Ok(typed_value),
|
||||
Some(text) => Ok(TypedExpr::If {
|
||||
location,
|
||||
branches: vec1::vec1![IfBranch {
|
||||
condition: typed_value,
|
||||
|
@ -710,7 +691,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
final_else: Box::new(TypedExpr::Trace {
|
||||
location,
|
||||
tipo: bool(),
|
||||
text: Box::new(text.expect("TraceLevel::Silent excluded from pattern-guard")),
|
||||
text: Box::new(text),
|
||||
then: Box::new(var_false),
|
||||
}),
|
||||
tipo: bool(),
|
||||
|
@ -2426,13 +2407,36 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
label: UntypedExpr,
|
||||
arguments: Vec<UntypedExpr>,
|
||||
) -> Result<TypedExpr, Error> {
|
||||
let label = self.infer_trace_arg(label)?;
|
||||
|
||||
let typed_arguments = arguments
|
||||
.into_iter()
|
||||
.map(|arg| self.infer_trace_arg(arg))
|
||||
.collect::<Result<Vec<_>, Error>>()?;
|
||||
|
||||
let then = self.infer(then)?;
|
||||
let tipo = then.tipo();
|
||||
|
||||
if let TraceKind::Todo = kind {
|
||||
self.environment.warnings.push(Warning::Todo {
|
||||
location,
|
||||
tipo: tipo.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
match self.tracing.trace_level(false) {
|
||||
TraceLevel::Silent => Ok(then),
|
||||
TraceLevel::Compact => {
|
||||
let text = self.infer(label)?;
|
||||
self.unify(string(), text.tipo(), text.location(), false)?;
|
||||
Ok(TypedExpr::Trace {
|
||||
location,
|
||||
tipo,
|
||||
then: Box::new(then),
|
||||
text: Box::new(text),
|
||||
})
|
||||
}
|
||||
TraceLevel::Verbose => {
|
||||
let label = self.infer_trace_arg(label)?;
|
||||
|
||||
let text = if typed_arguments.is_empty() {
|
||||
label
|
||||
} else {
|
||||
|
@ -2449,38 +2453,13 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
})
|
||||
};
|
||||
|
||||
let then = self.infer(then)?;
|
||||
let tipo = then.tipo();
|
||||
|
||||
if let TraceKind::Todo = kind {
|
||||
self.environment.warnings.push(Warning::Todo {
|
||||
location,
|
||||
tipo: tipo.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
match self.tracing.trace_level(false) {
|
||||
TraceLevel::Silent => Ok(then),
|
||||
TraceLevel::Compact => Ok(TypedExpr::Trace {
|
||||
location,
|
||||
tipo,
|
||||
then: Box::new(then),
|
||||
text: Box::new(TypedExpr::String {
|
||||
location,
|
||||
tipo: string(),
|
||||
value: self
|
||||
.lines
|
||||
.line_and_column_number(location.start)
|
||||
.expect("Spans are within bounds.")
|
||||
.to_string(),
|
||||
}),
|
||||
}),
|
||||
TraceLevel::Verbose => Ok(TypedExpr::Trace {
|
||||
Ok(TypedExpr::Trace {
|
||||
location,
|
||||
tipo,
|
||||
then: Box::new(then),
|
||||
text: Box::new(text),
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ use crate::{
|
|||
},
|
||||
builtins,
|
||||
builtins::{fuzzer, generic_var},
|
||||
line_numbers::LineNumbers,
|
||||
tipo::{expr::infer_function, Span, Type, TypeVar},
|
||||
IdGenerator,
|
||||
};
|
||||
|
@ -86,14 +85,8 @@ impl UntypedModule {
|
|||
}
|
||||
|
||||
for def in consts.into_iter().chain(not_consts) {
|
||||
let definition = infer_definition(
|
||||
def,
|
||||
&module_name,
|
||||
&mut hydrators,
|
||||
&mut environment,
|
||||
&self.lines,
|
||||
tracing,
|
||||
)?;
|
||||
let definition =
|
||||
infer_definition(def, &module_name, &mut hydrators, &mut environment, tracing)?;
|
||||
|
||||
definitions.push(definition);
|
||||
}
|
||||
|
@ -162,7 +155,6 @@ fn infer_definition(
|
|||
module_name: &String,
|
||||
hydrators: &mut HashMap<String, Hydrator>,
|
||||
environment: &mut Environment<'_>,
|
||||
lines: &LineNumbers,
|
||||
tracing: Tracing,
|
||||
) -> Result<TypedDefinition, Error> {
|
||||
match def {
|
||||
|
@ -171,7 +163,6 @@ fn infer_definition(
|
|||
module_name,
|
||||
hydrators,
|
||||
environment,
|
||||
lines,
|
||||
tracing,
|
||||
)?)),
|
||||
|
||||
|
@ -228,7 +219,7 @@ fn infer_definition(
|
|||
}
|
||||
|
||||
let mut typed_fun =
|
||||
infer_function(&fun, module_name, hydrators, environment, lines, tracing)?;
|
||||
infer_function(&fun, module_name, hydrators, environment, tracing)?;
|
||||
|
||||
if !typed_fun.return_type.is_bool() {
|
||||
return Err(Error::ValidatorMustReturnBool {
|
||||
|
@ -267,14 +258,8 @@ fn infer_definition(
|
|||
let params = params.into_iter().chain(other.arguments);
|
||||
other.arguments = params.collect();
|
||||
|
||||
let mut other_typed_fun = infer_function(
|
||||
&other,
|
||||
module_name,
|
||||
hydrators,
|
||||
environment,
|
||||
lines,
|
||||
tracing,
|
||||
)?;
|
||||
let mut other_typed_fun =
|
||||
infer_function(&other, module_name, hydrators, environment, tracing)?;
|
||||
|
||||
if !other_typed_fun.return_type.is_bool() {
|
||||
return Err(Error::ValidatorMustReturnBool {
|
||||
|
@ -338,8 +323,7 @@ fn infer_definition(
|
|||
});
|
||||
}
|
||||
|
||||
let typed_via =
|
||||
ExprTyper::new(environment, lines, tracing).infer(arg.via.clone())?;
|
||||
let typed_via = ExprTyper::new(environment, tracing).infer(arg.via.clone())?;
|
||||
|
||||
let hydrator: &mut Hydrator = hydrators.get_mut(&f.name).unwrap();
|
||||
|
||||
|
@ -404,14 +388,7 @@ fn infer_definition(
|
|||
None => Ok((None, None)),
|
||||
}?;
|
||||
|
||||
let typed_f = infer_function(
|
||||
&f.into(),
|
||||
module_name,
|
||||
hydrators,
|
||||
environment,
|
||||
lines,
|
||||
tracing,
|
||||
)?;
|
||||
let typed_f = infer_function(&f.into(), module_name, hydrators, environment, tracing)?;
|
||||
|
||||
environment.unify(
|
||||
typed_f.return_type.clone(),
|
||||
|
@ -629,7 +606,7 @@ fn infer_definition(
|
|||
tipo: _,
|
||||
}) => {
|
||||
let typed_expr =
|
||||
ExprTyper::new(environment, lines, tracing).infer_const(&annotation, *value)?;
|
||||
ExprTyper::new(environment, tracing).infer_const(&annotation, *value)?;
|
||||
|
||||
let tipo = typed_expr.tipo();
|
||||
|
||||
|
|
Loading…
Reference in New Issue