Skip to content

Commit 1a3d3cc

Browse files
committed
Resolve implicit imports before doing target check.
1 parent 290c100 commit 1a3d3cc

File tree

2 files changed

+107
-83
lines changed

2 files changed

+107
-83
lines changed

crates/wac-graph/src/graph.rs

Lines changed: 102 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,89 @@ impl CompositionGraph {
12591259
generation: entry.generation,
12601260
}
12611261
}
1262+
1263+
/// Yields an iterator over the resolved imports of the graph.
1264+
pub fn imports(&self) -> Result<impl Iterator<Item = (&str, NodeId)>, EncodeError> {
1265+
let import_nodes = self
1266+
.node_ids()
1267+
.filter_map(|n| match &self[n].kind() {
1268+
NodeKind::Import(_) => Some(n),
1269+
_ => None,
1270+
})
1271+
.collect();
1272+
let mut implicit_imports = Default::default();
1273+
let mut explicit_imports = Default::default();
1274+
let _ = self.resolve_imports(import_nodes, &mut implicit_imports, &mut explicit_imports)?;
1275+
1276+
Ok(implicit_imports.into_iter().chain(explicit_imports))
1277+
}
1278+
1279+
/// Resolves the imports (both implicit and explicit) of the given nodes.
1280+
///
1281+
/// Populates hashmaps that map the implicit and explicit import nodes to their import names.
1282+
/// Returns a type aggregator that contains the resolved types of the imports.
1283+
pub fn resolve_imports<'a>(
1284+
&'a self,
1285+
import_nodes: Vec<NodeId>,
1286+
implicit_imports: &mut HashMap<&'a str, NodeId>,
1287+
explicit_imports: &mut HashMap<&'a str, NodeId>,
1288+
) -> Result<TypeAggregator, EncodeError> {
1289+
let mut instantiations = HashMap::new();
1290+
let mut aggregator = TypeAggregator::default();
1291+
let mut cache = Default::default();
1292+
let mut checker = SubtypeChecker::new(&mut cache);
1293+
log::debug!("populating implicit imports");
1294+
for index in self.graph.node_indices() {
1295+
let node = &self.graph[index];
1296+
if !matches!(node.kind, NodeKind::Instantiation(_)) {
1297+
continue;
1298+
}
1299+
1300+
let package = &self[node.package.unwrap()];
1301+
let world = &self.types[package.ty()];
1302+
1303+
let unsatisfied_args = world
1304+
.imports
1305+
.iter()
1306+
.enumerate()
1307+
.filter(|(i, _)| !node.is_arg_satisfied(*i));
1308+
1309+
// Go through the unsatisfied arguments and import them
1310+
for (_, (name, kind)) in unsatisfied_args {
1311+
if let Some(import) = self.imports.get(name).copied() {
1312+
return Err(EncodeError::ImplicitImportConflict {
1313+
import: NodeId(import),
1314+
instantiation: NodeId(index),
1315+
package: PackageKey::new(package),
1316+
name: name.to_string(),
1317+
});
1318+
}
1319+
1320+
instantiations.entry(name).or_insert(index);
1321+
1322+
aggregator = aggregator
1323+
.aggregate(name, &self.types, *kind, &mut checker)
1324+
.map_err(|e| EncodeError::ImportTypeMergeConflict {
1325+
import: name.clone(),
1326+
first: NodeId(instantiations[&name]),
1327+
second: NodeId(index),
1328+
source: e,
1329+
})?;
1330+
implicit_imports.insert(name, NodeId(index));
1331+
}
1332+
}
1333+
log::debug!("populating explicit imports");
1334+
for n in import_nodes {
1335+
let node = &self.graph[n.0];
1336+
if let NodeKind::Import(name) = &node.kind {
1337+
explicit_imports.insert(name.as_str(), n);
1338+
aggregator = aggregator
1339+
.aggregate(name, self.types(), node.item_kind, &mut checker)
1340+
.unwrap();
1341+
}
1342+
}
1343+
Ok(aggregator)
1344+
}
12621345
}
12631346

