tamer: asg::air: Errors for rooting_ci() TODOs

This eliminates the TODOs that existed when looking for an OI for rooting an
identifier.

The change to `rooting_ci` is ridiculous, but I want to get other things
done before I jump down the rabbit hole of generalizing that (indexing local
identifiers).  Though I have an approach in mind.

DEV-13708
main
Mike Gerwitz 2023-03-31 13:57:11 -04:00
parent a33d0c4ea5
commit e3d60750a9
6 changed files with 48 additions and 41 deletions

View File

@ -164,10 +164,10 @@ impl ParseState for AirAggregate {
// TODO: We don't support package ids yet
(st @ Toplevel(..), AirBind(BindIdent(id))) => {
Transition(st).err(AsgError::InvalidExprBindContext(id))
Transition(st).err(AsgError::InvalidBindContext(id))
}
(st @ Toplevel(..), AirBind(RefIdent(id))) => {
Transition(st).err(AsgError::InvalidExprRefContext(id))
Transition(st).err(AsgError::InvalidRefContext(id))
}
// Note: We unfortunately can't match on `AirExpr | AirBind`
@ -385,16 +385,20 @@ impl AirAggregateCtx {
}
}
/// The active container (binding context) for [`Ident`]s.
/// The active container (rooting context) for [`Ident`]s.
///
/// The integer value returned represents the stack offset at which the
/// rooting index was found,
/// with `0` representing the package.
///
/// A value of [`None`] indicates that no bindings are permitted in the
/// current context.
fn rooting_oi(&self) -> Option<ObjectIndexTo<Ident>> {
fn rooting_oi(&self) -> Option<(usize, ObjectIndexTo<Ident>)> {
let Self(_, stack, _) = self;
stack.iter().rev().find_map(|st| match st {
stack.iter().enumerate().rev().find_map(|(i, st)| match st {
AirAggregate::Empty => None,
AirAggregate::Toplevel(pkg_oi) => Some((*pkg_oi).into()),
AirAggregate::Toplevel(pkg_oi) => Some((i, (*pkg_oi).into())),
// Expressions never serve as roots for identifiers;
// this will always fall through to the parent context.
@ -408,7 +412,7 @@ impl AirAggregateCtx {
// Templates must therefore serve as containers for identifiers
// bound therein.
AirAggregate::PkgTpl(tplst) => {
tplst.active_tpl_oi().map(Into::into)
tplst.active_tpl_oi().map(|oi| (i, oi.into()))
}
})
}
@ -479,16 +483,19 @@ impl AirAggregateCtx {
/// indexing.
///
/// TODO: Generalize this.
fn defines(&mut self, name: SPair) -> ObjectIndex<Ident> {
let oi_root = self.rooting_oi().expect("TODO");
let Self(asg, stack, _) = self;
fn defines(&mut self, name: SPair) -> Result<ObjectIndex<Ident>, AsgError> {
let (stacki, oi_root) = self
.rooting_oi()
.ok_or(AsgError::InvalidBindContext(name))?;
match stack.len() {
1 => asg
let asg = self.asg_mut();
Ok(match stacki {
0 => asg
.lookup_global_or_missing(name)
.add_edge_from(asg, oi_root, None),
_ => oi_root.declare_local(asg, name),
}
})
}
}

View File

@ -123,12 +123,14 @@ impl ParseState for AirExprAggregate {
}
(BuildingExpr(es, oi), AirBind(BindIdent(id))) => {
let oi_ident = ctx.defines(id);
let result = ctx.defines(id).and_then(|oi_ident| {
oi_ident.bind_definition(ctx.asg_mut(), id, oi)
});
// It is important that we do not mark this expression as
// reachable unless we successfully bind the identifier.
match oi_ident.bind_definition(ctx.asg_mut(), id, oi) {
Ok(_) => {
match result {
Ok(oi_ident) => {
Transition(BuildingExpr(es.reachable_by(oi_ident), oi))
.incomplete()
}

View File

@ -506,7 +506,7 @@ fn expr_bind_to_empty() {
// since it's likely that a bind token was issued too late,
// rather than trying to interpret this as being back in a
// package context and binding to the package.
Err(ParseError::StateError(AsgError::InvalidExprBindContext(
Err(ParseError::StateError(AsgError::InvalidBindContext(
id_noexpr_a
))),
@ -516,7 +516,7 @@ fn expr_bind_to_empty() {
Ok(Parsed::Incomplete), // ExprEnd
// Another error after a successful expression.
Err(ParseError::StateError(AsgError::InvalidExprBindContext(
Err(ParseError::StateError(AsgError::InvalidBindContext(
id_noexpr_b
))),
// RECOVERY
@ -853,7 +853,7 @@ fn expr_ref_outside_of_expr_context() {
Ok(Parsed::Incomplete), // ExprEnd
// Now we're past the header and in expression parsing mode.
Err(ParseError::StateError(AsgError::InvalidExprRefContext(
Err(ParseError::StateError(AsgError::InvalidRefContext(
id_foo
))),

View File

@ -27,7 +27,7 @@ use super::{
AirAggregate, AirAggregateCtx,
};
use crate::{
asg::graph::object::{Meta, ObjectIndexRelTo},
asg::graph::object::Meta,
diagnose::Annotate,
diagnostic_todo,
fmt::{DisplayWrapper, TtQuote},
@ -182,16 +182,13 @@ impl ParseState for AirTplAggregate {
"nested tpl open"
),
(Toplevel(tpl), AirBind(BindIdent(id))) => {
let oi_root = ctx.rooting_oi().expect("TODO");
let asg = ctx.asg_mut();
asg.lookup_global_or_missing(id)
.bind_definition(asg, id, tpl.oi())
.map(|oi_ident| oi_root.defines(asg, oi_ident))
.map(|_| ())
.transition(Toplevel(tpl.identify(id)))
}
(Toplevel(tpl), AirBind(BindIdent(id))) => ctx
.defines(id)
.and_then(|oi_ident| {
oi_ident.bind_definition(ctx.asg_mut(), id, tpl.oi())
})
.map(|_| ())
.transition(Toplevel(tpl.identify(id))),
(Toplevel(tpl), AirBind(RefIdent(id))) => {
tpl.oi().apply_named_tpl(ctx.asg_mut(), id);

View File

@ -102,18 +102,18 @@ pub enum AsgError {
/// delimiter.
UnbalancedTpl(Span),
/// Attempted to bind the an identifier to an expression while not in an
/// expression context.
/// Attempted to bind an identifier to an object while not in a context
/// that can receive an identifier binding.
///
/// Note that the user may encounter an error from a higher-level IR
/// instead of this one.
InvalidExprBindContext(SPair),
InvalidBindContext(SPair),
/// Attempted to reference an identifier as part of an expression while
/// not in an expression context.
/// Attempted to reference an identifier while not in a context that can
/// receive an identifier reference.
///
/// Ideally this situation is syntactically invalid in a source IR.
InvalidExprRefContext(SPair),
InvalidRefContext(SPair),
}
impl Display for AsgError {
@ -140,10 +140,10 @@ impl Display for AsgError {
),
UnbalancedExpr(_) => write!(f, "unbalanced expression"),
UnbalancedTpl(_) => write!(f, "unbalanced template definition"),
InvalidExprBindContext(_) => {
InvalidBindContext(_) => {
write!(f, "invalid expression identifier binding context")
}
InvalidExprRefContext(ident) => {
InvalidRefContext(ident) => {
write!(
f,
"invalid context for expression identifier {}",
@ -243,7 +243,7 @@ impl Diagnostic for AsgError {
vec![span.error("there is no open template to close here")]
}
InvalidExprBindContext(span) => vec![
InvalidBindContext(span) => vec![
span.error(
"there is no active expression to bind this identifier to",
),
@ -253,7 +253,7 @@ impl Diagnostic for AsgError {
),
],
InvalidExprRefContext(ident) => vec![ident.error(
InvalidRefContext(ident) => vec![ident.error(
"cannot reference the value of an expression from outside \
of an expression context",
)],

View File

@ -697,7 +697,8 @@ impl Asg {
|| diagnostic_opaque_ident_desc(ident),
|| {
format!(
"opaque identifier: {} has no object binding",
"identifier was not expected to be opaque: \
{} has no object binding",
TtQuote::wrap(ident),
)
},