Repository: tweag/nickel
Pull request #1125 (2023-02-15 10:35:11)

Fix new clippy warnings
Fix new clippy warnings coming with 1.67. Originally done to fix #1118, but the latter is still failing because of an unrelated Nix segfault in the CI. In the meantime, this PR backports those fixes to `master`.


Patch:
diff --git a/src/bin/nickel.rs b/src/bin/nickel.rs
index f4694648..80cd34ff 100644
--- a/src/bin/nickel.rs
+++ b/src/bin/nickel.rs
@@ -117,7 +117,7 @@ fn main() {
             .map(Program::new_from_file)
             .unwrap_or_else(Program::new_from_stdin)
             .unwrap_or_else(|err| {
-                eprintln!("Error when reading input: {}", err);
+                eprintln!("Error when reading input: {err}");
                 process::exit(1)
             });
 
diff --git a/src/cache.rs b/src/cache.rs
index d58ef4c6..96f95e49 100644
--- a/src/cache.rs
+++ b/src/cache.rs
@@ -1082,7 +1082,7 @@ impl ImportResolver for Cache {
         let id_op = self.get_or_add_file(&path_buf).map_err(|err| {
             ImportError::IOError(
                 path_buf.to_string_lossy().into_owned(),
-                format!("{}", err),
+                format!("{err}"),
                 *pos,
             )
         })?;
diff --git a/src/error.rs b/src/error.rs
index 4e82572e..2d67536a 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -831,7 +831,7 @@ impl ToDiagnostic<FileId> for EvalError {
                 }
 
                 let mut diags = vec![Diagnostic::error()
-                    .with_message(format!("missing definition for `{}`", id,))
+                    .with_message(format!("missing definition for `{id}`",))
                     .with_labels(labels)
                     .with_notes(vec![])];
 
@@ -897,18 +897,15 @@ impl ToDiagnostic<FileId> for EvalError {
                 if let Some(span) = span_opt.into_opt() {
                     labels.push(
                         Label::primary(span.src_id, span.start.to_usize()..span.end.to_usize())
-                            .with_message(format!("this requires field {} to exist", field)),
+                            .with_message(format!("this requires field {field} to exist")),
                     );
                 } else {
-                    notes.push(format!(
-                        "field {} was required by the operator {}",
-                        field, op
-                    ));
+                    notes.push(format!("field {field} was required by the operator {op}"));
                 }
 
                 if let Some(span) = t.pos.as_opt_ref() {
                     labels.push(
-                        secondary(span).with_message(format!("field {} is missing here", field)),
+                        secondary(span).with_message(format!("field {field} is missing here")),
                     );
                 }
 
@@ -919,10 +916,7 @@ impl ToDiagnostic<FileId> for EvalError {
             EvalError::NotEnoughArgs(count, op, span_opt) => {
                 let mut labels = Vec::new();
                 let mut notes = Vec::new();
-                let msg = format!(
-                    "{} expects {} arguments, but not enough were provided",
-                    op, count
-                );
+                let msg = format!("{op} expects {count} arguments, but not enough were provided");
 
                 if let Some(span) = span_opt.into_opt() {
                     labels.push(
@@ -988,7 +982,7 @@ impl ToDiagnostic<FileId> for EvalError {
                     .unwrap_or_default();
 
                 vec![Diagnostic::error()
-                    .with_message(format!("internal error: {}", msg))
+                    .with_message(format!("internal error: {msg}"))
                     .with_labels(labels)
                     .with_notes(vec![String::from(INTERNAL_ERROR_MSG)])]
             }
@@ -1000,7 +994,7 @@ impl ToDiagnostic<FileId> for EvalError {
                     .unwrap_or_default();
 
                 vec![Diagnostic::error()
-                    .with_message(format!("{} parse error: {}", format, msg))
+                    .with_message(format!("{format} parse error: {msg}"))
                     .with_labels(labels)
                     .with_notes(vec![String::from(INTERNAL_ERROR_MSG)])]
             }
@@ -1190,7 +1184,7 @@ mod blame_error {
                     .map(|ident| ident.to_string())
                     .unwrap_or_else(|| String::from("<func>"));
                 Diagnostic::note().with_labels(vec![
-                    primary(&cdescr.span).with_message(format!("While calling to {}", name))
+                    primary(&cdescr.span).with_message(format!("While calling to {name}"))
                 ])
             });
             let diags =
@@ -1381,7 +1375,7 @@ impl ToDiagnostic<FileId> for ParseError {
                     .unwrap_or_default();
 
                 Diagnostic::error()
-                    .with_message(format!("{} parse error: {}", format, msg))
+                    .with_message(format!("{format} parse error: {msg}"))
                     .with_labels(labels)
             }
             ParseError::UnboundTypeVariables(idents, span) => Diagnostic::error()
@@ -1389,7 +1383,7 @@ impl ToDiagnostic<FileId> for ParseError {
                     "unbound type variable(s): {}",
                     idents
                         .iter()
-                        .map(|x| format!("`{}`", x))
+                        .map(|x| format!("`{x}`"))
                         .collect::<Vec<_>>()
                         .join(",")
                 ))
@@ -1415,7 +1409,7 @@ impl ToDiagnostic<FileId> for ParseError {
                     String::from("Note: you can reference other fields of a record recursively from within a field, so you might not need the recursive let."),
                 ]),
             ParseError::TypeVariableKindMismatch { ty_var, span } => Diagnostic::error()
-                .with_message(format!("the type variable {} is used in conflicting ways", ty_var))
+                .with_message(format!("the type variable {ty_var} is used in conflicting ways"))
                 .with_labels(vec![
                     primary(span),
                 ])
@@ -1451,11 +1445,11 @@ impl ToDiagnostic<FileId> for TypecheckError {
                 }
             TypecheckError::MissingRow(ident, expd, actual, span_opt) =>
                 vec![Diagnostic::error()
-                    .with_message(format!("type error: missing row `{}`", ident))
+                    .with_message(format!("type error: missing row `{ident}`"))
                     .with_labels(mk_expr_label(span_opt))
                     .with_notes(vec![
-                        format!("The type of the expression was expected to be `{}` which contains the field `{}`", expd, ident),
-                        format!("The type of the expression was inferred to be `{}`, which does not contain the field `{}`", actual, ident),
+                        format!("The type of the expression was expected to be `{expd}` which contains the field `{ident}`"),
+                        format!("The type of the expression was inferred to be `{actual}`, which does not contain the field `{ident}`"),
                     ])]
             ,
             TypecheckError::MissingDynTail(expd, actual, span_opt) =>
@@ -1463,18 +1457,18 @@ impl ToDiagnostic<FileId> for TypecheckError {
                     .with_message(String::from("type error: missing dynamic tail `| Dyn`"))
                     .with_labels(mk_expr_label(span_opt))
                     .with_notes(vec![
-                        format!("The type of the expression was expected to be `{}` which contains the tail `| Dyn`", expd),
-                        format!("The type of the expression was inferred to be `{}`, which does not contain the tail `| Dyn`", actual),
+                        format!("The type of the expression was expected to be `{expd}` which contains the tail `| Dyn`"),
+                        format!("The type of the expression was inferred to be `{actual}`, which does not contain the tail `| Dyn`"),
                     ])]
             ,
 
             TypecheckError::ExtraRow(ident, expd, actual, span_opt) =>
                 vec![Diagnostic::error()
-                    .with_message(format!("type error: extra row `{}`", ident))
+                    .with_message(format!("type error: extra row `{ident}`"))
                     .with_labels(mk_expr_label(span_opt))
                     .with_notes(vec![
-                        format!("The type of the expression was expected to be `{}`, which does not contain the field `{}`", expd, ident),
-                        format!("The type of the expression was inferred to be `{}`, which contains the extra field `{}`", actual, ident),
+                        format!("The type of the expression was expected to be `{expd}`, which does not contain the field `{ident}`"),
+                        format!("The type of the expression was inferred to be `{actual}`, which contains the extra field `{ident}`"),
                     ])]
             ,
             TypecheckError::ExtraDynTail(expd, actual, span_opt) =>
@@ -1482,8 +1476,8 @@ impl ToDiagnostic<FileId> for TypecheckError {
                     .with_message(String::from("type error: extra dynamic tail `| Dyn`"))
                     .with_labels(mk_expr_label(span_opt))
                     .with_notes(vec![
-                        format!("The type of the expression was expected to be `{}`, which does not contain the tail `| Dyn`", expd),
-                        format!("The type of the expression was inferred to be `{}`, which contains the extra tail `| Dyn`", actual),
+                        format!("The type of the expression was expected to be `{expd}`, which does not contain the tail `| Dyn`"),
+                        format!("The type of the expression was inferred to be `{actual}`, which contains the extra tail `| Dyn`"),
                     ])]
             ,
 
@@ -1492,7 +1486,7 @@ impl ToDiagnostic<FileId> for TypecheckError {
                     .with_message(String::from("unbound type variable"))
                     .with_labels(vec![primary_alt(span_opt.into_opt(), ident.to_string(), files).with_message("this type variable is unbound")])
                     .with_notes(vec![
-                        format!("Maybe you forgot to put a `forall {}.` somewhere in the enclosing type ?", ident),
+                        format!("Maybe you forgot to put a `forall {ident}.` somewhere in the enclosing type ?"),
                     ])]
             ,
             TypecheckError::TypeMismatch(expd, actual, span_opt) => {
@@ -1531,7 +1525,7 @@ impl ToDiagnostic<FileId> for TypecheckError {
                         .with_message("incompatible row kinds")
                         .with_labels(mk_expr_label(span_opt))
                         .with_notes(vec![
-                            format!("The row type of `{}` was expected to be `{}`, but was inferred to be `{}`", ident, expd_str, actual_str),
+                            format!("The row type of `{ident}` was expected to be `{expd_str}`, but was inferred to be `{actual_str}`"),
                             String::from("Enum row types and record row types are not compatible"),
                         ])]
             }
@@ -1549,13 +1543,13 @@ impl ToDiagnostic<FileId> for TypecheckError {
                     err = next;
                 }
 
-                let path_str: Vec<String> = path.clone().into_iter().map(|ident| format!("{}", ident)).collect();
+                let path_str: Vec<String> = path.clone().into_iter().map(|ident| format!("{ident}")).collect();
                 let field = path_str.join(".");
 
                 //TODO: we should rather have RowMismatch hold a rows, instead of a general type,
                 //than doing this match.
-                let row_msg = |word, field, ty| format!("The type of the expression was {} to have the row `{}: {}`", word, field, ty);
-                let default_msg = |word, ty| format!("The type of the expression was {} to be `{}`", word, ty);
+                let row_msg = |word, field, ty| format!("The type of the expression was {word} to have the row `{field}: {ty}`");
+                let default_msg = |word, ty| format!("The type of the expression was {word} to be `{ty}`");
 
                 let note1 = if let TypeF::Record(rrows) = &expd.0 {
                     match rrows.row_find_path(path.as_slice()) {
@@ -1581,7 +1575,7 @@ impl ToDiagnostic<FileId> for TypecheckError {
                     .with_notes(vec![
                         note1,
                         note2,
-                        format!("Could not match the two declaration of `{}`", field),
+                        format!("Could not match the two declaration of `{field}`"),
                     ])
                 ];
 
@@ -1602,7 +1596,7 @@ impl ToDiagnostic<FileId> for TypecheckError {
                         .with_labels(mk_expr_label(span_opt))
                         .with_notes(vec![
                             format!("The type of the expression was inferred to have the row `{}: {}`", ident, conflict.as_ref().cloned().unwrap()),
-                            format!("But this type appears inside another row type, which already has a declaration for the field `{}`", ident),
+                            format!("But this type appears inside another row type, which already has a declaration for the field `{ident}`"),
                             String::from("A type cannot have two conflicting declaration for the same row"),
                         ])]
             }
@@ -1612,12 +1606,12 @@ impl ToDiagnostic<FileId> for TypecheckError {
 
                 let mut labels = vec![
                     Label::secondary(
-                        files.add("", format!("{}", expd)),
+                        files.add("", format!("{expd}")),
                         expd_start..expd_end,
                     )
                         .with_message("this part of the expected type"),
                     Label::secondary(
-                        files.add("", format!("{}", actual)),
+                        files.add("", format!("{actual}")),
                         actual_start..actual_end,
                     )
                         .with_message("does not match this part of the inferred type"),
@@ -1628,8 +1622,8 @@ impl ToDiagnostic<FileId> for TypecheckError {
                     .with_message("function types mismatch")
                     .with_labels(labels)
                     .with_notes(vec![
-                        format!("The type of the expression was expected to be `{}`", expd),
-                        format!("The type of the expression was inferred to be `{}`", actual),
+                        format!("The type of the expression was expected to be `{expd}`"),
+                        format!("The type of the expression was inferred to be `{actual}`"),
                         String::from("Could not match the two function types"),
                     ])
                 ];
@@ -1687,7 +1681,7 @@ impl ToDiagnostic<FileId> for ImportError {
                     .unwrap_or_default();
 
                 vec![Diagnostic::error()
-                    .with_message(format!("import of {} failed: {}", path, error))
+                    .with_message(format!("import of {path} failed: {error}"))
                     .with_labels(labels)]
             }
             ImportError::ParseErrors(error, span_opt) => {
@@ -1725,7 +1719,7 @@ impl ToDiagnostic<FileId> for SerializationError {
                 ))
                 .with_labels(vec![primary_term(rt, files)])],
             SerializationError::UnsupportedNull(format, rt) => vec![Diagnostic::error()
-                .with_message(format!("{} doesn't support null values", format))
+                .with_message(format!("{format} doesn't support null values"))
                 .with_labels(vec![primary_term(rt, files)])],
             SerializationError::NonSerializable(rt) => vec![Diagnostic::error()
                 .with_message("non serializable term")
@@ -1757,7 +1751,7 @@ impl ToDiagnostic<FileId> for ReplError {
     ) -> Vec<Diagnostic<FileId>> {
         match self {
             ReplError::UnknownCommand(s) => vec![Diagnostic::error()
-                .with_message(format!("unknown command `{}`", s))
+                .with_message(format!("unknown command `{s}`"))
                 .with_notes(vec![String::from(
                     "type `:?` or `:help` for a list of available commands.",
                 )])],
@@ -1767,12 +1761,11 @@ impl ToDiagnostic<FileId> for ReplError {
                     .map(|msg| vec![msg.clone()])
                     .unwrap_or_default();
                 notes.push(format!(
-                    "type `:? {}` or `:help {}` for more information.",
-                    cmd, cmd
+                    "type `:? {cmd}` or `:help {cmd}` for more information."
                 ));
 
                 vec![Diagnostic::error()
-                    .with_message(format!("{}: missing argument", cmd))
+                    .with_message(format!("{cmd}: missing argument"))
                     .with_notes(notes)]
             }
         }
diff --git a/src/eval/merge.rs b/src/eval/merge.rs
index 55e4095d..90e60fd2 100644
--- a/src/eval/merge.rs
+++ b/src/eval/merge.rs
@@ -246,7 +246,7 @@ pub fn merge<C: Cache>(
             match mode {
                 MergeMode::Contract(mut lbl) if !r2.attrs.open && !left.is_empty() => {
                     let fields: Vec<String> =
-                        left.keys().map(|field| format!("`{}`", field)).collect();
+                        left.keys().map(|field| format!("`{field}`")).collect();
                     let plural = if fields.len() == 1 { "" } else { "s" };
                     lbl.tag = format!("extra field{} {}", plural, fields.join(","));
                     return Err(EvalError::BlameError {
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index f746262d..f690a8ab 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -585,7 +585,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                         Closure::atomic_closure(t)
                     } else {
                         return Err(EvalError::InternalError(
-                            format!("Resolved import not found ({:?})", id),
+                            format!("Resolved import not found ({id:?})"),
                             pos,
                         ));
                     }
@@ -901,8 +901,8 @@ pub fn subst<C: Cache>(
 
             RichTerm::new(Term::Let(id, t1, t2, attrs), pos)
         }
-        p @ Term::LetPattern(..) => panic!("Pattern {:?} has not been transformed before evaluation", p),
-        p @ Term::FunPattern(..) => panic!("Pattern {:?} has not been transformed before evaluation", p),
+        p @ Term::LetPattern(..) => panic!("Pattern {p:?} has not been transformed before evaluation"),
+        p @ Term::FunPattern(..) => panic!("Pattern {p:?} has not been transformed before evaluation"),
         Term::App(t1, t2) => {
             let t1 = subst(cache, t1, initial_env, env);
             let t2 = subst(cache, t2, initial_env, env);
diff --git a/src/eval/operation.rs b/src/eval/operation.rs
index 6fd3b452..3ed70174 100644
--- a/src/eval/operation.rs
+++ b/src/eval/operation.rs
@@ -87,10 +87,10 @@ pub enum OperationCont {
 impl std::fmt::Debug for OperationCont {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
-            OperationCont::Op1(op, _) => write!(f, "Op1 {:?}", op),
-            OperationCont::Op2First(op, _, _) => write!(f, "Op2First {:?}", op),
-            OperationCont::Op2Second(op, _, _, _) => write!(f, "Op2Second {:?}", op),
-            OperationCont::OpN { op, .. } => write!(f, "OpN {:?}", op),
+            OperationCont::Op1(op, _) => write!(f, "Op1 {op:?}"),
+            OperationCont::Op2First(op, _, _) => write!(f, "Op2First {op:?}"),
+            OperationCont::Op2Second(op, _, _, _) => write!(f, "Op2Second {op:?}"),
+            OperationCont::OpN { op, .. } => write!(f, "OpN {op:?}"),
         }
     }
 }
@@ -597,8 +597,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                     if n < 0.0 || n.fract() != 0.0 {
                         Err(EvalError::Other(
                             format!(
-                            "generate: expected the 1st argument to be a positive integer, got {}",
-                            n
+                            "generate: expected the 1st argument to be a positive integer, got {n}"
                         ),
                             pos_op,
                         ))
@@ -951,7 +950,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
             UnaryOp::CharFromCode() => {
                 if let Term::Num(code) = *t {
                     if code.fract() != 0.0 {
-                        Err(EvalError::Other(format!("charFromCode: expected the argument to be an integer, got the floating-point value {}", code), pos_op))
+                        Err(EvalError::Other(format!("charFromCode: expected the argument to be an integer, got the floating-point value {code}"), pos_op))
                     } else if code < 0.0 || code > (u32::MAX as f64) {
                         Err(EvalError::Other(format!("charFromCode: code out of bounds. Expected a value between 0 and {}, got {}", u32::MAX, code), pos_op))
                     } else if let Some(car) = std::char::from_u32(code as u32) {
@@ -961,7 +960,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                         )))
                     } else {
                         Err(EvalError::Other(
-                            format!("charFromCode: invalid character code {}", code),
+                            format!("charFromCode: invalid character code {code}"),
                             pos_op,
                         ))
                     }
@@ -1041,7 +1040,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
             UnaryOp::NumFromStr() => {
                 if let Term::Str(s) = &*t {
                     let n = s.parse::<f64>().map_err(|_| {
-                        EvalError::Other(format!("numFrom: invalid num literal `{}`", s), pos)
+                        EvalError::Other(format!("numFrom: invalid num literal `{s}`"), pos)
                     })?;
                     Ok(Closure::atomic_closure(RichTerm::new(
                         Term::Num(n),
@@ -1986,7 +1985,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                                 match fields.insert(Ident::from(id), Field {value, metadata }) {
                                     //TODO: what to do on insertion where an empty optional field
                                     //exists? Temporary: we fail with existing field exception
-                                    Some(t) => Err(EvalError::Other(format!("insert: tried to extend a record with the field {}, but it already exists", id), pos_op)),
+                                    Some(t) => Err(EvalError::Other(format!("insert: tried to extend a record with the field {id}, but it already exists"), pos_op)),
                                     _ => Ok(Closure {
                                         body: Term::Record(RecordData { fields, ..record }).into(),
                                         env: env2,
@@ -2196,7 +2195,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                 (Term::Array(ts, attrs), Term::Num(n)) => {
                     let n_int = *n as usize;
                     if n.fract() != 0.0 {
-                        Err(EvalError::Other(format!("elemAt: expected the 2nd argument to be an integer, got the floating-point value {}", n), pos_op))
+                        Err(EvalError::Other(format!("elemAt: expected the 2nd argument to be an integer, got the floating-point value {n}"), pos_op))
                     } else if *n < 0.0 || n_int >= ts.len() {
                         Err(EvalError::Other(format!("elemAt: index out of bounds. Expected a value between 0 and {}, got {}", ts.len(), n), pos_op))
                     } else {
@@ -2366,21 +2365,21 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                             "Json" => serde_json::from_str(s).map_err(|err| {
                                 EvalError::DeserializationError(
                                     String::from("json"),
-                                    format!("{}", err),
+                                    format!("{err}"),
                                     pos_op,
                                 )
                             })?,
                             "Yaml" => serde_yaml::from_str(s).map_err(|err| {
                                 EvalError::DeserializationError(
                                     String::from("yaml"),
-                                    format!("{}", err),
+                                    format!("{err}"),
                                     pos_op,
                                 )
                             })?,
                             "Toml" => toml::from_str(s).map_err(|err| {
                                 EvalError::DeserializationError(
                                     String::from("toml"),
-                                    format!("{}", err),
+                                    format!("{err}"),
                                     pos_op,
                                 )
                             })?,
@@ -2554,7 +2553,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                     }
                     (Term::Str(_), Term::Str(_), _) => Err(EvalError::TypeError(
                         String::from("Str"),
-                        format!("{}, 3rd argument", n_op),
+                        format!("{n_op}, 3rd argument"),
                         thd_pos,
                         RichTerm {
                             term: thd,
@@ -2563,7 +2562,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                     )),
                     (Term::Str(_), _, _) => Err(EvalError::TypeError(
                         String::from("Str"),
-                        format!("{}, 2nd argument", n_op),
+                        format!("{n_op}, 2nd argument"),
                         snd_pos,
                         RichTerm {
                             term: snd,
@@ -2572,7 +2571,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                     )),
                     (_, _, _) => Err(EvalError::TypeError(
                         String::from("Str"),
-                        format!("{}, 1st argument", n_op),
+                        format!("{n_op}, 1st argument"),
                         fst_pos,
                         RichTerm {
                             term: fst,
@@ -2596,11 +2595,11 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
                         let end_int = *end as usize;
 
                         if start.fract() != 0.0 {
-                            Err(EvalError::Other(format!("substring: expected the 2nd argument (start) to be an integer, got the floating-point value {}", start), pos_op))
+                            Err(EvalError::Other(format!("substring: expected the 2nd argument (start) to be an integer, got the floating-point value {start}"), pos_op))
                         } else if !s.is_char_boundary(start_int) {
                             Err(EvalError::Other(format!("substring: index out of bounds. Expected the 2nd argument (start) to be between 0 and {}, got {}", s.len(), start), pos_op))
                         } else if end.fract() != 0.0 {
-                            Err(EvalError::Other(format!("substring: expected the 3nd argument (end) to be an integer, got the floating-point value {}", end), pos_op))
+                            Err(EvalError::Other(format!("substring: expected the 3nd argument (end) to be an integer, got the floating-point value {end}"), pos_op))
                         } else if end <= start || !s.is_char_boundary(end_int) {
                             Err(EvalError::Other(format!("substring: index out of bounds. Expected the 3rd argument (end) to be between {} and {}, got {}", start+1., s.len(), end), pos_op))
                         } else {
diff --git a/src/eval/stack.rs b/src/eval/stack.rs
index 6f9623a1..cfad05b0 100644
--- a/src/eval/stack.rs
+++ b/src/eval/stack.rs
@@ -63,7 +63,7 @@ impl<C: Cache> std::fmt::Debug for Marker<C> {
             Marker::Arg(_, _) => write!(f, "Arg"),
             Marker::TrackedArg(_, _) => write!(f, "TrackedArg"),
             Marker::UpdateIndex(_) => write!(f, "UpdateIndex"),
-            Marker::Cont(op, sz, _) => write!(f, "Cont {:?} (callstack size {})", op, sz),
+            Marker::Cont(op, sz, _) => write!(f, "Cont {op:?} (callstack size {sz})"),
             Marker::StrChunk(_) => write!(f, "StrChunk"),
             Marker::StrAcc { .. } => write!(f, "StrAcc"),
         }
@@ -329,7 +329,7 @@ impl<C: Cache> std::fmt::Debug for Stack<C> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         writeln!(f, "--- STACK ---")?;
         for marker in self.0.iter().rev() {
-            writeln!(f, "| {:?}", marker)?;
+            writeln!(f, "| {marker:?}")?;
         }
         writeln!(f, "---  END  ---")
     }
diff --git a/src/label.rs b/src/label.rs
index 020706cd..6c56e002 100644
--- a/src/label.rs
+++ b/src/label.rs
@@ -139,7 +139,7 @@ pub mod ty_path {
         // different blocks.
         let forall_offset = match (&ty.0, path_it.peek()) {
             (_, None) => {
-                let repr = format!("{}", ty);
+                let repr = format!("{ty}");
                 return PathSpan {
                     start: 0,
                     end: repr.len(),
@@ -223,7 +223,7 @@ pub mod ty_path {
                                 last,
                                 last_arrow_elem,
                             } = span(path_it, ty);
-                            let full_offset = start_offset + format!("{}", id).len() + id_offset;
+                            let full_offset = start_offset + format!("{id}").len() + id_offset;
 
                             return PathSpan {
                                 start: full_offset + sub_start,
@@ -234,9 +234,9 @@ pub mod ty_path {
                         }
                         RecordRowsIteratorItem::Row(RecordRowF { id, types: ty }) => {
                             // The last +1 is for the
-                            start_offset += format!("{}", id).len()
+                            start_offset += format!("{id}").len()
                                 + id_offset
-                                + format!("{}", ty).len()
+                                + format!("{ty}").len()
                                 + end_offset;
                         }
                         RecordRowsIteratorItem::TailDyn | RecordRowsIteratorItem::TailVar(_) => (),
@@ -275,7 +275,7 @@ but this field doesn't exist in {}",
             }
             // The type and the path don't match, we stop here.
             _ => {
-                let repr = format!("{}", ty);
+                let repr = format!("{ty}");
                 PathSpan {
                     start: 0,
                     end: repr.len(),
diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs
index 3264a6d3..c4fd2646 100644
--- a/src/parser/lexer.rs
+++ b/src/parser/lexer.rs
@@ -540,7 +540,7 @@ impl<'input> Lexer<'input> {
                 // We can only enter string mode from normal mode
                 self.count = match self.stack.pop() {
                     Some(ModeElt::Normal(count)) => count,
-                    mode => panic!("lexer::leave_str (popped mode {:?})", mode),
+                    mode => panic!("lexer::leave_str (popped mode {mode:?})"),
                 };
 
                 self.lexer = Some(ModalLexer::Normal(lexer.morph()));
@@ -555,7 +555,7 @@ impl<'input> Lexer<'input> {
                 // We can only enter string mode from normal mode
                 self.count = match self.stack.pop() {
                     Some(ModeElt::Normal(count)) => count,
-                    mode => panic!("lexer::leave_str (popped mode {:?})", mode),
+                    mode => panic!("lexer::leave_str (popped mode {mode:?})"),
                 };
 
                 self.lexer = Some(ModalLexer::Normal(lexer.morph()));
@@ -574,7 +574,7 @@ impl<'input> Lexer<'input> {
                         self.count = count;
                         self.lexer = Some(ModalLexer::MultiStr(lexer.morph()))
                     }
-                    mode => panic!("lexer::leave_normal (popped mode {:?})", mode),
+                    mode => panic!("lexer::leave_normal (popped mode {mode:?})"),
                 };
             }
             _ => panic!("lexer::leave_normal"),
diff --git a/src/pretty.rs b/src/pretty.rs
index fd1b2944..25ec365d 100644
--- a/src/pretty.rs
+++ b/src/pretty.rs
@@ -316,7 +316,7 @@ where
                 .append(allocator.as_string(id))
                 .append(allocator.space()),
             op => allocator
-                .text(format!("%{:?}%", op).to_lowercase())
+                .text(format!("%{op:?}%").to_lowercase())
                 .append(allocator.space()),
         }
     }
@@ -352,7 +352,7 @@ where
             DynAccess() => allocator.text("."),
             ArrayElemAt() => allocator.text("%elem_at%"),
 
-            op => allocator.as_string(format!("%{:?}%", op).to_lowercase()),
+            op => allocator.as_string(format!("%{op:?}%").to_lowercase()),
         }
     }
 }
@@ -662,7 +662,7 @@ where
                             .text("if")
                             .append(allocator.space())
                             .append(rt.to_owned().pretty(allocator)),
-                        op => panic!("pretty print is not impleented for {:?}", op),
+                        op => panic!("pretty print is not impleented for {op:?}"),
                     }
                 }
             },
@@ -700,7 +700,7 @@ where
                 .group(),
 
             SealingKey(sym) => allocator
-                .text(format!("#<sealing key: {}>", sym))
+                .text(format!("#<sealing key: {sym}>"))
                 .append(allocator.hardline()),
             // TODO
             Sealed(_i, _rt, _lbl) => allocator.text("#<sealed>").append(allocator.hardline()),
@@ -712,7 +712,7 @@ where
                 .text("import")
                 .append(allocator.space())
                 .append(allocator.as_string(f.to_string_lossy()).double_quotes()),
-            ResolvedImport(id) => allocator.text(format!("import <file_id: {:?}>", id)),
+            ResolvedImport(id) => allocator.text(format!("import <file_id: {id:?}>")),
             ParseError(_) => allocator.text("%<PARSE ERROR>"),
             RuntimeError(_) => allocator.text("%<RUNTIME ERROR>"),
         }
diff --git a/src/program.rs b/src/program.rs
index c8ef094f..d09d2c16 100644
--- a/src/program.rs
+++ b/src/program.rs
@@ -381,10 +381,7 @@ where
     });
     match result {
         Ok(()) => (),
-        Err(err) => panic!(
-            "Program::report: could not print an error on stderr: {}",
-            err
-        ),
+        Err(err) => panic!("Program::report: could not print an error on stderr: {err}"),
     };
 }
 
@@ -535,7 +532,7 @@ mod tests {
 
         let mut p: Program<EC> = Program::new_from_source(src, "<test>").map_err(|io_err| {
             Error::EvalError(EvalError::Other(
-                format!("IO error: {}", io_err),
+                format!("IO error: {io_err}"),
                 TermPos::None,
             ))
         })?;
@@ -547,7 +544,7 @@ mod tests {
 
         let mut p: Program<EC> = Program::new_from_source(src, "<test>").map_err(|io_err| {
             Error::EvalError(EvalError::Other(
-                format!("IO error: {}", io_err),
+                format!("IO error: {io_err}"),
                 TermPos::None,
             ))
         })?;
diff --git a/src/repl/command.rs b/src/repl/command.rs
index 192329ad..c465877f 100644
--- a/src/repl/command.rs
+++ b/src/repl/command.rs
@@ -112,7 +112,7 @@ impl FromStr for Command {
                 } else {
                     arg
                 };
-                println!("{}", arg);
+                println!("{arg}");
                 Ok(Command::Load(OsString::from(arg)))
             }
             CommandType::Typecheck => {
diff --git a/src/repl/mod.rs b/src/repl/mod.rs
index 701fbedb..8a3e0297 100644
--- a/src/repl/mod.rs
+++ b/src/repl/mod.rs
@@ -400,8 +400,8 @@ pub fn print_help(out: &mut impl Write, arg: Option<&str>) -> std::io::Result<()
             let mut aliases = cmd.aliases().into_iter();
 
             if let Some(fst) = aliases.next() {
-                write!(w, "Aliases: `{}`", fst)?;
-                aliases.try_for_each(|alias| write!(w, ", `{}`", alias))?;
+                write!(w, "Aliases: `{fst}`")?;
+                aliases.try_for_each(|alias| write!(w, ", `{alias}`"))?;
                 writeln!(w)?;
             }
 
@@ -410,7 +410,7 @@ pub fn print_help(out: &mut impl Write, arg: Option<&str>) -> std::io::Result<()
 
         match arg.parse::<CommandType>() {
             Ok(c @ CommandType::Help) => {
-                writeln!(out, ":{} [command]", c)?;
+                writeln!(out, ":{c} [command]")?;
                 print_aliases(out, c)?;
                 writeln!(
                     out,
@@ -418,12 +418,12 @@ pub fn print_help(out: &mut impl Write, arg: Option<&str>) -> std::io::Result<()
                 )?;
             }
             Ok(c @ CommandType::Query) => {
-                writeln!(out, ":{} <expression>", c)?;
+                writeln!(out, ":{c} <expression>")?;
                 print_aliases(out, c)?;
                 writeln!(out, "Print the metadata attached to an attribute")?;
             }
             Ok(c @ CommandType::Load) => {
-                writeln!(out, ":{} <file>", c)?;
+                writeln!(out, ":{c} <file>")?;
                 print_aliases(out, c)?;
                 write!(out,"Evaluate the content of <file> to a record and load its attributes in the environment.")?;
                 writeln!(
@@ -432,7 +432,7 @@ pub fn print_help(out: &mut impl Write, arg: Option<&str>) -> std::io::Result<()
                 )?;
             }
             Ok(c @ CommandType::Typecheck) => {
-                writeln!(out, ":{} <expression>", c)?;
+                writeln!(out, ":{c} <expression>")?;
                 print_aliases(out, c)?;
                 writeln!(
                     out,
@@ -440,17 +440,17 @@ pub fn print_help(out: &mut impl Write, arg: Option<&str>) -> std::io::Result<()
                 )?;
             }
             Ok(c @ CommandType::Print) => {
-                writeln!(out, ":{} <expression>", c)?;
+                writeln!(out, ":{c} <expression>")?;
                 print_aliases(out, c)?;
                 writeln!(out, "Evaluate and print <expression> recursively")?;
             }
             Ok(c @ CommandType::Exit) => {
-                writeln!(out, ":{}", c)?;
+                writeln!(out, ":{c}")?;
                 print_aliases(out, c)?;
                 writeln!(out, "Exit the REPL session")?;
             }
             Err(UnknownCommandError {}) => {
-                writeln!(out, "Unknown command `{}`.", arg)?;
+                writeln!(out, "Unknown command `{arg}`.")?;
                 writeln!(out, "Available commands: ? help query load typecheck")?;
             }
         };
diff --git a/src/repl/query_print.rs b/src/repl/query_print.rs
index 37d02ab2..674e278b 100644
--- a/src/repl/query_print.rs
+++ b/src/repl/query_print.rs
@@ -29,7 +29,7 @@ pub struct SimpleRenderer {}
 /// Helper to render the result of the `query` sub-command without markdown support.
 impl QueryPrinter for SimpleRenderer {
     fn write_metadata(&self, out: &mut impl Write, attr: &str, value: &str) -> io::Result<()> {
-        writeln!(out, "* {}: {}", attr, value)
+        writeln!(out, "* {attr}: {value}")
     }
 
     fn write_doc(&self, out: &mut impl Write, content: &str) -> io::Result<()> {
@@ -37,7 +37,7 @@ impl QueryPrinter for SimpleRenderer {
             self.write_metadata(out, "documentation", content)
         } else {
             writeln!(out, "* documentation\n")?;
-            writeln!(out, "{}", content)
+            writeln!(out, "{content}")
         }
     }
 
@@ -48,7 +48,7 @@ impl QueryPrinter for SimpleRenderer {
         writeln!(out, "Available fields:")?;
 
         for field in fields {
-            writeln!(out, " - {}", field)?;
+            writeln!(out, " - {field}")?;
         }
 
         Ok(())
@@ -72,7 +72,7 @@ fn termimad_to_io(err: termimad::Error) -> io::Error {
         // query printer functions just for this variant that is specific to the termimad backend
         // doesn't seem to worth it.
         termimad::Error::InsufficientWidth(err) => {
-            io::Error::new(io::ErrorKind::Other, format!("{}", err))
+            io::Error::new(io::ErrorKind::Other, format!("{err}"))
         }
     }
 }
@@ -93,13 +93,13 @@ impl QueryPrinter for MarkdownRenderer {
         let text = expander.expand(&template);
         let (width, _) = terminal_size();
         let fmt_text = FmtText::from_text(&self.skin, text, Some(width as usize));
-        write!(out, "{}", fmt_text)
+        write!(out, "{fmt_text}")
     }
 
     fn write_doc(&self, out: &mut impl Write, content: &str) -> io::Result<()> {
         if content.find('\n').is_none() {
             self.skin
-                .write_text_on(out, &format!("* **documentation**: {}", content))
+                .write_text_on(out, &format!("* **documentation**: {content}"))
                 .map_err(termimad_to_io)
         } else {
             self.skin
@@ -130,7 +130,7 @@ impl QueryPrinter for MarkdownRenderer {
             expander.set("field", field.to_string());
             let text = expander.expand(&template);
             let fmt_text = FmtText::from_text(&self.skin, text, Some(width as usize));
-            write!(out, "{}", fmt_text)?;
+            write!(out, "{fmt_text}")?;
         }
 
         Ok(())
@@ -262,7 +262,7 @@ fn write_query_result_<R: QueryPrinter>(
                 },
             value: Some(t),
         } if selected_attrs.value => {
-            renderer.write_metadata(out, "priority", &format!("{}", n))?;
+            renderer.write_metadata(out, "priority", &format!("{n}"))?;
             renderer.write_metadata(out, "value", &t.as_ref().shallow_repr())?;
             found = true;
         }
diff --git a/src/repl/rustyline_frontend.rs b/src/repl/rustyline_frontend.rs
index d959056c..1a147c5e 100644
--- a/src/repl/rustyline_frontend.rs
+++ b/src/repl/rustyline_frontend.rs
@@ -86,7 +86,7 @@ pub fn repl(histfile: PathBuf, color_opt: ColorOpt) -> Result<(), InitError> {
                         _ => (),
                     }),
                     Ok(Command::Typecheck(exp)) => {
-                        repl.typecheck(&exp).map(|types| println!("Ok: {}", types))
+                        repl.typecheck(&exp).map(|types| println!("Ok: {types}"))
                     }
                     Ok(Command::Query(exp)) => repl.query(&exp).map(|field| {
                         query_print::write_query_result(
@@ -137,7 +137,7 @@ pub fn repl(histfile: PathBuf, color_opt: ColorOpt) -> Result<(), InitError> {
                 let _ = editor.save_history(&histfile);
                 program::report(
                     repl.cache_mut(),
-                    Error::IOError(IOError(format!("{}", err))),
+                    Error::IOError(IOError(format!("{err}"))),
                     color_opt,
                 );
             }
diff --git a/src/serialize.rs b/src/serialize.rs
index ade7de94..e769def5 100644
--- a/src/serialize.rs
+++ b/src/serialize.rs
@@ -228,7 +228,7 @@ where
         ExportFormat::Toml => toml::Value::try_from(rt)
             .map_err(|err| SerializationError::Other(err.to_string()))
             .and_then(|v| {
-                write!(writer, "{}", v).map_err(|err| SerializationError::Other(err.to_string()))
+                write!(writer, "{v}").map_err(|err| SerializationError::Other(err.to_string()))
             }),
         ExportFormat::Raw => match rt.as_ref() {
             Term::Str(s) => writer
@@ -252,7 +252,7 @@ pub fn to_string(format: ExportFormat, rt: &RichTerm) -> Result<String, Serializ
             serde_yaml::to_string(&rt).map_err(|err| SerializationError::Other(err.to_string()))
         }
         ExportFormat::Toml => toml::Value::try_from(rt)
-            .map(|v| format!("{}", v))
+            .map(|v| format!("{v}"))
             .map_err(|err| SerializationError::Other(err.to_string())),
         ExportFormat::Raw => match rt.as_ref() {
             Term::Str(s) => Ok(s.clone()),
@@ -285,7 +285,7 @@ mod tests {
 
         Program::new_from_source(src, "<test>").map_err(|io_err| {
             Error::EvalError(EvalError::Other(
-                format!("IO error: {}", io_err),
+                format!("IO error: {io_err}"),
                 TermPos::None,
             ))
         })
diff --git a/src/term/mod.rs b/src/term/mod.rs
index 399867ff..75b16e39 100644
--- a/src/term/mod.rs
+++ b/src/term/mod.rs
@@ -391,7 +391,7 @@ impl fmt::Display for MergePriority {
         match self {
             MergePriority::Bottom => write!(f, "default"),
             MergePriority::Neutral => write!(f, "{}", NumeralPriority::zero()),
-            MergePriority::Numeral(p) => write!(f, "{}", p),
+            MergePriority::Numeral(p) => write!(f, "{p}"),
             MergePriority::Top => write!(f, "force"),
         }
     }
@@ -627,8 +627,8 @@ impl Term {
             Term::Null => String::from("null"),
             Term::Bool(true) => String::from("true"),
             Term::Bool(false) => String::from("false"),
-            Term::Num(n) => format!("{}", n),
-            Term::Str(s) => format!("\"{}\"", s),
+            Term::Num(n) => format!("{n}"),
+            Term::Str(s) => format!("\"{s}\""),
             Term::StrChunks(chunks) => {
                 let chunks_str: Vec<String> = chunks
                     .iter()
@@ -648,9 +648,9 @@ impl Term {
                 let re = regex::Regex::new("_?[a-zA-Z][_a-zA-Z0-9]*").unwrap();
                 let s = id.to_string();
                 if re.is_match(&s) {
-                    format!("`{}", s)
+                    format!("`{s}")
                 } else {
-                    format!("`\"{}\"", s)
+                    format!("`\"{s}\"")
                 }
             }
             Term::Record(..) | Term::RecRecord(..) => String::from("{ ... }"),
@@ -683,7 +683,7 @@ impl Term {
                         if let Some(ref value) = field.value {
                             format!("{} = {}", ident, value.as_ref().deep_repr())
                         } else {
-                            format!("{}", ident)
+                            format!("{ident}")
                         }
                     })
                     .collect();
@@ -1363,7 +1363,7 @@ impl RichTerm {
     /// than the bound, the string is truncated to `max_width` and the last character after
     /// truncate is replaced by the ellipsis unicode character U+2026.
     pub fn pretty_print_cap(&self, max_width: usize) -> String {
-        let output = format!("{}", self);
+        let output = format!("{self}");
 
         if output.len() <= max_width {
             output
diff --git a/src/transform/desugar_destructuring.rs b/src/transform/desugar_destructuring.rs
index 197f9973..366fa528 100644
--- a/src/transform/desugar_destructuring.rs
+++ b/src/transform/desugar_destructuring.rs
@@ -68,8 +68,7 @@ pub fn desugar_fun(rt: RichTerm) -> RichTerm {
         },
         Term::FunPattern(Some(x), Destruct::Empty, t_) => RichTerm::new(Term::Fun(x, t_), rt.pos),
         t@Term::FunPattern(..) => panic!(
-            "A function can not have empty pattern without name in {:?}",
-            t
+            "A function can not have empty pattern without name in {t:?}"
         ),
     } else rt
     }
diff --git a/src/transform/mod.rs b/src/transform/mod.rs
index 168772bc..f01698e8 100644
--- a/src/transform/mod.rs
+++ b/src/transform/mod.rs
@@ -141,8 +141,7 @@ impl Closurizable for RichTerm {
         let idx = match self.as_ref() {
             Term::Var(id) if id.is_generated() => with_env.get(id).cloned().unwrap_or_else(|| {
                 panic!(
-                "Internal error(closurize) : generated identifier {} not found in the environment",
-                id
+                "Internal error(closurize) : generated identifier {id} not found in the environment"
             )
             }),
             _ => {
diff --git a/src/typecheck/mod.rs b/src/typecheck/mod.rs
index 3c461373..2b03beb8 100644
--- a/src/typecheck/mod.rs
+++ b/src/typecheck/mod.rs
@@ -610,7 +610,7 @@ pub fn mk_initial_ctxt(initial_env: &[RichTerm]) -> Result<Context, EnvBuildErro
                             .value
                             .as_ref()
                             .unwrap_or_else(|| {
-                                panic!("expected stdlib module {} to have a definition", id)
+                                panic!("expected stdlib module {id} to have a definition")
                             })
                             .clone(),
                     )
diff --git a/src/typecheck/reporting.rs b/src/typecheck/reporting.rs
index 984e5817..079d5a2a 100644
--- a/src/typecheck/reporting.rs
+++ b/src/typecheck/reporting.rs
@@ -37,7 +37,7 @@ fn mk_name(names: &HashMap<usize, Ident>, counter: &mut usize, id: usize) -> Str
     match names.get(&id) {
         // First check if that constant or variable was introduced by a forall. If it was, try
         // to use the same name.
-        Some(orig) => format!("{}", orig),
+        Some(orig) => format!("{orig}"),
         None => {
             //Otherwise, generate a new character
             let next = *counter;
@@ -60,11 +60,11 @@ fn select_uniq(name_reg: &mut NameReg, mut name: String, id: usize) -> Ident {
     if name_reg.taken.contains(&name) {
         let mut suffix = 1;
 
-        while name_reg.taken.contains(&format!("{}{}", name, suffix)) {
+        while name_reg.taken.contains(&format!("{name}{suffix}")) {
             suffix += 1;
         }
 
-        name = format!("{}{}", name, suffix);
+        name = format!("{name}{suffix}");
     }
 
     let ident = Ident::from(name);
diff --git a/src/types.rs b/src/types.rs
index ce48952a..ba04ecd2 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -965,12 +965,12 @@ impl Display for RecordRows {
                 write!(f, "{}: {}", row.id, row.types)?;
 
                 match tail.0 {
-                    RecordRowsF::Extend { .. } => write!(f, ", {}", tail),
-                    _ => write!(f, "{}", tail),
+                    RecordRowsF::Extend { .. } => write!(f, ", {tail}"),
+                    _ => write!(f, "{tail}"),
                 }
             }
             RecordRowsF::Empty => Ok(()),
-            RecordRowsF::TailVar(id) => write!(f, " ; {}", id),
+            RecordRowsF::TailVar(id) => write!(f, " ; {id}"),
             RecordRowsF::TailDyn => write!(f, " ; Dyn"),
         }
     }
@@ -980,15 +980,15 @@ impl Display for EnumRows {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.0 {
             EnumRowsF::Extend { ref row, ref tail } => {
-                write!(f, "`{}", row)?;
+                write!(f, "`{row}")?;
 
                 match tail.0 {
-                    EnumRowsF::Extend { .. } => write!(f, ", {}", tail),
-                    _ => write!(f, "{}", tail),
+                    EnumRowsF::Extend { .. } => write!(f, ", {tail}"),
+                    _ => write!(f, "{tail}"),
                 }
             }
             EnumRowsF::Empty => Ok(()),
-            EnumRowsF::TailVar(id) => write!(f, " ; {}", id),
+            EnumRowsF::TailVar(id) => write!(f, " ; {id}"),
         }
     }
 }
@@ -1004,29 +1004,29 @@ impl Display for Types {
                 write!(f, "Array ")?;
 
                 if ty.fmt_is_atom() {
-                    write!(f, "{}", ty)
+                    write!(f, "{ty}")
                 } else {
-                    write!(f, "({})", ty)
+                    write!(f, "({ty})")
                 }
             }
             TypeF::Sym => write!(f, "Sym"),
             TypeF::Flat(ref t) => write!(f, "{}", t.pretty_print_cap(32)),
-            TypeF::Var(var) => write!(f, "{}", var),
+            TypeF::Var(var) => write!(f, "{var}"),
             TypeF::Forall { var, ref body, .. } => {
                 let mut curr: &Types = body.as_ref();
-                write!(f, "forall {}", var)?;
+                write!(f, "forall {var}")?;
                 while let Types(TypeF::Forall { var, ref body, .. }) = curr {
-                    write!(f, " {}", var)?;
+                    write!(f, " {var}")?;
                     curr = body;
                 }
-                write!(f, ". {}", curr)
+                write!(f, ". {curr}")
             }
-            TypeF::Enum(row) => write!(f, "[|{}|]", row),
-            TypeF::Record(row) => write!(f, "{{{}}}", row),
-            TypeF::Dict(ty) => write!(f, "{{_: {}}}", ty),
+            TypeF::Enum(row) => write!(f, "[|{row}|]"),
+            TypeF::Record(row) => write!(f, "{{{row}}}"),
+            TypeF::Dict(ty) => write!(f, "{{_: {ty}}}"),
             TypeF::Arrow(dom, codom) => match dom.0 {
-                TypeF::Arrow(_, _) => write!(f, "({}) -> {}", dom, codom),
-                _ => write!(f, "{} -> {}", dom, codom),
+                TypeF::Arrow(_, _) => write!(f, "({dom}) -> {codom}"),
+                _ => write!(f, "{dom} -> {codom}"),
             },
             TypeF::Wildcard(_) => write!(f, "_"),
         }
@@ -1046,8 +1046,8 @@ mod test {
         use crate::term::TypeAnnotation;
 
         // Wrap the type in a contract to have it accepted by the parser.
-        let wrapper = format!("null | {}", s);
-        println!("{}", wrapper);
+        let wrapper = format!("null | {s}");
+        println!("{wrapper}");
         let id = Files::new().add("<test>", wrapper.clone());
 
         let rt = TermParser::new()
@@ -1070,7 +1070,7 @@ mod test {
     /// original type must be written in the same way as types are formatted.
     fn assert_format_eq(s: &str) {
         let ty = parse_type(s);
-        assert_eq!(s, &format!("{}", ty));
+        assert_eq!(s, &format!("{ty}"));
     }
 
     #[test]


Test patch:
diff --git a/src/eval/tests.rs b/src/eval/tests.rs
index e0ad3303..6ef6bacf 100644
--- a/src/eval/tests.rs
+++ b/src/eval/tests.rs
@@ -25,7 +25,7 @@ fn parse(s: &str) -> Option<RichTerm> {
     grammar::TermParser::new()
         .parse_term(id, lexer::Lexer::new(s))
         .map(RichTerm::without_pos)
-        .map_err(|err| println!("{:?}", err))
+        .map_err(|err| println!("{err:?}"))
         .ok()
 }
 
diff --git a/src/parser/tests.rs b/src/parser/tests.rs
index 3f95dc6d..b104c1b2 100644
--- a/src/parser/tests.rs
+++ b/src/parser/tests.rs
@@ -234,7 +234,7 @@ fn enum_terms() {
 
     for (name, input, expected) in success_cases {
         let actual = parse_without_pos(input);
-        assert_eq!(actual, expected, "test case \"{}\" failed", name,);
+        assert_eq!(actual, expected, "test case \"{name}\" failed",);
     }
 
     let failure_cases = [
@@ -435,12 +435,7 @@ fn string_lexing() {
             ],
         ),
     ] {
-        assert_eq!(
-            lex_without_pos(input),
-            Ok(expected),
-            "Case failed: {}",
-            name
-        )
+        assert_eq!(lex_without_pos(input), Ok(expected), "Case failed: {name}")
     }
 }
 
diff --git a/tests/integration/contracts_fail.rs b/tests/integration/contracts_fail.rs
index ee9acafc..98984e97 100644
--- a/tests/integration/contracts_fail.rs
+++ b/tests/integration/contracts_fail.rs
@@ -82,8 +82,7 @@ fn merge_compose_contract() {
             "let Even = fun l x => if x % 2 == 0 then x else %blame% l in
         let DivBy3 = fun l x => if x % 3 ==  0 then x else %blame% l in
         let composed = {{a | Even}} & {{a | DivBy3}} in
-        (({{a = {},}}) & composed).a",
-            arg
+        (({{a = {arg},}}) & composed).a"
         )
     };
 
@@ -215,7 +214,7 @@ fn records_contracts_poly() {
     // for that reason, you can just move the examples into the array above.
     let bad_acc = "let f | forall a. { ; a} -> { ; a} = fun x => %seq% x.a x in f";
     assert_matches!(
-        eval(format!("{} {{a=1}}", bad_acc)),
+        eval(format!("{bad_acc} {{a=1}}")),
         Err(Error::EvalError(EvalError::FieldMissing(..)))
     );
 
@@ -255,7 +254,7 @@ fn lists_contracts() {
         })) => {
             assert_matches!(label.path.as_slice(), [Elem::Array, Elem::Field(id), Elem::Array] if &id.to_string() == "a")
         }
-        err => panic!("expected blame error, got {:?}", err),
+        err => panic!("expected blame error, got {err:?}"),
     }
     // Check that reporting doesn't panic. Provide a dummy file database, as we won't report
     // the error message but just check that it can be built.
@@ -273,7 +272,7 @@ fn lists_contracts() {
         })) => {
             assert_matches!(label.path.as_slice(), [Elem::Field(id), Elem::Array, Elem::Codomain] if &id.to_string() == "foo")
         }
-        err => panic!("expected blame error, got {:?}", err),
+        err => panic!("expected blame error, got {err:?}"),
     }
     res.unwrap_err().to_diagnostic(&mut files, None);
 }
diff --git a/tests/integration/free_vars.rs b/tests/integration/free_vars.rs
index 55b1b929..059b8c39 100644
--- a/tests/integration/free_vars.rs
+++ b/tests/integration/free_vars.rs
@@ -41,7 +41,7 @@ fn check_dyn_vars(expr: &str, expected: Vec<Vec<&str>>) -> bool {
             let deps = deps.unwrap();
             dyns.len() == deps.dyn_fields.len() && dyn_free_vars_incl(&deps.dyn_fields, expected)
         }
-        _ => panic!("{} hasn't been parsed as a record", expr),
+        _ => panic!("{expr} hasn't been parsed as a record"),
     }
 }
 
@@ -59,7 +59,7 @@ fn check_stat_vars(expr: &str, expected: HashMap<&str, Vec<&str>>) -> bool {
             record.fields.len() == deps.stat_fields.len()
                 && stat_free_vars_incl(&deps.stat_fields, expected)
         }
-        _ => panic!("{} hasn't been parsed as a record", expr),
+        _ => panic!("{expr} hasn't been parsed as a record"),
     }
 }
 
diff --git a/tests/integration/imports.rs b/tests/integration/imports.rs
index 936e0cc7..7dd55fc5 100644
--- a/tests/integration/imports.rs
+++ b/tests/integration/imports.rs
@@ -7,7 +7,7 @@ use std::path::PathBuf;
 
 fn mk_import(file: &str) -> String {
     let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
-    path.push(format!("tests/integration/imports/{}", file));
+    path.push(format!("tests/integration/imports/{file}"));
     format!(
         "import \"{}\"",
         path.into_os_string().into_string().unwrap()
diff --git a/tests/integration/merge_fail.rs b/tests/integration/merge_fail.rs
index 063e02d2..4eda1aba 100644
--- a/tests/integration/merge_fail.rs
+++ b/tests/integration/merge_fail.rs
@@ -10,7 +10,7 @@ fn eval_full(s: &str) -> Result<RichTerm, Error> {
 
     let mut p = TestProgram::new_from_source(src, "<test>").map_err(|io_err| {
         Error::EvalError(EvalError::Other(
-            format!("IO error: {}", io_err),
+            format!("IO error: {io_err}"),
             TermPos::None,
         ))
     })?;
diff --git a/tests/integration/pretty.rs b/tests/integration/pretty.rs
index 2ba0d8b6..33b1801b 100644
--- a/tests/integration/pretty.rs
+++ b/tests/integration/pretty.rs
@@ -36,7 +36,7 @@ fn pretty(rt: &RichTerm) -> String {
 fn check_file(file: &str) {
     let mut buffer = String::new();
     let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
-    path.push(format!("tests/integration/pass/{}", file));
+    path.push(format!("tests/integration/pass/{file}"));
     std::fs::File::open(&path)
         .and_then(|mut file| file.read_to_string(&mut buffer))
         .unwrap();
diff --git a/tests/snapshot/main.rs b/tests/snapshot/main.rs
index 018b4df8..0bcc27b4 100644
--- a/tests/snapshot/main.rs
+++ b/tests/snapshot/main.rs
@@ -76,7 +76,7 @@ impl TestFile {
             .file_name()
             .and_then(|f| f.to_str())
             .expect("Could not extract file name");
-        format!("{}_{}", prefix, file_name)
+        format!("{prefix}_{file_name}")
     }
 
     fn as_nickel_argument(&self) -> &str {