12641347
impl Index<NodeId> for CompositionGraph {
@@ -1382,8 +1465,9 @@ impl<'a> CompositionGraphEncoder<'a> {
13821465
.toposort()
13831466
.map_err(|n| EncodeError::GraphContainsCycle { node: NodeId(n) })?
13841467
.into_iter()
1468+
.map(NodeId)
13851469
.partition::<Vec<_>, _>(|index| {
1386-
let node = &self.0.graph[*index];
1470+
let node = &self.0.graph[index.0];
13871471
matches!(node.kind, NodeKind::Import(_))
13881472
});
13891473

@@ -1392,16 +1476,16 @@ impl<'a> CompositionGraphEncoder<'a> {
13921476

13931477
// Encode non-import nodes in the graph in topographical order
13941478
for n in other_nodes {
1395-
let node = &self.0.graph[n];
1479+
let node = &self.0.graph[n.0];
13961480
let index = match &node.kind {
13971481
NodeKind::Definition => self.definition(&mut state, node),
1398-
NodeKind::Instantiation(_) => self.instantiation(&mut state, n, node, options),
1399-
NodeKind::Alias => self.alias(&mut state, n),
1482+
NodeKind::Instantiation(_) => self.instantiation(&mut state, n.0, node, options),
1483+
NodeKind::Alias => self.alias(&mut state, n.0),
14001484
// `other_nodes` does not contain any import nodes
14011485
NodeKind::Import(_) => unreachable!(),
14021486
};
14031487

1404-
let prev = state.node_indexes.insert(n, index);
1488+
let prev = state.node_indexes.insert(n.0, index);
14051489
assert!(prev.is_none());
14061490
}
14071491

@@ -1489,73 +1573,20 @@ impl<'a> CompositionGraphEncoder<'a> {
14891573
}
14901574

14911575
/// Encode both implicit and explicit imports.
1576+
///
1577+
/// `import_nodes` are expected to only be `NodeKind::Import` nodes.
14921578
fn encode_imports(
14931579
&self,
14941580
state: &mut State,
1495-
import_nodes: Vec<NodeIndex>,
1581+
import_nodes: Vec<NodeId>,
14961582
) -> Result<(), EncodeError> {
1497-
let mut aggregator = TypeAggregator::default();
1498-
let mut instantiations = HashMap::new();
1499-
let mut arguments = Vec::new();
1500-
let mut encoded = HashMap::new();
1501-
let mut cache = Default::default();
1502-
let mut checker = SubtypeChecker::new(&mut cache);
15031583
let mut explicit_imports = HashMap::new();
1584+
let mut implicit_imports = HashMap::new();
1585+
let aggregator =
1586+
self.0
1587+
.resolve_imports(import_nodes, &mut implicit_imports, &mut explicit_imports)?;
15041588

1505-
log::debug!("populating implicit imports");
1506-
1507-
// Enumerate the instantiation nodes and populate the import types
1508-
for index in self.0.graph.node_indices() {
1509-
let node = &self.0.graph[index];
1510-
if !matches!(node.kind, NodeKind::Instantiation(_)) {
1511-
continue;
1512-
}
1513-
1514-
let package = &self.0[node.package.unwrap()];
1515-
let world = &self.0.types[package.ty()];
1516-
1517-
let unsatisfied_args = world
1518-
.imports
1519-
.iter()
1520-
.enumerate()
1521-
.filter(|(i, _)| !node.is_arg_satisfied(*i));
1522-
1523-
// Go through the unsatisfied arguments and import them
1524-
for (_, (name, kind)) in unsatisfied_args {
1525-
if let Some(import) = self.0.imports.get(name).copied() {
1526-
return Err(EncodeError::ImplicitImportConflict {
1527-
import: NodeId(import),
1528-
instantiation: NodeId(index),
1529-
package: PackageKey::new(package),
1530-
name: name.to_string(),
1531-
});
1532-
}
1533-
1534-
instantiations.entry(name).or_insert(index);
1535-
1536-
aggregator = aggregator
1537-
.aggregate(name, &self.0.types, *kind, &mut checker)
1538-
.map_err(|e| EncodeError::ImportTypeMergeConflict {
1539-
import: name.clone(),
1540-
first: NodeId(instantiations[&name]),
1541-
second: NodeId(index),
1542-
source: e,
1543-
})?;
1544-
arguments.push((index, name));
1545-
}
1546-
}
1547-
1548-
log::debug!("populating explicit imports");
1549-
1550-
for n in import_nodes {
1551-
let node = &self.0.graph[n];
1552-
if let NodeKind::Import(name) = &node.kind {
1553-
explicit_imports.insert(name.as_str(), n);
1554-
aggregator = aggregator
1555-
.aggregate(name, self.0.types(), node.item_kind, &mut checker)
1556-
.unwrap();
1557-
}
1558-
}
1589+
let mut encoded = HashMap::new();
15591590

15601591
// Next encode the imports
15611592
for (name, kind) in aggregator.imports() {
@@ -1565,19 +1596,19 @@ impl<'a> CompositionGraphEncoder<'a> {
15651596
}
15661597

15671598
// Populate the implicit argument map
1568-
for (node, name) in arguments {
1569-
let (kind, index) = encoded[name.as_str()];
1599+
for (name, node) in implicit_imports {
1600+
let (kind, index) = encoded[name];
15701601
state
15711602
.implicit_args
1572-
.entry(node)
1603+
.entry(node.0)
15731604
.or_default()
1574-
.push((name.clone(), kind, index));
1605+
.push((name.to_owned(), kind, index));
15751606
}
15761607

15771608
// Finally, populate the node indexes with the encoded explicit imports
15781609
for (name, node_index) in explicit_imports {
15791610
let (_, encoded_index) = encoded[name];
1580-
state.node_indexes.insert(node_index, encoded_index);
1611+
state.node_indexes.insert(node_index.0, encoded_index);
15811612
}
15821613

15831614
Ok(())

crates/wac-parser/src/resolution.rs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ pub enum Error {
609609
world: String,
610610
/// The span where the error occurred.
611611
#[label(primary, "cannot have an import named `{name}`")]
612-
span: SourceSpan,
612+
span: Option<SourceSpan>,
613613
},
614614
/// Missing an export for the target world.
615615
#[error("target world `{world}` requires an export named `{name}`")]
@@ -2717,21 +2717,14 @@ impl<'a> AstResolver<'a> {
27172717

27182718
// The output is allowed to import a subset of the world's imports
27192719
checker.invert();
2720-
for (name, import) in state
2721-
.graph
2722-
.node_ids()
2723-
.filter_map(|n| match &state.graph[n].kind() {
2724-
NodeKind::Import(name) => Some((name, n)),
2725-
_ => None,
2726-
})
2727-
{
2720+
for (name, import) in state.graph.imports().unwrap() {
27282721
let expected = world
27292722
.imports
27302723
.get(name)
27312724
.ok_or_else(|| Error::ImportNotInTarget {
2732-
name: name.clone(),
2725+
name: name.to_owned(),
27332726
world: path.string.to_owned(),
2734-
span: state.import_spans[&import],
2727+
span: state.import_spans.get(&import).copied(),
27352728
})?;
27362729

27372730
checker
@@ -2743,7 +2736,7 @@ impl<'a> AstResolver<'a> {
27432736
)
27442737
.map_err(|e| Error::TargetMismatch {
27452738
kind: ExternKind::Import,
2746-
name: name.clone(),
2739+
name: name.to_owned(),
27472740
world: path.string.to_owned(),
27482741
span: state.import_spans[&import],
27492742
source: e,

0 commit comments

Comments
 (0)