rework trace label evaluation strategy

Namely:

  1. Fully evaluate & type-check the label, irrespective of the trace level. So that labels using other variables do not generate "unused identifier" warnings when compiling with different trace mode (and so that the success of a build doesn't depend on the trace level).

     This was already done for trace arguments, but not for labels, somehow.

  2. Move the requirement for compact trace label being String from errors down to warnings; following point (1), we shouldn't fail compilation for different trace levels. It seems more reasonable to simply raise a warning.

Signed-off-by: KtorZ <matthias.benkort@gmail.com>
This commit is contained in:
KtorZ 2025-03-18 09:05:08 +01:00
parent 3fa25fecfa
commit c88cbd8f28
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
4 changed files with 50 additions and 38 deletions

View File

@ -13,6 +13,7 @@
- **aiken-lang**: Change default placeholder for `trace` to `Void` instead of `todo`. @KtorZ - **aiken-lang**: Change default placeholder for `trace` to `Void` instead of `todo`. @KtorZ
- **aiken-lang**: Disallow (parse error) dangling colon `:` in traces. See [#1113](https://github.com/aiken-lang/aiken/issues/1113). @KtorZ - **aiken-lang**: Disallow (parse error) dangling colon `:` in traces. See [#1113](https://github.com/aiken-lang/aiken/issues/1113). @KtorZ
- **aiken-lang**: Fix `aiken blueprint apply` wrongly overriding all validators handlers names & ABI to the mint's one. See [#1099](https://github.com/aiken-lang/aiken/issues/1099). @KtorZ - **aiken-lang**: Fix `aiken blueprint apply` wrongly overriding all validators handlers names & ABI to the mint's one. See [#1099](https://github.com/aiken-lang/aiken/issues/1099). @KtorZ
- **aiken-lang**: Always type-check trace label irrespective of the trace level, to avoid unnecessary warnings in compact or silent mode. See [#1122](https://github.com/aiken-lang/aiken/issues/1122). @KtorZ
### Fixed ### Fixed

View File

@ -1321,8 +1321,8 @@ fn trace_non_string_label_compact() {
"#; "#;
assert!(matches!( assert!(matches!(
check_with_verbosity(parse(source_code), TraceLevel::Compact), &check_with_verbosity(parse(source_code), TraceLevel::Compact),
Err((_, Error::CouldNotUnify { .. })) Ok((warnings, _)) if warnings == &[Warning::CompactTraceLabelIsNotstring { location: Span::create(40, 7) }],
)) ))
} }

View File

@ -1865,6 +1865,15 @@ pub enum Warning {
location: Span, location: Span,
suggestion: UntypedPattern, suggestion: UntypedPattern,
}, },
#[error("I noticed a (compact) dynamic trace label which is not a string")]
#[diagnostic(help("Compiling with a compact trace-level, you are probably expecting compact traces although here, the entire label will need to be serialise *at runtime* which will add a significant overhead.\n\nAs a reminder, trace arguments are fully ignored in compact tracing. Hence, you probably want to put a cute little label here and move the current trace as argument!"))]
#[diagnostic(code("trace::label_is_not_string"))]
#[diagnostic(url("https://aiken-lang.org/language-tour/troubleshooting#traces"))]
CompactTraceLabelIsNotstring {
#[label("compact trace label is not String")]
location: Span,
},
} }
impl ExtraData for Warning { impl ExtraData for Warning {
@ -1884,6 +1893,7 @@ impl ExtraData for Warning {
| Warning::UnusedVariable { .. } | Warning::UnusedVariable { .. }
| Warning::DiscardedLetAssignment { .. } | Warning::DiscardedLetAssignment { .. }
| Warning::ValidatorInLibraryModule { .. } | Warning::ValidatorInLibraryModule { .. }
| Warning::CompactTraceLabelIsNotstring { .. }
| Warning::UseWhenInstead { .. } => None, | Warning::UseWhenInstead { .. } => None,
Warning::Utf8ByteArrayIsValidHexString { value, .. } => Some(value.clone()), Warning::Utf8ByteArrayIsValidHexString { value, .. } => Some(value.clone()),
Warning::UnusedImportedModule { location, .. } => { Warning::UnusedImportedModule { location, .. } => {

View File

@ -2506,6 +2506,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
#[allow(clippy::result_large_err)] #[allow(clippy::result_large_err)]
fn infer_trace_arg(&mut self, arg: UntypedExpr) -> Result<TypedExpr, Error> { fn infer_trace_arg(&mut self, arg: UntypedExpr) -> Result<TypedExpr, Error> {
let location = arg.location();
let typed_arg = self.infer(arg)?; let typed_arg = self.infer(arg)?;
match self.unify( match self.unify(
Type::string(), Type::string(),
@ -2514,6 +2515,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
false, false,
) { ) {
Err(_) => { Err(_) => {
if matches!(self.tracing.trace_level(false), TraceLevel::Compact) {
self.environment
.warnings
.push(Warning::CompactTraceLabelIsNotstring { location });
}
self.unify(Type::data(), typed_arg.tipo(), typed_arg.location(), true)?; self.unify(Type::data(), typed_arg.tipo(), typed_arg.location(), true)?;
Ok(diagnose_expr(typed_arg)) Ok(diagnose_expr(typed_arg))
} }
@ -2546,44 +2553,38 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
}) })
} }
let label = self.infer_trace_arg(label)?;
let text = if typed_arguments.is_empty() {
label.clone()
} else {
let delimiter = |ix| TypedExpr::String {
location: Span::empty(),
tipo: Type::string(),
value: if ix == 0 { ": " } else { ", " }.to_string(),
};
typed_arguments
.into_iter()
.enumerate()
.fold(label.clone(), |text, (ix, arg)| {
append_string_expr(append_string_expr(text, delimiter(ix)), arg)
})
};
match self.tracing.trace_level(false) { match self.tracing.trace_level(false) {
TraceLevel::Silent => Ok(then), TraceLevel::Silent => Ok(then),
TraceLevel::Compact => { TraceLevel::Compact => Ok(TypedExpr::Trace {
let text = self.infer(label)?; location,
self.unify(Type::string(), text.tipo(), text.location(), false)?; tipo,
Ok(TypedExpr::Trace { then: Box::new(then),
location, text: Box::new(label),
tipo, }),
then: Box::new(then), TraceLevel::Verbose => Ok(TypedExpr::Trace {
text: Box::new(text), location,
}) tipo,
} then: Box::new(then),
TraceLevel::Verbose => { text: Box::new(text),
let label = self.infer_trace_arg(label)?; }),
let text = if typed_arguments.is_empty() {
label
} else {
let delimiter = |ix| TypedExpr::String {
location: Span::empty(),
tipo: Type::string(),
value: if ix == 0 { ": " } else { ", " }.to_string(),
};
typed_arguments
.into_iter()
.enumerate()
.fold(label, |text, (ix, arg)| {
append_string_expr(append_string_expr(text, delimiter(ix)), arg)
})
};
Ok(TypedExpr::Trace {
location,
tipo,
then: Box::new(then),
text: Box::new(text),
})
}
} }
} }