cranelift-isle: Save variable names for later use (#5221)
It's nice to be able to report these names after sema analysis completes so rule authors can recognize which names they used. This isn't used anywhere yet, but I'm planning to use it during codegen, and the rule-verification folks wanted something like this for debugging output.
This commit is contained in:
@@ -429,12 +429,25 @@ pub struct Rule {
|
|||||||
/// The right-hand side expression that this rule evaluates upon successful
|
/// The right-hand side expression that this rule evaluates upon successful
|
||||||
/// match.
|
/// match.
|
||||||
pub rhs: Expr,
|
pub rhs: Expr,
|
||||||
|
/// Variable names used in this rule, indexed by [VarId].
|
||||||
|
pub vars: Vec<BoundVar>,
|
||||||
/// The priority of this rule, defaulted to 0 if it was missing in the source.
|
/// The priority of this rule, defaulted to 0 if it was missing in the source.
|
||||||
pub prio: i64,
|
pub prio: i64,
|
||||||
/// The source position where this rule is defined.
|
/// The source position where this rule is defined.
|
||||||
pub pos: Pos,
|
pub pos: Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A name bound in a pattern or let-expression.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct BoundVar {
|
||||||
|
/// The identifier used for this variable within the scope of the current [Rule].
|
||||||
|
pub id: VarId,
|
||||||
|
/// The variable's name.
|
||||||
|
pub name: Sym,
|
||||||
|
/// The type of the value this variable is bound to.
|
||||||
|
pub ty: TypeId,
|
||||||
|
}
|
||||||
|
|
||||||
/// An `if-let` clause with a subpattern match on an expr after the
|
/// An `if-let` clause with a subpattern match on an expr after the
|
||||||
/// main LHS matches.
|
/// main LHS matches.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -1082,17 +1095,22 @@ impl TypeEnv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct Bindings {
|
struct Bindings {
|
||||||
next_var: usize,
|
seen: Vec<BoundVar>,
|
||||||
vars: Vec<BoundVar>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
impl Bindings {
|
||||||
struct BoundVar {
|
fn add_var(&mut self, name: Sym, ty: TypeId) -> VarId {
|
||||||
name: Sym,
|
let id = VarId(self.seen.len());
|
||||||
id: VarId,
|
log!("binding var {:?} as {:?} with type {:?}", name.0, id, ty);
|
||||||
ty: TypeId,
|
self.seen.push(BoundVar { id, name, ty });
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup(&self, name: Sym) -> Option<&BoundVar> {
|
||||||
|
self.seen.iter().rev().find(|binding| binding.name == name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TermEnv {
|
impl TermEnv {
|
||||||
@@ -1623,10 +1641,7 @@ impl TermEnv {
|
|||||||
match def {
|
match def {
|
||||||
&ast::Def::Rule(ref rule) => {
|
&ast::Def::Rule(ref rule) => {
|
||||||
let pos = rule.pos;
|
let pos = rule.pos;
|
||||||
let mut bindings = Bindings {
|
let mut bindings = Bindings::default();
|
||||||
next_var: 0,
|
|
||||||
vars: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
let rule_term = match rule.pattern.root_term() {
|
let rule_term = match rule.pattern.root_term() {
|
||||||
Some(name) => {
|
Some(name) => {
|
||||||
@@ -1692,6 +1707,7 @@ impl TermEnv {
|
|||||||
lhs,
|
lhs,
|
||||||
iflets,
|
iflets,
|
||||||
rhs,
|
rhs,
|
||||||
|
vars: bindings.seen,
|
||||||
prio: rule.prio.unwrap_or(0),
|
prio: rule.prio.unwrap_or(0),
|
||||||
pos,
|
pos,
|
||||||
});
|
});
|
||||||
@@ -1878,18 +1894,14 @@ impl TermEnv {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let name = tyenv.intern_mut(var);
|
let name = tyenv.intern_mut(var);
|
||||||
if bindings.vars.iter().any(|bv| bv.name == name) {
|
if bindings.lookup(name).is_some() {
|
||||||
tyenv.report_error(
|
tyenv.report_error(
|
||||||
pos,
|
pos,
|
||||||
format!("Re-bound variable name in LHS pattern: '{}'", var.0),
|
format!("Re-bound variable name in LHS pattern: '{}'", var.0),
|
||||||
);
|
);
|
||||||
// Try to keep going.
|
// Try to keep going.
|
||||||
}
|
}
|
||||||
let id = VarId(bindings.next_var);
|
let id = bindings.add_var(name, ty);
|
||||||
bindings.next_var += 1;
|
|
||||||
log!("binding var {:?}", var.0);
|
|
||||||
bindings.vars.push(BoundVar { name, id, ty });
|
|
||||||
|
|
||||||
Some((Pattern::BindPattern(ty, id, Box::new(subpat)), ty))
|
Some((Pattern::BindPattern(ty, id, Box::new(subpat)), ty))
|
||||||
}
|
}
|
||||||
&ast::Pattern::Var { ref var, pos } => {
|
&ast::Pattern::Var { ref var, pos } => {
|
||||||
@@ -1899,7 +1911,7 @@ impl TermEnv {
|
|||||||
// `BindPattern` with a wildcard subpattern to capture
|
// `BindPattern` with a wildcard subpattern to capture
|
||||||
// at this location.
|
// at this location.
|
||||||
let name = tyenv.intern_mut(var);
|
let name = tyenv.intern_mut(var);
|
||||||
match bindings.vars.iter().rev().find(|bv| bv.name == name) {
|
match bindings.lookup(name) {
|
||||||
None => {
|
None => {
|
||||||
let ty = match expected_ty {
|
let ty = match expected_ty {
|
||||||
Some(ty) => ty,
|
Some(ty) => ty,
|
||||||
@@ -1911,10 +1923,7 @@ impl TermEnv {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let id = VarId(bindings.next_var);
|
let id = bindings.add_var(name, ty);
|
||||||
bindings.next_var += 1;
|
|
||||||
log!("binding var {:?}", var.0);
|
|
||||||
bindings.vars.push(BoundVar { name, id, ty });
|
|
||||||
Some((
|
Some((
|
||||||
Pattern::BindPattern(ty, id, Box::new(Pattern::Wildcard(ty))),
|
Pattern::BindPattern(ty, id, Box::new(Pattern::Wildcard(ty))),
|
||||||
ty,
|
ty,
|
||||||
@@ -2123,7 +2132,7 @@ impl TermEnv {
|
|||||||
None => {
|
None => {
|
||||||
// Maybe this was actually a variable binding and the user has placed
|
// Maybe this was actually a variable binding and the user has placed
|
||||||
// parens around it by mistake? (See #4775.)
|
// parens around it by mistake? (See #4775.)
|
||||||
if bindings.vars.iter().any(|b| b.name == name) {
|
if bindings.lookup(name).is_some() {
|
||||||
tyenv.report_error(
|
tyenv.report_error(
|
||||||
pos,
|
pos,
|
||||||
format!(
|
format!(
|
||||||
@@ -2215,7 +2224,7 @@ impl TermEnv {
|
|||||||
&ast::Expr::Var { ref name, pos } => {
|
&ast::Expr::Var { ref name, pos } => {
|
||||||
let sym = tyenv.intern_mut(name);
|
let sym = tyenv.intern_mut(name);
|
||||||
// Look through bindings, innermost (most recent) first.
|
// Look through bindings, innermost (most recent) first.
|
||||||
let bv = match bindings.vars.iter().rev().find(|b| b.name == sym) {
|
let bv = match bindings.lookup(sym) {
|
||||||
None => {
|
None => {
|
||||||
tyenv.report_error(pos, format!("Unknown variable '{}'", name.0));
|
tyenv.report_error(pos, format!("Unknown variable '{}'", name.0));
|
||||||
return None;
|
return None;
|
||||||
@@ -2295,7 +2304,7 @@ impl TermEnv {
|
|||||||
ref body,
|
ref body,
|
||||||
pos,
|
pos,
|
||||||
} => {
|
} => {
|
||||||
let orig_binding_len = bindings.vars.len();
|
let orig_binding_len = bindings.seen.len();
|
||||||
|
|
||||||
// For each new binding...
|
// For each new binding...
|
||||||
let mut let_defs = vec![];
|
let mut let_defs = vec![];
|
||||||
@@ -2335,10 +2344,7 @@ impl TermEnv {
|
|||||||
)));
|
)));
|
||||||
|
|
||||||
// Bind the var with the given type.
|
// Bind the var with the given type.
|
||||||
let id = VarId(bindings.next_var);
|
let id = bindings.add_var(name, tid);
|
||||||
bindings.next_var += 1;
|
|
||||||
bindings.vars.push(BoundVar { name, id, ty: tid });
|
|
||||||
|
|
||||||
let_defs.push((id, tid, val));
|
let_defs.push((id, tid, val));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2347,7 +2353,7 @@ impl TermEnv {
|
|||||||
let body_ty = body.ty();
|
let body_ty = body.ty();
|
||||||
|
|
||||||
// Pop the bindings.
|
// Pop the bindings.
|
||||||
bindings.vars.truncate(orig_binding_len);
|
bindings.seen.truncate(orig_binding_len);
|
||||||
|
|
||||||
Some(Expr::Let {
|
Some(Expr::Let {
|
||||||
ty: body_ty,
|
ty: body_ty,
|
||||||
|
|||||||
Reference in New Issue
Block a user