Merge pull request #5374 from GabrielDertoni/remove-needless-string-alloc

refactor: remove needless string allocation in pretty printer
This commit is contained in:
Folkert de Vries 2023-05-06 00:34:48 +02:00 committed by GitHub
commit ec21f19826
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 83 additions and 99 deletions

View file

@ -9,7 +9,7 @@ use crate::pattern::{Pattern, RecordDestruct, TupleDestruct};
use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_module::symbol::{Interns, ModuleId, Symbol};
use ven_pretty::{Arena, DocAllocator, DocBuilder}; use ven_pretty::{text, Arena, DocAllocator, DocBuilder};
pub struct Ctx<'a> { pub struct Ctx<'a> {
pub home: ModuleId, pub home: ModuleId,
@ -163,10 +163,10 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
use EPrec::*; use EPrec::*;
match e { match e {
Num(_, n, _, _) | Int(_, _, n, _, _) | Float(_, _, n, _, _) => f.text(&**n), Num(_, n, _, _) | Int(_, _, n, _, _) | Float(_, _, n, _, _) => f.text(&**n),
Str(s) => f.text(format!(r#""{}""#, s)), Str(s) => text!(f, r#""{}""#, s),
SingleQuote(_, _, c, _) => f.text(format!("'{}'", c)), SingleQuote(_, _, c, _) => text!(f, "'{}'", c),
IngestedFile(file_path, bytes, _) => { IngestedFile(file_path, bytes, _) => {
f.text(format!("<ingested {:?}, {} bytes>", file_path, bytes.len())) text!(f, "<ingested {:?}, {} bytes>", file_path, bytes.len())
} }
List { List {
elem_var: _, elem_var: _,
@ -354,15 +354,15 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
RecordAccess { RecordAccess {
loc_expr, field, .. loc_expr, field, ..
} => expr(c, AppArg, f, &loc_expr.value) } => expr(c, AppArg, f, &loc_expr.value)
.append(f.text(format!(".{}", field.as_str()))) .append(text!(f, ".{}", field.as_str()))
.group(), .group(),
TupleAccess { TupleAccess {
loc_expr, index, .. loc_expr, index, ..
} => expr(c, AppArg, f, &loc_expr.value) } => expr(c, AppArg, f, &loc_expr.value)
.append(f.text(format!(".{index}"))) .append(text!(f, ".{index}"))
.group(), .group(),
OpaqueWrapFunction(OpaqueWrapFunctionData { opaque_name, .. }) => { OpaqueWrapFunction(OpaqueWrapFunctionData { opaque_name, .. }) => {
f.text(format!("@{}", opaque_name.as_str(c.interns))) text!(f, "@{}", opaque_name.as_str(c.interns))
} }
RecordAccessor(_) => todo!(), RecordAccessor(_) => todo!(),
RecordUpdate { RecordUpdate {
@ -436,11 +436,12 @@ fn pp_sym<'a>(c: &Ctx, f: &'a Arena<'a>, sym: Symbol) -> DocBuilder<'a, Arena<'a
if sym.module_id() == c.home { if sym.module_id() == c.home {
f.text(sym.as_str(c.interns).to_owned()) f.text(sym.as_str(c.interns).to_owned())
} else { } else {
f.text(format!( text!(
f,
"{}.{}", "{}.{}",
sym.module_string(c.interns), sym.module_string(c.interns),
sym.as_str(c.interns), sym.as_str(c.interns),
)) )
} }
} }
@ -516,8 +517,7 @@ fn pattern<'a>(
), ),
UnwrappedOpaque { UnwrappedOpaque {
opaque, argument, .. opaque, argument, ..
} => f } => text!(f, "@{} ", opaque.module_string(c.interns))
.text(format!("@{} ", opaque.module_string(c.interns)))
.append(pattern(c, Free, f, &argument.1.value)) .append(pattern(c, Free, f, &argument.1.value))
.group(), .group(),
RecordDestructure { destructs, .. } => f RecordDestructure { destructs, .. } => f
@ -559,8 +559,8 @@ fn pattern<'a>(
NumLiteral(_, n, _, _) | IntLiteral(_, _, n, _, _) | FloatLiteral(_, _, n, _, _) => { NumLiteral(_, n, _, _) | IntLiteral(_, _, n, _, _) | FloatLiteral(_, _, n, _, _) => {
f.text(&**n) f.text(&**n)
} }
StrLiteral(s) => f.text(format!(r#""{}""#, s)), StrLiteral(s) => text!(f, r#""{}""#, s),
SingleQuote(_, _, c, _) => f.text(format!("'{}'", c)), SingleQuote(_, _, c, _) => text!(f, "'{}'", c),
Underscore => f.text("_"), Underscore => f.text("_"),
Shadowed(_, _, _) => todo!(), Shadowed(_, _, _) => todo!(),

View file

@ -1,7 +1,7 @@
use std::fmt::Display; use std::fmt::Display;
use roc_module::symbol::{Interns, Symbol}; use roc_module::symbol::{Interns, Symbol};
use ven_pretty::{Arena, DocAllocator, DocBuilder}; use ven_pretty::{text, Arena, DocAllocator, DocBuilder};
use crate::{ use crate::{
ir::{Parens, ProcLayout}, ir::{Parens, ProcLayout},
@ -103,11 +103,7 @@ fn format_sourced_doc<'d>(f: &'d Arena<'d>, line: usize, source: &str, doc: Doc<
fn format_header<'d>(f: &'d Arena<'d>, title: &str) -> Doc<'d> { fn format_header<'d>(f: &'d Arena<'d>, title: &str) -> Doc<'d> {
let title_width = title.len() + 4; let title_width = title.len() + 4;
f.text(format!( text!(f, "── {} {}", title, "".repeat(HEADER_WIDTH - title_width))
"── {} {}",
title,
"".repeat(HEADER_WIDTH - title_width)
))
} }
fn format_kind<'a, 'd, I>( fn format_kind<'a, 'd, I>(

View file

@ -36,7 +36,7 @@ use roc_types::subs::{
StorageSubs, Subs, Variable, VariableSubsSlice, StorageSubs, Subs, Variable, VariableSubsSlice,
}; };
use std::collections::HashMap; use std::collections::HashMap;
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder}; use ven_pretty::{text, BoxAllocator, DocAllocator, DocBuilder};
use pattern::{from_can_pattern, store_pattern, Pattern}; use pattern::{from_can_pattern, store_pattern, Pattern};
@ -1647,7 +1647,7 @@ impl ModifyRc {
.append(";"), .append(";"),
Inc(symbol, n) => alloc Inc(symbol, n) => alloc
.text("inc ") .text("inc ")
.append(alloc.text(format!("{} ", n))) .append(text!(alloc, "{} ", n))
.append(symbol_to_doc(alloc, symbol, pretty)) .append(symbol_to_doc(alloc, symbol, pretty))
.append(";"), .append(";"),
Dec(symbol) => alloc Dec(symbol) => alloc
@ -1700,24 +1700,19 @@ impl<'a> Call<'a> {
LowLevel { op: lowlevel, .. } => { LowLevel { op: lowlevel, .. } => {
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty)); let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
alloc text!(alloc, "lowlevel {:?} ", lowlevel).append(alloc.intersperse(it, " "))
.text(format!("lowlevel {:?} ", lowlevel))
.append(alloc.intersperse(it, " "))
} }
HigherOrder(higher_order) => { HigherOrder(higher_order) => {
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty)); let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
alloc text!(alloc, "lowlevel {:?} ", higher_order.op).append(alloc.intersperse(it, " "))
.text(format!("lowlevel {:?} ", higher_order.op))
.append(alloc.intersperse(it, " "))
} }
Foreign { Foreign {
ref foreign_symbol, .. ref foreign_symbol, ..
} => { } => {
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty)); let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
alloc text!(alloc, "foreign {:?} ", foreign_symbol.as_str())
.text(format!("foreign {:?} ", foreign_symbol.as_str()))
.append(alloc.intersperse(it, " ")) .append(alloc.intersperse(it, " "))
} }
} }
@ -1920,13 +1915,13 @@ impl<'a> Literal<'a> {
use Literal::*; use Literal::*;
match self { match self {
Int(bytes) => alloc.text(format!("{}i64", i128::from_ne_bytes(*bytes))), Int(bytes) => text!(alloc, "{}i64", i128::from_ne_bytes(*bytes)),
U128(bytes) => alloc.text(format!("{}u128", u128::from_ne_bytes(*bytes))), U128(bytes) => text!(alloc, "{}u128", u128::from_ne_bytes(*bytes)),
Float(lit) => alloc.text(format!("{}f64", lit)), Float(lit) => text!(alloc, "{}f64", lit),
Decimal(bytes) => alloc.text(format!("{}dec", RocDec::from_ne_bytes(*bytes))), Decimal(bytes) => text!(alloc, "{}dec", RocDec::from_ne_bytes(*bytes)),
Bool(lit) => alloc.text(format!("{}", lit)), Bool(lit) => text!(alloc, "{}", lit),
Byte(lit) => alloc.text(format!("{}u8", lit)), Byte(lit) => text!(alloc, "{}u8", lit),
Str(lit) => alloc.text(format!("{:?}", lit)), Str(lit) => text!(alloc, "{:?}", lit),
} }
} }
} }
@ -2064,11 +2059,10 @@ impl<'a> Expr<'a> {
StructAtIndex { StructAtIndex {
index, structure, .. index, structure, ..
} => alloc } => text!(alloc, "StructAtIndex {} ", index)
.text(format!("StructAtIndex {} ", index))
.append(symbol_to_doc(alloc, *structure, pretty)), .append(symbol_to_doc(alloc, *structure, pretty)),
RuntimeErrorFunction(s) => alloc.text(format!("ErrorFunction {}", s)), RuntimeErrorFunction(s) => text!(alloc, "ErrorFunction {}", s),
GetTagId { structure, .. } => alloc GetTagId { structure, .. } => alloc
.text("GetTagId ") .text("GetTagId ")
@ -2087,8 +2081,7 @@ impl<'a> Expr<'a> {
structure, structure,
index, index,
.. ..
} => alloc } => text!(alloc, "UnionAtIndex (Id {}) (Index {}) ", tag_id, index)
.text(format!("UnionAtIndex (Id {}) (Index {}) ", tag_id, index))
.append(symbol_to_doc(alloc, *structure, pretty)), .append(symbol_to_doc(alloc, *structure, pretty)),
} }
} }
@ -2216,8 +2209,7 @@ impl<'a> Stmt<'a> {
let branches_docs = branches let branches_docs = branches
.iter() .iter()
.map(|(tag, _info, expr)| { .map(|(tag, _info, expr)| {
alloc text!(alloc, "case {}:", tag)
.text(format!("case {}:", tag))
.append(alloc.hardline()) .append(alloc.hardline())
.append(expr.to_doc(alloc, interner, pretty).indent(4)) .append(expr.to_doc(alloc, interner, pretty).indent(4))
.indent(4) .indent(4)

View file

@ -1343,7 +1343,7 @@ mod debug_types {
use super::{TypeTag, Types}; use super::{TypeTag, Types};
use roc_collections::soa::{Index, Slice}; use roc_collections::soa::{Index, Slice};
use roc_module::ident::TagName; use roc_module::ident::TagName;
use ven_pretty::{Arena, DocAllocator, DocBuilder}; use ven_pretty::{text, Arena, DocAllocator, DocBuilder};
pub struct DebugTag<'a>(pub &'a Types, pub Index<TypeTag>); pub struct DebugTag<'a>(pub &'a Types, pub Index<TypeTag>);
@ -1409,13 +1409,13 @@ mod debug_types {
f.text("[") f.text("[")
.append( .append(
f.intersperse( f.intersperse(
Some(f.text(format!("{name:?}"))) Some(text!(f, "{name:?}"))
.into_iter() .into_iter()
.chain(captures.into_iter().map(|c| typ(types, f, Free, c))), .chain(captures.into_iter().map(|c| typ(types, f, Free, c))),
f.text(" "), f.text(" "),
), ),
) )
.append(f.text(format!(", ^{ambient_function:?}"))) .append(text!(f, ", ^{ambient_function:?}"))
.append(f.text("]")) .append(f.text("]"))
} }
TypeTag::FunctionOrTagUnion(_, _) => { TypeTag::FunctionOrTagUnion(_, _) => {
@ -1426,7 +1426,7 @@ mod debug_types {
unspecialized: Uls(var, sym, region), unspecialized: Uls(var, sym, region),
} => f } => f
.text("[") .text("[")
.append(f.text(format!("{var:?}:{sym:?}:{region}"))) .append(text!(f, "{var:?}:{sym:?}:{region}"))
.append(f.text("]")), .append(f.text("]")),
TypeTag::DelayedAlias { shared } => { TypeTag::DelayedAlias { shared } => {
maybe_paren!(Free, p, alias(types, f, tag, shared)) maybe_paren!(Free, p, alias(types, f, tag, shared))
@ -1464,7 +1464,7 @@ mod debug_types {
) )
) )
} }
TypeTag::Variable(var) => f.text(format!("{var:?}")), TypeTag::Variable(var) => text!(f, "{var:?}"),
TypeTag::RangedNumber(range) => ranged(f, range), TypeTag::RangedNumber(range) => ranged(f, range),
TypeTag::Error => f.text("ERROR"), TypeTag::Error => f.text("ERROR"),
TypeTag::TagUnion(tags, _) => { TypeTag::TagUnion(tags, _) => {
@ -1473,7 +1473,7 @@ mod debug_types {
TypeTag::RecursiveTagUnion(rec, tags, _) => tag_union( TypeTag::RecursiveTagUnion(rec, tags, _) => tag_union(
types, types,
f, f,
f.text(format!("<rec {rec:?}>")), text!(f, "<rec {rec:?}>"),
tags, tags,
types.get_type_arguments(tag), types.get_type_arguments(tag),
), ),
@ -1594,15 +1594,13 @@ mod debug_types {
} }
arg.append(f.text(" (+ ")) arg.append(f.text(" (+ "))
.append(f.intersperse( .append(f.intersperse(
abilities.sorted_iter().map(|ab| f.text(format!("{ab:?}"))), abilities.sorted_iter().map(|ab| text!(f, "{ab:?}")),
f.text(", "), f.text(", "),
)) ))
.append(f.text(")")) .append(f.text(")"))
}); });
f.intersperse( f.intersperse(
Some(f.text(format!("{symbol:?}"))) Some(text!(f, "{symbol:?}")).into_iter().chain(fmt_args),
.into_iter()
.chain(fmt_args),
f.text(" "), f.text(" "),
) )
} }

