print all the relevant info

This commit is contained in:
Folkert 2022-11-23 22:58:58 +01:00
parent e7f3c6f281
commit e44a8a9eed
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
17 changed files with 308 additions and 12 deletions

View file

@ -1000,7 +1000,15 @@ fn roc_dev_native(
SIGUSR2 => {
// this is the signal we use for a dbg
println!("I need to dbg something");
roc_repl_expect::run::render_dbgs_in_memory(
&mut writer,
arena,
&mut expectations,
&interns,
&layout_interner,
&memory,
)
.unwrap();
}
_ => println!("received signal {}", sig),
}

View file

@ -615,10 +615,12 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
loc_condition,
loc_continuation,
variable,
symbol,
} => Dbg {
loc_condition: Box::new(loc_condition.map(|e| go_help!(e))),
loc_continuation: Box::new(loc_continuation.map(|e| go_help!(e))),
variable: sub!(*variable),
symbol: *symbol,
},
TypedHole(v) => TypedHole(sub!(*v)),

View file

@ -244,6 +244,7 @@ pub enum Expr {
loc_condition: Box<Loc<Expr>>,
loc_continuation: Box<Loc<Expr>>,
variable: Variable,
symbol: Symbol,
},
/// Rendered as empty box in editor
@ -260,6 +261,14 @@ pub struct ExpectLookup {
pub ability_info: Option<SpecializationId>,
}
#[derive(Clone, Copy, Debug)]
pub struct DbgLookup {
pub symbol: Symbol,
pub var: Variable,
pub region: Region,
pub ability_info: Option<SpecializationId>,
}
impl Expr {
pub fn category(&self) -> Category {
match self {
@ -1039,6 +1048,33 @@ pub fn canonicalize_expr<'a>(
output,
)
}
ast::Expr::Dbg(condition, continuation) => {
let mut output = Output::default();
let (loc_condition, output1) =
canonicalize_expr(env, var_store, scope, condition.region, &condition.value);
let (loc_continuation, output2) = canonicalize_expr(
env,
var_store,
scope,
continuation.region,
&continuation.value,
);
output.union(output1);
output.union(output2);
(
Dbg {
loc_condition: Box::new(loc_condition),
loc_continuation: Box::new(loc_continuation),
variable: var_store.fresh(),
symbol: scope.gen_unique_symbol(),
},
output,
)
}
ast::Expr::If(if_thens, final_else_branch) => {
let mut branches = Vec::with_capacity(if_thens.len());
let mut output = Output::default();
@ -1838,6 +1874,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
loc_condition,
loc_continuation,
variable,
symbol,
} => {
let loc_condition = Loc {
region: loc_condition.region,
@ -1853,6 +1890,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
loc_condition: Box::new(loc_condition),
loc_continuation: Box::new(loc_continuation),
variable,
symbol,
}
}
@ -2582,9 +2620,10 @@ impl Declarations {
})
}
pub fn expects(&self) -> VecMap<Region, Vec<ExpectLookup>> {
pub fn expects(&self) -> ExpectCollector {
let mut collector = ExpectCollector {
expects: VecMap::default(),
dbgs: VecMap::default(),
};
let var = Variable::EMPTY_RECORD;
@ -2617,7 +2656,7 @@ impl Declarations {
}
}
collector.expects
collector
}
}
@ -2897,8 +2936,9 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: b
loc_expr
}
struct ExpectCollector {
expects: VecMap<Region, Vec<ExpectLookup>>,
pub struct ExpectCollector {
pub expects: VecMap<Region, Vec<ExpectLookup>>,
pub dbgs: VecMap<Symbol, DbgLookup>,
}
impl crate::traverse::Visitor for ExpectCollector {
@ -2917,6 +2957,21 @@ impl crate::traverse::Visitor for ExpectCollector {
self.expects
.insert(loc_condition.region, lookups_in_cond.to_vec());
}
Expr::Dbg {
loc_condition,
variable,
symbol,
..
} => {
let lookup = DbgLookup {
symbol: *symbol,
var: *variable,
region: loc_condition.region,
ability_info: None,
};
self.dbgs.insert(*symbol, lookup);
}
_ => (),
}

View file

@ -3,7 +3,9 @@ use crate::annotation::{canonicalize_annotation, AnnotationFor};
use crate::def::{canonicalize_defs, Def};
use crate::effect_module::HostedGeneratedFunctions;
use crate::env::Env;
use crate::expr::{ClosureData, Declarations, ExpectLookup, Expr, Output, PendingDerives};
use crate::expr::{
ClosureData, DbgLookup, Declarations, ExpectLookup, Expr, Output, PendingDerives,
};
use crate::pattern::{BindingsFromPattern, Pattern};
use crate::scope::Scope;
use bumpalo::Bump;
@ -131,6 +133,7 @@ pub struct Module {
pub rigid_variables: RigidVariables,
pub abilities_store: PendingAbilitiesStore,
pub loc_expects: VecMap<Region, Vec<ExpectLookup>>,
pub loc_dbgs: VecMap<Symbol, DbgLookup>,
}
#[derive(Debug, Default)]
@ -153,6 +156,7 @@ pub struct ModuleOutput {
pub pending_derives: PendingDerives,
pub scope: Scope,
pub loc_expects: VecMap<Region, Vec<ExpectLookup>>,
pub loc_dbgs: VecMap<Symbol, DbgLookup>,
}
fn validate_generate_with<'a>(
@ -776,7 +780,7 @@ pub fn canonicalize_module_defs<'a>(
}
}
let loc_expects = declarations.expects();
let collected = declarations.expects();
ModuleOutput {
scope,
@ -789,7 +793,8 @@ pub fn canonicalize_module_defs<'a>(
problems: env.problems,
symbols_from_requires,
pending_derives,
loc_expects,
loc_expects: collected.expects,
loc_dbgs: collected.dbgs,
}
}

