#[warn(missing_docs)]
use crate::{
crate_prelude::*,
hir::{self, HirNode},
port_list::AsPortedNode,
resolver::InstTarget,
Context, ParamEnv, ParamEnvData, ParamEnvSource, PortMapping,
};
use std::sync::Arc;
#[derive(Debug)]
pub struct InstDetails<'a> {
pub hir: &'a hir::Inst<'a>,
pub target: Arc<InstTargetDetails<'a>>,
pub ports: Arc<PortMapping<'a>>,
pub inner_env: ParamEnv,
}
#[derive(Debug)]
pub struct InstTargetDetails<'a> {
pub hir: &'a hir::InstTarget<'a>,
pub kind: InstTarget<'a>,
pub outer_env: ParamEnv,
pub inner_env: ParamEnv,
pub params: &'a ParamEnvData<'a>,
}
#[moore_derive::query]
pub(crate) fn inst_details<'a>(
cx: &impl Context<'a>,
Ref(inst): Ref<'a, hir::Inst<'a>>,
env: ParamEnv,
) -> Result<Arc<InstDetails<'a>>> {
let inst_target = match cx.hir_of(inst.target)? {
HirNode::InstTarget(x) => x,
_ => unreachable!(),
};
let target = cx.inst_target_details(Ref(inst_target), env)?;
let port_mapping = cx.port_mapping(
target.kind.as_any().as_all().get_ported().unwrap(),
target.outer_env,
target.inner_env,
Ref(inst),
&inst.pos_ports,
&inst.named_ports,
inst.has_wildcard_port,
)?;
trace!("Deriving additional parametrization due to interfaces");
let mut intf_params = vec![];
for &(ext_port, assigned) in port_mapping.0.iter() {
let port_list = cx.canonicalize_ports(ext_port.node);
let int_port = match ext_port.exprs.as_slice() {
&[ref expr] if expr.selects.is_empty() => &port_list.int[expr.port],
_ => continue,
};
let data = match int_port.data {
Some(ref x) => x,
None => continue,
};
let ty = cx.packed_type_from_ast(Ref(data.ty), target.inner_env, None);
if ty.get_interface().is_none() {
continue;
}
trace!(
" - Adding indirect {:?} for interface `{}` port `{}`",
assigned,
ty,
int_port.name
);
intf_params.push((int_port.id, assigned));
}
let inner_env = if !intf_params.is_empty() {
let mut params = target.params.clone();
params.add_interfaces(intf_params);
trace!(
"Extended parametrization with implicit interface parameters: {:?}",
params
);
cx.intern_param_env(params)
} else {
target.inner_env
};
Ok(Arc::new(InstDetails {
hir: inst,
target: target,
ports: port_mapping,
inner_env,
}))
}
#[moore_derive::query]
pub(crate) fn inst_target_details<'a>(
cx: &impl Context<'a>,
Ref(inst_target): Ref<'a, hir::InstTarget<'a>>,
env: ParamEnv,
) -> Result<Arc<InstTargetDetails<'a>>> {
let target = cx.resolve_inst_target(inst_target.ast)?;
let inst_env = cx.param_env(match target {
resolver::InstTarget::Module(node) => ParamEnvSource::ModuleInst {
module: Ref(cx.hir_of_module(node)?),
env,
pos: &inst_target.pos_params,
named: &inst_target.named_params,
},
resolver::InstTarget::Interface(node) => ParamEnvSource::InterfaceInst {
interface: Ref(cx.hir_of_interface(node)?),
env,
pos: &inst_target.pos_params,
named: &inst_target.named_params,
},
})?;
let inst_env_data = cx.param_env_data(inst_env);
Ok(Arc::new(InstTargetDetails {
hir: inst_target,
kind: target,
outer_env: env,
inner_env: inst_env,
params: inst_env_data,
}))
}
pub struct InstVerbosityVisitor<'a, 'gcx> {
cx: &'a GlobalContext<'gcx>,
env: ParamEnv,
}
impl<'a, 'gcx> InstVerbosityVisitor<'a, 'gcx> {
pub fn new(cx: &'a GlobalContext<'gcx>) -> Self {
Self {
cx,
env: cx.default_param_env(),
}
}
}
impl<'a, 'gcx> hir::Visitor<'gcx> for InstVerbosityVisitor<'a, 'gcx> {
type Context = GlobalContext<'gcx>;
fn context(&self) -> &Self::Context {
self.cx
}
fn visit_inst(&mut self, hir: &'gcx hir::Inst<'gcx>) {
let details = match self.cx.inst_details(Ref(hir), self.env) {
Ok(x) => x,
Err(()) => return,
};
self.cx.emit(
DiagBuilder2::note("instantiation details")
.span(hir.name.span)
.add_note(format!("{:#?}", details)),
);
Self {
cx: self.cx,
env: details.inner_env,
}
.visit_node_with_id(details.target.kind.as_any().id(), false);
}
}