View file

@ -13,7 +13,7 @@ use std::path::PathBuf;
use crate::error::r#type::suggest; use crate::error::r#type::suggest;
use crate::report::{to_file_problem_report, Annotation, Report, RocDocAllocator, RocDocBuilder}; use crate::report::{to_file_problem_report, Annotation, Report, RocDocAllocator, RocDocBuilder};
use ven_pretty::DocAllocator; use ven_pretty::{text, DocAllocator};
const SYNTAX_PROBLEM: &str = "SYNTAX PROBLEM"; const SYNTAX_PROBLEM: &str = "SYNTAX PROBLEM";
const NAMING_PROBLEM: &str = "NAMING PROBLEM"; const NAMING_PROBLEM: &str = "NAMING PROBLEM";
@ -352,7 +352,7 @@ pub fn can_problem<'b>(
alloc.reflow("The definition of "), alloc.reflow("The definition of "),
alloc.symbol_unqualified(alias), alloc.symbol_unqualified(alias),
alloc.reflow(" has "), alloc.reflow(" has "),
alloc.text(format!("{}", num_unbound)), text!(alloc, "{}", num_unbound),
alloc.reflow(" unbound type variables."), alloc.reflow(" unbound type variables."),
])); ]));
stack.push(alloc.reflow("Here is one occurrence:")); stack.push(alloc.reflow("Here is one occurrence:"));
@ -1748,9 +1748,9 @@ fn pretty_runtime_error<'b>(
alloc.concat([ alloc.concat([
alloc alloc
.reflow("Roc uses signed 64-bit floating points, allowing values between "), .reflow("Roc uses signed 64-bit floating points, allowing values between "),
alloc.text(format!("{:e}", f64::MIN)), text!(alloc, "{:e}", f64::MIN),
alloc.reflow(" and "), alloc.reflow(" and "),
alloc.text(format!("{:e}", f64::MAX)), text!(alloc, "{:e}", f64::MAX),
]), ]),
tip, tip,
]); ]);

