tamer: asg::air::ir::AirBind::RefIdent: New optional canonical name
This allows for a canonical package name to be optionally provided to explicitly resolve a reference against, avoiding a lexical lookup. This change doesn't actually utilize this new value yet; it just retains BC. The new argument will be used for the linker, since it already knows the package that defined an identifier while reading the object file's symbol table. It will also be used by tamec for the same purposes while processing package imports. DEV-13162 -- squashed with -- tamer: asg::air::ir::RefIdent: CanonicalName=SPair The use of CanonicalName created an asymmetry between RefIdent and BindIdent. The hope was to move CanonicalName instantiation outside of AIR and into NIR, but doing so would be confusing and awkward without doing something with BindIdent. I don't have the time to deal with that for now, so let's observe how the system continues to evolve and see whether hoisting it out makes sense in the end. For now, this works just fine and I need to move on with the actual goal of finishing package imports so that I can expand templates. DEV-13162main
parent
00492ace01
commit
572337505c
|
@ -42,6 +42,7 @@ use super::{
|
|||
use crate::{
|
||||
diagnose::Annotate,
|
||||
diagnostic_todo,
|
||||
fmt::{DisplayWrapper, TtQuote},
|
||||
parse::{prelude::*, StateStack},
|
||||
span::{Span, UNKNOWN_SPAN},
|
||||
sym::SymbolId,
|
||||
|
@ -217,11 +218,39 @@ impl ParseState for AirAggregate {
|
|||
}
|
||||
|
||||
// Package import
|
||||
(Toplevel(oi_pkg), AirBind(RefIdent(pathspec))) => oi_pkg
|
||||
.import(ctx.asg_mut(), pathspec)
|
||||
(Toplevel(oi_pkg), AirBind(RefIdent(namespec, None))) => oi_pkg
|
||||
.import(ctx.asg_mut(), namespec)
|
||||
.map(|_| ())
|
||||
.transition(Toplevel(oi_pkg)),
|
||||
|
||||
// Providing a canonical package name here makes a lot of sense,
|
||||
// but we'd have to figure out what to expect for the namespec
|
||||
// in this case.
|
||||
// For example,
|
||||
// we could use it to import specific identifiers,
|
||||
// or '*',
|
||||
// or anything really.
|
||||
// The system should never produce this,
|
||||
// thus the internal error.
|
||||
(Toplevel(oi_pkg), AirBind(RefIdent(namespec, Some(in_pkg)))) => {
|
||||
crate::diagnostic_panic!(
|
||||
vec![
|
||||
oi_pkg.note("in this package"),
|
||||
namespec.note("for this namespec"),
|
||||
in_pkg.internal_error(
|
||||
"unexpected pre-resolved canonical package name"
|
||||
),
|
||||
in_pkg.help(
|
||||
"TAMER expected to resolve the namespec itself; \
|
||||
this could lead to a potential contradiction"
|
||||
),
|
||||
],
|
||||
"unexpected pre-resolved canonical package name \
|
||||
for namespec {}",
|
||||
TtQuote::wrap(namespec),
|
||||
)
|
||||
}
|
||||
|
||||
// Note: We unfortunately can't match on `AirExpr | AirBind | ...`
|
||||
// and delegate in the same block
|
||||
// (without having to duplicate type checks and then handle
|
||||
|
|
|
@ -138,7 +138,7 @@ impl ParseState for AirExprAggregate {
|
|||
}
|
||||
}
|
||||
|
||||
(BuildingExpr(es, oi), AirBind(RefIdent(name))) => {
|
||||
(BuildingExpr(es, oi), AirBind(RefIdent(name, None))) => {
|
||||
let oi_ident = ctx.lookup_lexical_or_missing(name);
|
||||
Transition(BuildingExpr(
|
||||
es,
|
||||
|
@ -147,6 +147,19 @@ impl ParseState for AirExprAggregate {
|
|||
.incomplete()
|
||||
}
|
||||
|
||||
(BuildingExpr(..), AirBind(RefIdent(name, Some(in_pkg)))) => {
|
||||
use crate::diagnose::Annotate;
|
||||
crate::diagnostic_todo!(
|
||||
vec![
|
||||
in_pkg.note("for an identifier in this package"),
|
||||
name.internal_error(
|
||||
"RefIdent with resolved Pkg not yet supported"
|
||||
)
|
||||
],
|
||||
"RefIdent with resolved Pkg",
|
||||
)
|
||||
}
|
||||
|
||||
(BuildingExpr(es, oi), AirDoc(DocIndepClause(clause))) => {
|
||||
oi.desc_short(ctx.asg_mut(), clause);
|
||||
Transition(BuildingExpr(es, oi)).incomplete()
|
||||
|
|
|
@ -703,7 +703,7 @@ fn expr_ref_to_ident() {
|
|||
|
||||
// Reference to an as-of-yet-undefined id (okay),
|
||||
// with a different span than `id_bar`.
|
||||
Air::RefIdent(SPair("bar".into(), S3)),
|
||||
Air::RefIdent(SPair("bar".into(), S3), None),
|
||||
Air::ExprEnd(S4),
|
||||
|
||||
//
|
||||
|
@ -762,7 +762,7 @@ fn idents_share_defining_pkg() {
|
|||
|
||||
Air::ExprStart(ExprOp::Sum, S4),
|
||||
Air::BindIdent(id_bar),
|
||||
Air::RefIdent(id_baz),
|
||||
Air::RefIdent(id_baz, None),
|
||||
Air::ExprEnd(S7),
|
||||
Air::ExprEnd(S8),
|
||||
Air::PkgEnd(S9),
|
||||
|
|
|
@ -537,7 +537,22 @@ sum_ir! {
|
|||
/// However,
|
||||
/// the identifier must eventually be bound to an object of
|
||||
/// the appropriate type depending on context.
|
||||
RefIdent(id: SPair) => {
|
||||
///
|
||||
/// A reference may optionally be accompanied by an explicit
|
||||
/// package resolution.
|
||||
/// If present,
|
||||
/// then the identifier is explicitly bound to an identifier
|
||||
/// in a package _canonically_ named by the provided
|
||||
/// [`SPair`].
|
||||
/// Otherwise,
|
||||
/// a value of [`None`] indicates that the reference should be
|
||||
/// resolved in the usual way using lexical scoping rules and
|
||||
/// considering package imports.
|
||||
///
|
||||
/// The canonical name has potential attractive future use cases,
|
||||
/// including the ability to reference identifiers from
|
||||
/// packages that have not been explicitly imported.
|
||||
RefIdent(id: SPair, pkg: Option<SPair>) => {
|
||||
span: id,
|
||||
display: |f| write!(
|
||||
f,
|
||||
|
|
|
@ -566,7 +566,7 @@ fn pkg_import_canonicalized_against_current_pkg() {
|
|||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
BindIdent(pkg_name),
|
||||
RefIdent(pkg_rel),
|
||||
RefIdent(pkg_rel, None),
|
||||
PkgEnd(S3),
|
||||
];
|
||||
|
||||
|
@ -602,7 +602,7 @@ fn pkg_doc() {
|
|||
|
||||
// Some object to place in-between the two
|
||||
// documentation blocks.
|
||||
RefIdent(id_import),
|
||||
RefIdent(id_import, None),
|
||||
|
||||
DocText(doc_b),
|
||||
];
|
||||
|
|
|
@ -197,7 +197,7 @@ impl ParseState for AirTplAggregate {
|
|||
.map(|_| ())
|
||||
.transition(Toplevel(tpl.identify(id))),
|
||||
|
||||
(Toplevel(tpl), AirBind(RefIdent(name))) => {
|
||||
(Toplevel(tpl), AirBind(RefIdent(name, None))) => {
|
||||
let tpl_oi = tpl.oi();
|
||||
let ref_oi = ctx.lookup_lexical_or_missing(name);
|
||||
|
||||
|
@ -206,6 +206,18 @@ impl ParseState for AirTplAggregate {
|
|||
Transition(Toplevel(tpl)).incomplete()
|
||||
}
|
||||
|
||||
(Toplevel(..), AirBind(RefIdent(name, Some(in_pkg)))) => {
|
||||
crate::diagnostic_todo!(
|
||||
vec![
|
||||
in_pkg.note("for an identifier in this package"),
|
||||
name.internal_error(
|
||||
"RefIdent with resolved Pkg not yet supported"
|
||||
)
|
||||
],
|
||||
"RefIdent with resolved Pkg",
|
||||
)
|
||||
}
|
||||
|
||||
(Toplevel(tpl), AirDoc(DocIndepClause(clause))) => {
|
||||
tpl.oi().desc_short(ctx.asg_mut(), clause);
|
||||
Transition(Toplevel(tpl)).incomplete()
|
||||
|
|
|
@ -182,7 +182,7 @@ fn tpl_apply_within_expr() {
|
|||
|
||||
// But the application will remain.
|
||||
Air::TplStart(S7),
|
||||
Air::RefIdent(ref_tpl),
|
||||
Air::RefIdent(ref_tpl, None),
|
||||
Air::TplEndRef(S9),
|
||||
Air::ExprEnd(S10),
|
||||
];
|
||||
|
@ -600,7 +600,7 @@ fn tpl_apply_nested_missing() {
|
|||
|
||||
// Inner template application (Missing)
|
||||
Air::TplStart(S3),
|
||||
Air::RefIdent(ref_tpl_inner_pre),
|
||||
Air::RefIdent(ref_tpl_inner_pre, None),
|
||||
Air::TplEndRef(S5),
|
||||
|
||||
// Define the template above
|
||||
|
@ -611,7 +611,7 @@ fn tpl_apply_nested_missing() {
|
|||
// Apply again,
|
||||
// this time _after_ having been defined.
|
||||
Air::TplStart(S9),
|
||||
Air::RefIdent(ref_tpl_inner_post),
|
||||
Air::RefIdent(ref_tpl_inner_post, None),
|
||||
Air::TplEndRef(S11),
|
||||
Air::TplEnd(S12),
|
||||
];
|
||||
|
|
|
@ -84,7 +84,7 @@ fn traverses_ontological_tree() {
|
|||
ExprStart(ExprOp::Sum, S4),
|
||||
ExprEnd(S5),
|
||||
|
||||
RefIdent(SPair(id_b.symbol(), S6)),
|
||||
RefIdent(SPair(id_b.symbol(), S6), None),
|
||||
ExprEnd(S7),
|
||||
|
||||
ExprStart(ExprOp::Sum, S8),
|
||||
|
@ -212,7 +212,7 @@ fn traverses_ontological_tree_tpl_apply() {
|
|||
|
||||
// Apply the above template.
|
||||
TplStart(S5),
|
||||
RefIdent(ref_tpl),
|
||||
RefIdent(ref_tpl, None),
|
||||
|
||||
TplMetaStart(S7),
|
||||
BindIdent(id_param),
|
||||
|
@ -273,18 +273,18 @@ fn traverses_ontological_tree_tpl_within_template() {
|
|||
// which will begin as Missing and must be later resolved when
|
||||
// the template is defined.
|
||||
TplStart(S6),
|
||||
RefIdent(ref_inner_before), // --.
|
||||
TplEndRef(S8), // |
|
||||
// |
|
||||
// Named inner template. // |
|
||||
TplStart(S9), // /
|
||||
BindIdent(id_tpl_inner), //<-:
|
||||
TplEnd(S11), // \
|
||||
// |
|
||||
// Apply above inner template, // |
|
||||
// _after_ definition. // |
|
||||
TplStart(S12), // |
|
||||
RefIdent(ref_inner_after), // __/
|
||||
RefIdent(ref_inner_before, None), // --.
|
||||
TplEndRef(S8), // |
|
||||
// |
|
||||
// Named inner template. // |
|
||||
TplStart(S9), // /
|
||||
BindIdent(id_tpl_inner), //<-:
|
||||
TplEnd(S11), // \
|
||||
// |
|
||||
// Apply above inner template, // |
|
||||
// _after_ definition. // |
|
||||
TplStart(S12), // |
|
||||
RefIdent(ref_inner_after, None), // __/
|
||||
TplEndRef(S14),
|
||||
TplEnd(S15),
|
||||
PkgEnd(S16),
|
||||
|
|
|
@ -89,26 +89,26 @@ fn sorts_objects_given_single_root() {
|
|||
PkgStart(S1),
|
||||
// Before this can be computed,
|
||||
// its dependencies must be.
|
||||
ExprStart(ExprOp::Sum, S2), // -.
|
||||
BindIdent(id_a), // |
|
||||
// |
|
||||
// This is a dependency, // |
|
||||
// but it is owned by this Expr // |
|
||||
// and so would have been emitted // |
|
||||
// first anyway. // |
|
||||
ExprStart(ExprOp::Sum, S4), // |
|
||||
ExprEnd(S5), // |
|
||||
// v
|
||||
ExprStart(ExprOp::Sum, S2), // -.
|
||||
BindIdent(id_a), // |
|
||||
// |
|
||||
// This is a dependency, // |
|
||||
// but it is owned by this Expr // |
|
||||
// and so would have been emitted // |
|
||||
// first anyway. // |
|
||||
ExprStart(ExprOp::Sum, S4), // |
|
||||
ExprEnd(S5), // |
|
||||
// v
|
||||
// But this is a reference to another
|
||||
// Expr that appears later.
|
||||
RefIdent(SPair(id_b.symbol(), S6)), // --.
|
||||
ExprEnd(S7), // |
|
||||
// |
|
||||
// This will have to be emitted // |
|
||||
// _before_ the above Expr that // |
|
||||
// depends on its value having been // |
|
||||
// computed. // /
|
||||
ExprStart(ExprOp::Sum, S8), // <`
|
||||
RefIdent(SPair(id_b.symbol(), S6), None), // --.
|
||||
ExprEnd(S7), // |
|
||||
// |
|
||||
// This will have to be emitted // |
|
||||
// _before_ the above Expr that // |
|
||||
// depends on its value having been // |
|
||||
// computed. // /
|
||||
ExprStart(ExprOp::Sum, S8), // <`
|
||||
BindIdent(id_b),
|
||||
ExprEnd(S10),
|
||||
|
||||
|
@ -176,21 +176,21 @@ fn sorts_objects_given_single_root_more_complex() {
|
|||
PkgStart(S1),
|
||||
ExprStart(ExprOp::Sum, S2),
|
||||
BindIdent(id_a),
|
||||
RefIdent(SPair(id_b.symbol(), S4)), // ---.
|
||||
ExprEnd(S5), // )
|
||||
// /
|
||||
ExprStart(ExprOp::Sum, S6), // /
|
||||
BindIdent(id_b), // <'
|
||||
RefIdent(SPair(id_d.symbol(), S8)), // -------.
|
||||
ExprEnd(S9), // <. |
|
||||
// \ |
|
||||
ExprStart(ExprOp::Sum, S10), // \ |
|
||||
BindIdent(id_c), // ) |
|
||||
RefIdent(SPair(id_b.symbol(), S12)), // ---' /
|
||||
ExprEnd(S13), // /
|
||||
// /
|
||||
ExprStart(ExprOp::Sum, S14), // /
|
||||
BindIdent(id_d), // <--'
|
||||
RefIdent(SPair(id_b.symbol(), S4), None), // ---.
|
||||
ExprEnd(S5), // )
|
||||
// /
|
||||
ExprStart(ExprOp::Sum, S6), // /
|
||||
BindIdent(id_b), // <'
|
||||
RefIdent(SPair(id_d.symbol(), S8), None), // -------.
|
||||
ExprEnd(S9), // <. |
|
||||
// \ |
|
||||
ExprStart(ExprOp::Sum, S10), // \ |
|
||||
BindIdent(id_c), // ) |
|
||||
RefIdent(SPair(id_b.symbol(), S12), None), // ---' /
|
||||
ExprEnd(S13), // /
|
||||
// /
|
||||
ExprStart(ExprOp::Sum, S14), // /
|
||||
BindIdent(id_d), // <--'
|
||||
ExprEnd(S16),
|
||||
PkgEnd(S17),
|
||||
];
|
||||
|
@ -236,21 +236,21 @@ fn omits_unreachable() {
|
|||
PkgStart(S1),
|
||||
ExprStart(ExprOp::Sum, S2),
|
||||
BindIdent(id_a),
|
||||
RefIdent(SPair(id_b.symbol(), S4)), // ---.
|
||||
ExprEnd(S5), // )
|
||||
// /
|
||||
ExprStart(ExprOp::Sum, S6), // /
|
||||
BindIdent(id_b), // <'
|
||||
RefIdent(SPair(id_d.symbol(), S8)), // -------.
|
||||
ExprEnd(S9), // <. |
|
||||
// \ |
|
||||
ExprStart(ExprOp::Sum, S10), // \ |
|
||||
BindIdent(id_c), // ) |
|
||||
RefIdent(SPair(id_b.symbol(), S12)), // ---' /
|
||||
ExprEnd(S13), // /
|
||||
// /
|
||||
ExprStart(ExprOp::Sum, S14), // /
|
||||
BindIdent(id_d), // <--'
|
||||
RefIdent(SPair(id_b.symbol(), S4), None), // ---.
|
||||
ExprEnd(S5), // )
|
||||
// /
|
||||
ExprStart(ExprOp::Sum, S6), // /
|
||||
BindIdent(id_b), // <'
|
||||
RefIdent(SPair(id_d.symbol(), S8), None), // -------.
|
||||
ExprEnd(S9), // <. |
|
||||
// \ |
|
||||
ExprStart(ExprOp::Sum, S10), // \ |
|
||||
BindIdent(id_c), // ) |
|
||||
RefIdent(SPair(id_b.symbol(), S12), None), // ---' /
|
||||
ExprEnd(S13), // /
|
||||
// /
|
||||
ExprStart(ExprOp::Sum, S14), // /
|
||||
BindIdent(id_d), // <--'
|
||||
ExprEnd(S16),
|
||||
PkgEnd(S17),
|
||||
];
|
||||
|
@ -363,14 +363,14 @@ fn unsupported_cycles_with_recovery() {
|
|||
let toks = vec![
|
||||
PkgStart(S1),
|
||||
ExprStart(ExprOp::Sum, S2),
|
||||
BindIdent(id_a), // <----. self-cycle
|
||||
RefIdent(SPair(id_a.symbol(), S4)), // ____/ \
|
||||
RefIdent(SPair(id_b.symbol(), S5)), // ---. \ a->b->a
|
||||
ExprEnd(S6), // ) ) cycle
|
||||
// / /
|
||||
ExprStart(ExprOp::Sum, S7), // / /
|
||||
BindIdent(id_b), // <' /
|
||||
RefIdent(SPair(id_a.symbol(), S9)), // ----'
|
||||
BindIdent(id_a), // <----. self-cycle
|
||||
RefIdent(SPair(id_a.symbol(), S4), None), // ____/ \
|
||||
RefIdent(SPair(id_b.symbol(), S5), None), // ---. \ a->b->a
|
||||
ExprEnd(S6), // ) ) cycle
|
||||
// / /
|
||||
ExprStart(ExprOp::Sum, S7), // / /
|
||||
BindIdent(id_b), // <' /
|
||||
RefIdent(SPair(id_a.symbol(), S9), None), // ----'
|
||||
ExprEnd(S10),
|
||||
PkgEnd(S11),
|
||||
];
|
||||
|
|
|
@ -149,13 +149,13 @@ impl ParseState for NirToAir {
|
|||
Transition(PredPartial(ospan, on)).incomplete()
|
||||
}
|
||||
(PredPartial(ospan, on), Ref(value)) => {
|
||||
stack.push(Air::RefIdent(value));
|
||||
stack.push(Air::RefIdent(on));
|
||||
stack.push(Air::RefIdent(value, None));
|
||||
stack.push(Air::RefIdent(on, None));
|
||||
Transition(Ready).ok(Air::ExprStart(ExprOp::Eq, ospan))
|
||||
}
|
||||
(PredPartial(ospan, on), Close(Match, cspan)) => {
|
||||
stack.push(Air::RefIdent(SPair(SYM_TRUE, ospan)));
|
||||
stack.push(Air::RefIdent(on));
|
||||
stack.push(Air::RefIdent(SPair(SYM_TRUE, ospan), None));
|
||||
stack.push(Air::RefIdent(on, None));
|
||||
Transition(Ready)
|
||||
.ok(Air::ExprStart(ExprOp::Eq, ospan))
|
||||
.with_lookahead(Close(Match, cspan))
|
||||
|
@ -248,7 +248,7 @@ impl ParseState for NirToAir {
|
|||
Transition(st).ok(Air::BindIdent(spair))
|
||||
}
|
||||
(Ready, Ref(spair) | RefSubject(spair)) => {
|
||||
Transition(Ready).ok(Air::RefIdent(spair))
|
||||
Transition(Ready).ok(Air::RefIdent(spair, None))
|
||||
}
|
||||
|
||||
(Ready, Desc(clause)) => {
|
||||
|
|
|
@ -188,7 +188,7 @@ fn apply_template_long_form_nullary() {
|
|||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::TplStart(S1)),
|
||||
O(Air::RefIdent(name)),
|
||||
O(Air::RefIdent(name, None)),
|
||||
O(Air::TplEndRef(S3)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
|
@ -224,7 +224,7 @@ fn apply_template_long_form_args() {
|
|||
#[rustfmt::skip]
|
||||
Ok(vec![
|
||||
O(Air::TplStart(S1)),
|
||||
O(Air::RefIdent(name)),
|
||||
O(Air::RefIdent(name, None)),
|
||||
|
||||
O(Air::TplMetaStart(S3)),
|
||||
O(Air::BindIdent(p1)),
|
||||
|
@ -267,8 +267,8 @@ fn match_short_no_value() {
|
|||
// Once closing,
|
||||
// we default to an equality check against `TRUE`.
|
||||
O(Air::ExprStart(ExprOp::Eq, S1)),
|
||||
O(Air::RefIdent(name)),
|
||||
O(Air::RefIdent(SPair(SYM_TRUE, S1))),
|
||||
O(Air::RefIdent(name, None)),
|
||||
O(Air::RefIdent(SPair(SYM_TRUE, S1), None)),
|
||||
O(Air::ExprEnd(S3)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
|
@ -297,10 +297,10 @@ fn match_short_with_value() {
|
|||
Incomplete,
|
||||
Incomplete,
|
||||
O(Air::ExprStart(ExprOp::Eq, S1)),
|
||||
O(Air::RefIdent(name)),
|
||||
O(Air::RefIdent(name, None)),
|
||||
// Rather than defaulting to `SYM_TRUE` as above,
|
||||
// we use the _user-provided_ value.
|
||||
O(Air::RefIdent(value)),
|
||||
O(Air::RefIdent(value, None)),
|
||||
O(Air::ExprEnd(S4)),
|
||||
]),
|
||||
Sut::parse(toks.into_iter()).collect(),
|
||||
|
@ -338,8 +338,8 @@ fn match_short_value_before_subject_err() {
|
|||
// because no value has been provided
|
||||
// (rather the value was consumed in the error).
|
||||
Ok(O(Air::ExprStart(ExprOp::Eq, S1))),
|
||||
Ok(O(Air::RefIdent(name))),
|
||||
Ok(O(Air::RefIdent(SPair(SYM_TRUE, S1)))),
|
||||
Ok(O(Air::RefIdent(name, None))),
|
||||
Ok(O(Air::RefIdent(SPair(SYM_TRUE, S1), None))),
|
||||
Ok(O(Air::ExprEnd(S3))),
|
||||
],
|
||||
Sut::parse(toks.into_iter()).collect::<Vec<Result<_, _>>>(),
|
||||
|
|
Loading…
Reference in New Issue