View file

@ -358,6 +358,14 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc<Expr<'a>>) -> &'a Loc
region: loc_expr.region,
})
}
Dbg(condition, continuation) => {
let desugared_condition = &*arena.alloc(desugar_expr(arena, condition));
let desugared_continuation = &*arena.alloc(desugar_expr(arena, continuation));
arena.alloc(Loc {
value: Dbg(desugared_condition, desugared_continuation),
region: loc_expr.region,
})
}
}
}

View file

@ -291,6 +291,7 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr, var: Variable) {
variable,
loc_condition,
loc_continuation,
symbol: _,
} => {
visitor.visit_expr(&loc_condition.value, loc_condition.region, *variable);
visitor.visit_expr(

View file

@ -660,6 +660,7 @@ pub fn constrain_expr(
loc_condition,
loc_continuation,
variable,
symbol: _,
} => {
let dbg_type = constraints.push_variable(*variable);
let expected_dbg = constraints.push_expected_type(Expected::NoExpectation(dbg_type));

View file

@ -71,6 +71,7 @@ impl<'a> Formattable for Expr<'a> {
Expect(condition, continuation) => {
condition.is_multiline() || continuation.is_multiline()
}
Dbg(condition, continuation) => condition.is_multiline() || continuation.is_multiline(),
If(branches, final_else) => {
final_else.is_multiline()
@ -379,6 +380,9 @@ impl<'a> Formattable for Expr<'a> {
Expect(condition, continuation) => {
fmt_expect(buf, condition, continuation, self.is_multiline(), indent);
}
Dbg(condition, continuation) => {
fmt_dbg(buf, condition, continuation, self.is_multiline(), indent);
}
If(branches, final_else) => {
fmt_if(buf, branches, final_else, self.is_multiline(), indent);
}
@ -843,6 +847,33 @@ fn fmt_when<'a, 'buf>(
}
}
fn fmt_dbg<'a, 'buf>(
buf: &mut Buf<'buf>,
condition: &'a Loc<Expr<'a>>,
continuation: &'a Loc<Expr<'a>>,
is_multiline: bool,
indent: u16,
) {
buf.ensure_ends_with_newline();
buf.indent(indent);
buf.push_str("dbg");
let return_indent = if is_multiline {
buf.newline();
indent + INDENT
} else {
buf.spaces(1);
indent
};
condition.format(buf, return_indent);
// Always put a blank line after the `dbg` line(s)
buf.ensure_ends_with_blank_line();
continuation.format(buf, indent);
}
fn fmt_expect<'a, 'buf>(
buf: &mut Buf<'buf>,
condition: &'a Loc<Expr<'a>>,

View file

@ -692,6 +692,10 @@ impl<'a> RemoveSpaces<'a> for Expr<'a> {
arena.alloc(a.remove_spaces(arena)),
arena.alloc(b.remove_spaces(arena)),
),
Expr::Dbg(a, b) => Expr::Dbg(
arena.alloc(a.remove_spaces(arena)),
arena.alloc(b.remove_spaces(arena)),
),
Expr::Apply(a, b, c) => Expr::Apply(
arena.alloc(a.remove_spaces(arena)),
b.remove_spaces(arena),

View file

@ -1123,7 +1123,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
// now what
arguments!(condition);
let region = roc_region::all::Region::zero(); // todo
let region = unsafe { std::mem::transmute::<_, roc_region::all::Region>(args[0]) };
crate::llvm::expect::clone_to_shared_memory(
env,
@ -1131,7 +1131,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
layout_ids,
args[0],
region,
&[],
&[args[0]],
);
crate::llvm::expect::send_dbg(env);

View file

@ -7,7 +7,7 @@ use parking_lot::Mutex;
use roc_builtins::roc::module_source;
use roc_can::abilities::{AbilitiesStore, PendingAbilitiesStore, ResolvedImpl};
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints, TypeOrVar};
use roc_can::expr::PendingDerives;
use roc_can::expr::{DbgLookup, PendingDerives};
use roc_can::expr::{Declarations, ExpectLookup};
use roc_can::module::{
canonicalize_module_defs, ExposedByModule, ExposedForModule, ExposedModuleTypes, Module,
@ -731,6 +731,7 @@ pub struct Expectations {
pub subs: roc_types::subs::Subs,
pub path: PathBuf,
pub expectations: VecMap<Region, Vec<ExpectLookup>>,
pub dbgs: VecMap<Symbol, DbgLookup>,
pub ident_ids: IdentIds,
}
@ -775,6 +776,7 @@ struct ParsedModule<'a> {
}
type LocExpects = VecMap<Region, Vec<ExpectLookup>>;
type LocDbgs = VecMap<Symbol, DbgLookup>;
/// A message sent out _from_ a worker thread,
/// representing a result of work done, or a request for further work
@ -794,6 +796,7 @@ enum Msg<'a> {
module_timing: ModuleTiming,
abilities_store: AbilitiesStore,
loc_expects: LocExpects,
loc_dbgs: LocDbgs,
},
FinishedAllTypeChecking {
solved_subs: Solved<Subs>,
@ -2403,6 +2406,7 @@ fn update<'a>(
mut module_timing,
abilities_store,
loc_expects,
loc_dbgs,
} => {
log!("solved types for {:?}", module_id);
module_timing.end_time = Instant::now();
@ -2424,6 +2428,7 @@ fn update<'a>(
let expectations = Expectations {
expectations: loc_expects,
dbgs: loc_dbgs,
subs: solved_subs.clone().into_inner(),
path: path.to_owned(),
ident_ids: ident_ids.clone(),
@ -4552,6 +4557,7 @@ fn run_solve<'a>(
let mut module = module;
let loc_expects = std::mem::take(&mut module.loc_expects);
let loc_dbgs = std::mem::take(&mut module.loc_dbgs);
let module = module;
let (solved_subs, solved_implementations, exposed_vars_by_symbol, problems, abilities_store) = {
@ -4626,6 +4632,7 @@ fn run_solve<'a>(
module_timing,
abilities_store,
loc_expects,
loc_dbgs,
}
}
@ -4832,6 +4839,7 @@ fn canonicalize_and_constrain<'a>(
rigid_variables: module_output.rigid_variables,
abilities_store: module_output.scope.abilities_store,
loc_expects: module_output.loc_expects,
loc_dbgs: module_output.loc_dbgs,
};
let constrained_module = ConstrainedModule {

View file

@ -6551,9 +6551,9 @@ pub fn from_can<'a>(
loc_condition,
loc_continuation,
variable,
symbol: dbg_symbol,
} => {
let rest = from_can(env, variable, loc_continuation.value, procs, layout_cache);
let dbg_symbol = env.unique_symbol();
let call = crate::ir::Call {
call_type: CallType::LowLevel {

View file

@ -208,6 +208,7 @@ pub enum Expr<'a> {
Defs(&'a Defs<'a>, &'a Loc<Expr<'a>>),
Backpassing(&'a [Loc<Pattern<'a>>], &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
Expect(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
Dbg(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
// Application
/// To apply by name, do Apply(Var(...), ...)

View file

@ -327,6 +327,7 @@ fn expr_start<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, E
loc!(specialize(EExpr::If, if_expr_help(options))),
loc!(specialize(EExpr::When, when::expr_help(options))),
loc!(specialize(EExpr::Expect, expect_help(options))),
loc!(specialize(EExpr::Dbg, dbg_help(options))),
loc!(specialize(EExpr::Closure, closure_help(options))),
loc!(expr_operator_chain(options)),
fail_expr_start_e()
@ -1912,6 +1913,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
| Expr::If(_, _)
| Expr::When(_, _)
| Expr::Expect(_, _)
| Expr::Dbg(_, _)
| Expr::MalformedClosure
| Expr::PrecedenceConflict { .. }
| Expr::RecordUpdate { .. }
@ -2330,6 +2332,36 @@ fn expect_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpe
}
}
fn dbg_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpect<'a>> {
move |arena: &'a Bump, state: State<'a>, min_indent| {
let start_column = state.column();
let (_, _, state) =
parser::keyword_e(keyword::DBG, EExpect::Dbg).parse(arena, state, min_indent)?;
let (_, condition, state) = space0_before_e(
specialize_ref(
EExpect::Condition,
set_min_indent(start_column + 1, expr_start(options)),
),
EExpect::IndentCondition,
)
.parse(arena, state, start_column + 1)
.map_err(|(_, f)| (MadeProgress, f))?;
let parse_cont = specialize_ref(
EExpect::Continuation,
space0_before_e(loc_expr(), EExpr::IndentEnd),
);
let (_, loc_cont, state) = parse_cont.parse(arena, state, min_indent)?;
let expr = Expr::Dbg(arena.alloc(condition), arena.alloc(loc_cont));
Ok((MadeProgress, expr, state))
}
}
fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<'a>> {
move |arena: &'a Bump, state, min_indent| {
let (_, _, state) =

View file

@ -354,6 +354,7 @@ pub enum EExpr<'a> {
If(EIf<'a>, Position),
Expect(EExpect<'a>, Position),
Dbg(EExpect<'a>, Position),
Closure(EClosure<'a>, Position),
Underscore(Position),

View file

@ -416,6 +416,44 @@ pub fn render_expects_in_memory<'a>(
)
}
pub fn render_dbgs_in_memory<'a>(
writer: &mut impl std::io::Write,
arena: &'a Bump,
expectations: &mut VecMap<ModuleId, Expectations>,
interns: &'a Interns,
layout_interner: &Arc<GlobalInterner<'a, Layout<'a>>>,
memory: &ExpectMemory,
) -> std::io::Result<usize> {
let shared_ptr = memory.ptr;
let frame = ExpectFrame::at_offset(shared_ptr, ExpectSequence::START_OFFSET);
let module_id = frame.module_id;
let data = expectations.get_mut(&module_id).unwrap();
let filename = data.path.to_owned();
let source = std::fs::read_to_string(&data.path).unwrap();
let renderer = Renderer::new(
arena,
interns,
RenderTarget::ColorTerminal,
module_id,
filename,
&source,
);
render_dbg_failure(
writer,
&renderer,
arena,
expectations,
interns,
layout_interner,
shared_ptr,
ExpectSequence::START_OFFSET,
)
}
fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> (Vec<Symbol>, Vec<Variable>) {
lookups
.iter()
@ -437,6 +475,69 @@ fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> (Vec<Symbol>,
.unzip()
}
#[allow(clippy::too_many_arguments)]
fn render_dbg_failure<'a>(
writer: &mut impl std::io::Write,
renderer: &Renderer,
arena: &'a Bump,
expectations: &mut VecMap<ModuleId, Expectations>,
interns: &'a Interns,
layout_interner: &Arc<GlobalInterner<'a, Layout<'a>>>,
start: *const u8,
offset: usize,
) -> std::io::Result<usize> {
// we always run programs as the host
let target_info = (&target_lexicon::Triple::host()).into();
let frame = ExpectFrame::at_offset(start, offset);
let module_id = frame.module_id;
let failure_region = frame.region;
let dbg_symbol = unsafe { std::mem::transmute::<_, Symbol>(failure_region) };
let expect_region = Some(Region::zero());
let data = expectations.get_mut(&module_id).unwrap();
let current = match data.dbgs.get(&dbg_symbol) {
None => panic!("region {failure_region:?} not in list of expects"),
Some(current) => current,
};
let failure_region = current.region;
let subs = arena.alloc(&mut data.subs);
let current = ExpectLookup {
symbol: current.symbol,
var: current.var,
ability_info: current.ability_info,
};
let (symbols, variables) = split_expect_lookups(subs, &[current]);
let (offset, expressions) = crate::get_values(
target_info,
arena,
subs,
interns,
layout_interner,
start,
frame.start_offset,
&variables,
);
renderer.render_dbg(
writer,
subs,
&symbols,
&variables,
&expressions,
expect_region,
failure_region,
)?;
Ok(offset)
}
#[allow(clippy::too_many_arguments)]
fn render_expect_failure<'a>(
writer: &mut impl std::io::Write,

View file

@ -164,6 +164,44 @@ impl<'a> Renderer<'a> {
write!(writer, "{}", buf)
}
#[allow(clippy::too_many_arguments)]
pub fn render_dbg<W>(
&self,
writer: &mut W,
subs: &mut Subs,
symbols: &[Symbol],
variables: &[Variable],
expressions: &[Expr<'_>],
expect_region: Option<Region>,
failure_region: Region,
) -> std::io::Result<()>
where
W: std::io::Write,
{
use crate::report::Report;
let line_col_region = self.to_line_col_region(expect_region, failure_region);
let doc = self.render_lookups(subs, line_col_region, symbols, variables, expressions);
let report = Report {
title: "DBG".into(),
doc,
filename: self.filename.clone(),
severity: crate::report::Severity::RuntimeError,
};
let mut buf = String::new();
report.render(
self.render_target,
&mut buf,
&self.alloc,
&crate::report::DEFAULT_PALETTE,
);
write!(writer, "{}", buf)
}
pub fn render_panic<W>(
&self,
writer: &mut W,