View file

@ -25,7 +25,7 @@ use roc_types::types::{
RecordField, TypeExt, RecordField, TypeExt,
}; };
use std::path::PathBuf; use std::path::PathBuf;
use ven_pretty::DocAllocator; use ven_pretty::{text, DocAllocator};
const ADD_ANNOTATIONS: &str = r#"Can more type annotations be added? Type annotations always help me give more specific messages, and I think they could help a lot in this case"#; const ADD_ANNOTATIONS: &str = r#"Can more type annotations be added? Type annotations always help me give more specific messages, and I think they could help a lot in this case"#;
@ -213,10 +213,10 @@ pub fn type_problem<'b>(
let stack = [ let stack = [
alloc.concat([ alloc.concat([
alloc.reflow("Failed to load "), alloc.reflow("Failed to load "),
alloc.text(format!("{:?}", file_path)), text!(alloc, "{:?}", file_path),
alloc.reflow(" as Str:"), alloc.reflow(" as Str:"),
]), ]),
alloc.text(format!("{}", utf8_err)), text!(alloc, "{}", utf8_err),
]; ];
Some(Report { Some(Report {
title: "INVALID UTF-8".to_string(), title: "INVALID UTF-8".to_string(),
@ -228,7 +228,7 @@ pub fn type_problem<'b>(
IngestedFileUnsupportedType(file_path, typ) => { IngestedFileUnsupportedType(file_path, typ) => {
let stack = [ let stack = [
alloc.concat([ alloc.concat([
alloc.text(format!("{:?}", file_path)), text!(alloc, "{:?}", file_path),
alloc.reflow(" is annotated to be a "), alloc.reflow(" is annotated to be a "),
alloc.inline_type_block(error_type_to_doc(alloc, typ)), alloc.inline_type_block(error_type_to_doc(alloc, typ)),
alloc.reflow("."), alloc.reflow("."),
@ -1678,7 +1678,7 @@ fn format_category<'b>(
match category { match category {
Lookup(name) => ( Lookup(name) => (
alloc.concat([ alloc.concat([
alloc.text(format!("{}his ", t)), text!(alloc, "{}his ", t),
alloc.symbol_foreign_qualified(*name), alloc.symbol_foreign_qualified(*name),
alloc.text(" value"), alloc.text(" value"),
]), ]),
@ -1687,7 +1687,7 @@ fn format_category<'b>(
If => ( If => (
alloc.concat([ alloc.concat([
alloc.text(format!("{}his ", t)), text!(alloc, "{}his ", t),
alloc.keyword("if"), alloc.keyword("if"),
alloc.text(" expression"), alloc.text(" expression"),
]), ]),
@ -1695,7 +1695,7 @@ fn format_category<'b>(
), ),
When => ( When => (
alloc.concat([ alloc.concat([
alloc.text(format!("{}his ", t)), text!(alloc, "{}his ", t),
alloc.keyword("when"), alloc.keyword("when"),
alloc.text(" expression"), alloc.text(" expression"),
]), ]),
@ -1730,10 +1730,7 @@ fn format_category<'b>(
alloc.text(" of type:"), alloc.text(" of type:"),
), ),
IngestedFile(file_path) => ( IngestedFile(file_path) => (
alloc.concat([ alloc.concat([this_is, text!(alloc, " an ingested file ({:?})", file_path)]),
this_is,
alloc.text(format!(" an ingested file ({:?})", file_path)),
]),
alloc.text(" of type:"), alloc.text(" of type:"),
), ),
Lambda => ( Lambda => (
@ -1747,7 +1744,7 @@ fn format_category<'b>(
OpaqueWrap(opaque) => ( OpaqueWrap(opaque) => (
alloc.concat([ alloc.concat([
alloc.text(format!("{}his ", t)), text!(alloc, "{}his ", t),
alloc.opaque_name(*opaque), alloc.opaque_name(*opaque),
alloc.text(" opaque wrapping"), alloc.text(" opaque wrapping"),
]), ]),
@ -1755,7 +1752,7 @@ fn format_category<'b>(
), ),
OpaqueArg => ( OpaqueArg => (
alloc.concat([alloc.text(format!("{}his argument to an opaque type", t))]), alloc.concat([text!(alloc, "{}his argument to an opaque type", t)]),
alloc.text(" has type:"), alloc.text(" has type:"),
), ),
@ -1764,7 +1761,7 @@ fn format_category<'b>(
args_count: 0, args_count: 0,
} => ( } => (
alloc.concat([ alloc.concat([
alloc.text(format!("{}his ", t)), text!(alloc, "{}his ", t),
alloc.tag(name.to_owned()), alloc.tag(name.to_owned()),
alloc.text(" tag"), alloc.text(" tag"),
]), ]),
@ -1776,7 +1773,7 @@ fn format_category<'b>(
args_count: _, args_count: _,
} => ( } => (
alloc.concat([ alloc.concat([
alloc.text(format!("{}his ", t)), text!(alloc, "{}his ", t),
alloc.tag(name.to_owned()), alloc.tag(name.to_owned()),
alloc.text(" tag application"), alloc.text(" tag application"),
]), ]),
@ -1790,7 +1787,7 @@ fn format_category<'b>(
Accessor(field) => ( Accessor(field) => (
alloc.concat([ alloc.concat([
alloc.text(format!("{}his ", t)), text!(alloc, "{}his ", t),
match field { match field {
IndexOrField::Index(index) => alloc.tuple_field(*index), IndexOrField::Index(index) => alloc.tuple_field(*index),
IndexOrField::Field(field) => alloc.record_field(field.to_owned()), IndexOrField::Field(field) => alloc.record_field(field.to_owned()),
@ -1801,7 +1798,7 @@ fn format_category<'b>(
), ),
RecordAccess(field) => ( RecordAccess(field) => (
alloc.concat([ alloc.concat([
alloc.text(format!("{}he value at ", t)), text!(alloc, "{}he value at ", t),
alloc.record_field(field.to_owned()), alloc.record_field(field.to_owned()),
]), ]),
alloc.text(" is a:"), alloc.text(" is a:"),
@ -1813,10 +1810,7 @@ fn format_category<'b>(
), ),
TupleAccess(index) => ( TupleAccess(index) => (
alloc.concat([ alloc.concat([text!(alloc, "{}he value at ", t), alloc.tuple_field(*index)]),
alloc.text(format!("{}he value at ", t)),
alloc.tuple_field(*index),
]),
alloc.text(" is a:"), alloc.text(" is a:"),
), ),
@ -1831,7 +1825,7 @@ fn format_category<'b>(
| BinOp::GreaterThanOrEq, | BinOp::GreaterThanOrEq,
), ),
) => ( ) => (
alloc.text(format!("{}his comparison", t)), text!(alloc, "{}his comparison", t),
alloc.text(" produces:"), alloc.text(" produces:"),
), ),
CallResult(Some(_), CalledVia::StringInterpolation) => ( CallResult(Some(_), CalledVia::StringInterpolation) => (
@ -1840,7 +1834,7 @@ fn format_category<'b>(
), ),
CallResult(Some(symbol), _) => ( CallResult(Some(symbol), _) => (
alloc.concat([ alloc.concat([
alloc.text(format!("{}his ", t)), text!(alloc, "{}his ", t),
alloc.symbol_foreign_qualified(*symbol), alloc.symbol_foreign_qualified(*symbol),
alloc.text(" call"), alloc.text(" call"),
]), ]),
@ -4812,8 +4806,7 @@ fn report_record_field_typo<'b>(
} else { } else {
let f = suggestions.remove(0); let f = suggestions.remove(0);
let fs = suggestions; let fs = suggestions;
let f_doc = alloc let f_doc = text!(alloc, "{}{}{}", field_prefix, field, field_suffix)
.text(format!("{}{}{}", field_prefix, field, field_suffix))
.annotate(Annotation::Typo); .annotate(Annotation::Typo);
let r_doc = match opt_sym { let r_doc = match opt_sym {
@ -4832,8 +4825,7 @@ fn report_record_field_typo<'b>(
alloc.reflow("Maybe "), alloc.reflow("Maybe "),
f_doc, f_doc,
alloc.reflow(" should be "), alloc.reflow(" should be "),
alloc text!(alloc, "{}{}{}", field_prefix, f.0, field_suffix)
.text(format!("{}{}{}", field_prefix, f.0, field_suffix))
.annotate(Annotation::TypoSuggestion), .annotate(Annotation::TypoSuggestion),
alloc.reflow(" instead?"), alloc.reflow(" instead?"),
]), ]),

View file

@ -5,7 +5,7 @@ use roc_problem::Severity;
use roc_region::all::LineColumnRegion; use roc_region::all::LineColumnRegion;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::{fmt, io}; use std::{fmt, io};
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder, Render, RenderAnnotated}; use ven_pretty::{text, BoxAllocator, DocAllocator, DocBuilder, Render, RenderAnnotated};
pub use crate::error::canonicalize::can_problem; pub use crate::error::canonicalize::can_problem;
pub use crate::error::parse::parse_problem; pub use crate::error::parse::parse_problem;
@ -393,27 +393,28 @@ impl<'a> RocDocAllocator<'a> {
self.text(symbol.as_str(self.interns)) self.text(symbol.as_str(self.interns))
.annotate(Annotation::Symbol) .annotate(Annotation::Symbol)
} else { } else {
self.text(format!( text!(
self,
"{}.{}", "{}.{}",
symbol.module_string(self.interns), symbol.module_string(self.interns),
symbol.as_str(self.interns), symbol.as_str(self.interns),
)) )
.annotate(Annotation::Symbol) .annotate(Annotation::Symbol)
} }
} }
pub fn symbol_qualified(&'a self, symbol: Symbol) -> DocBuilder<'a, Self, Annotation> { pub fn symbol_qualified(&'a self, symbol: Symbol) -> DocBuilder<'a, Self, Annotation> {
self.text(format!( text!(
self,
"{}.{}", "{}.{}",
symbol.module_string(self.interns), symbol.module_string(self.interns),
symbol.as_str(self.interns), symbol.as_str(self.interns),
)) )
.annotate(Annotation::Symbol) .annotate(Annotation::Symbol)
} }
/// TODO: remove in favor of tag_name /// TODO: remove in favor of tag_name
pub fn tag(&'a self, uppercase: Uppercase) -> DocBuilder<'a, Self, Annotation> { pub fn tag(&'a self, uppercase: Uppercase) -> DocBuilder<'a, Self, Annotation> {
self.text(format!("{}", uppercase)) text!(self, "{}", uppercase).annotate(Annotation::Tag)
.annotate(Annotation::Tag)
} }
pub fn opaque_name(&'a self, opaque: Symbol) -> DocBuilder<'a, Self, Annotation> { pub fn opaque_name(&'a self, opaque: Symbol) -> DocBuilder<'a, Self, Annotation> {
@ -434,18 +435,15 @@ impl<'a> RocDocAllocator<'a> {
pub fn wrapped_opaque_name(&'a self, opaque: Symbol) -> DocBuilder<'a, Self, Annotation> { pub fn wrapped_opaque_name(&'a self, opaque: Symbol) -> DocBuilder<'a, Self, Annotation> {
debug_assert_eq!(opaque.module_id(), self.home, "Opaque wrappings can only be defined in the same module they're defined in, but this one is defined elsewhere: {:?}", opaque); debug_assert_eq!(opaque.module_id(), self.home, "Opaque wrappings can only be defined in the same module they're defined in, but this one is defined elsewhere: {:?}", opaque);
self.text(format!("@{}", opaque.as_str(self.interns))) text!(self, "@{}", opaque.as_str(self.interns)).annotate(Annotation::Opaque)
.annotate(Annotation::Opaque)
} }
pub fn record_field(&'a self, lowercase: Lowercase) -> DocBuilder<'a, Self, Annotation> { pub fn record_field(&'a self, lowercase: Lowercase) -> DocBuilder<'a, Self, Annotation> {
self.text(format!(".{}", lowercase)) text!(self, ".{}", lowercase).annotate(Annotation::RecordField)
.annotate(Annotation::RecordField)
} }
pub fn tuple_field(&'a self, index: usize) -> DocBuilder<'a, Self, Annotation> { pub fn tuple_field(&'a self, index: usize) -> DocBuilder<'a, Self, Annotation> {
self.text(format!(".{}", index)) text!(self, ".{}", index).annotate(Annotation::TupleElem)
.annotate(Annotation::TupleElem)
} }
pub fn module(&'a self, module_id: ModuleId) -> DocBuilder<'a, Self, Annotation> { pub fn module(&'a self, module_id: ModuleId) -> DocBuilder<'a, Self, Annotation> {
@ -779,8 +777,7 @@ impl<'a> RocDocAllocator<'a> {
} }
pub fn ident(&'a self, ident: Ident) -> DocBuilder<'a, Self, Annotation> { pub fn ident(&'a self, ident: Ident) -> DocBuilder<'a, Self, Annotation> {
self.text(format!("{}", ident.as_inline_str())) text!(self, "{}", ident.as_inline_str()).annotate(Annotation::Symbol)
.annotate(Annotation::Symbol)
} }
pub fn int_literal<I>(&'a self, int: I) -> DocBuilder<'a, Self, Annotation> pub fn int_literal<I>(&'a self, int: I) -> DocBuilder<'a, Self, Annotation>

View file

@ -12,6 +12,15 @@ mod render;
pub use self::render::TermColored; pub use self::render::TermColored;
pub use self::render::{FmtWrite, IoWrite, Render, RenderAnnotated}; pub use self::render::{FmtWrite, IoWrite, Render, RenderAnnotated};
/// Macro to help build a text node with format arguments. It is semantically equivalent to `alloc.text(format(...))`, except
/// that it may not allocate a string at all.
#[macro_export]
macro_rules! text {
($alloc:expr, $($args:tt)*) => {
$alloc.as_string(format_args!($($args)*))
};
}
/// The concrete document type. This type is not meant to be used directly. Instead use the static /// The concrete document type. This type is not meant to be used directly. Instead use the static
/// functions on `Doc` or the methods on an `DocAllocator`. /// functions on `Doc` or the methods on an `DocAllocator`.
/// ///