Files
core/rust/src/compiler/check/failure/collection.rs
T
2026-11-03 03:32:07 +00:00

195 lines
7.8 KiB
Rust

//! 推导完整遍历、提前停止及归约中的失败处理义务。
//! 未知长度归约合并初始与迭代摘要直到稳定,保留空输入的可能性。
use super::{State, flow};
use crate::compiler::model::*;
use crate::syntax::diagnostic::Diagnostic;
use std::collections::{BTreeMap, BTreeSet};
impl State<'_> {
pub(super) fn collection(&mut self, collection: &Collection) -> Result<Flow, Diagnostic> {
if collection
.sequence
.value_type
.database_stream(self.definitions)
&& let Some(definition) = self.database_error
{
let Shape::Choice(variants) = &self.definitions[definition].shape else {
unreachable!()
};
self.failures
.extend((0..variants.len()).map(|variant| Failure {
definition,
variant,
}));
}
let sequence = self.expression(&collection.sequence)?;
if let Some(limit) = &collection.limit {
self.expression(limit)?;
}
let extra = collection
.extra
.as_ref()
.map(|value| self.expression(value))
.transpose()?;
let signature = &self.signatures[collection.handler];
self.failures.extend(&signature.failures);
let before = self.pending.clone();
// Stream 的失败元素尚未产生;只在实际消费合同中引入义务,关闭不等于丢弃已读错误。
let shape =
if let Type::Stream(item) | Type::AsyncStream(item) = &collection.sequence.value_type {
match &sequence.sequence {
// 转发流可能没有现存错误 token,但未来拉取仍会产生错误义务。
Some(Sequence::Unknown(value)) if value.tokens.is_empty() => {
Sequence::Unknown(Box::new(self.unknown(item, 0)?))
}
Some(sequence) => sequence.clone(),
None => Sequence::Unknown(Box::new(self.unknown(item, 0)?)),
}
} else {
sequence
.sequence
.clone()
.unwrap_or_else(|| Sequence::Unknown(Box::default()))
};
let mut produced = Vec::new();
let mut state = extra.clone().unwrap_or_default();
let mut fresh = BTreeMap::new();
match &shape {
Sequence::Known(items) => {
for item in items {
self.budget(0)?;
let value =
self.apply_handler(collection, item, &state, &mut BTreeMap::new())?;
if collection.operation.reduction() {
state = value;
produced.push(state.clone());
} else {
produced.push(value);
}
}
}
Sequence::Unknown(item) => {
if collection.operation.reduction() {
// 初始状态参与合并,因为未知集合可以完全不执行 handler。
loop {
self.budget(0)?;
let value = self.apply_handler(collection, item, &state, &mut fresh)?;
let previous = state.clone();
state.merge(&value);
if previous == state {
break;
}
}
produced.push(state.clone());
} else {
produced.push(self.apply_handler(collection, item, &state, &mut fresh)?);
}
}
}
let empty = matches!(&shape, Sequence::Known(items) if items.is_empty());
let nonempty = matches!(&shape, Sequence::Known(items) if !items.is_empty());
let partial = matches!(
collection.operation,
Operation::Find | Operation::ReduceUntil
);
self.pending = before;
// 提前结束只保证访问首项,不能用选中的输出消费剩余元素的义务。
if partial {
if let Sequence::Known(items) = &shape
&& let Some(first) = items.first()
{
self.pending.retain(|token| !first.tokens.contains(token));
}
} else {
self.pending
.retain(|token| !sequence.tokens.contains(token));
}
if let Some(extra) = &extra
&& (nonempty || collection.operation.reduction())
{
self.pending.retain(|token| !extra.tokens.contains(token));
}
let mut output = match collection.operation {
Operation::ParallelEach => Flow::default(),
Operation::Each if signature.outputs.is_empty() => Flow::default(),
Operation::Each => Flow::sequence(match shape {
Sequence::Known(_) => Sequence::Known(produced),
Sequence::Unknown(_) => Sequence::Unknown(Box::new(produced.pop().unwrap())),
}),
Operation::Filter if empty => Flow::sequence(Sequence::Known(Vec::new())),
Operation::Filter => Flow::sequence(Sequence::Unknown(Box::new(shape.element()))),
Operation::Find => {
let item = if empty {
return Ok(Flow::variants([(0, Flow::default())]));
} else if matches!(&shape, Sequence::Known(items) if items.len() == 1) {
shape.element()
} else {
self.unknown(&signature.inputs[0].1, 0)?
};
Flow::variants([(0, Flow::default()), (1, item)])
}
Operation::Sum => Flow::default(),
Operation::Reduce => state,
Operation::ReduceUntil => {
if let Some((first, rest)) = produced.split_first() {
let mut output = first.clone();
for value in rest {
output.merge(value);
}
output
} else {
state
}
}
};
let retained: BTreeSet<_> = self.pending.intersection(&output.tokens).copied().collect();
if !retained.is_empty() {
let mut mapping = BTreeMap::new();
for token in &output.tokens {
let target = if retained.contains(token) {
self.token()?
} else {
*token
};
mapping.insert(*token, BTreeSet::from([target]));
}
output = self.instantiate(&output, &mut mapping, 0)?;
}
self.pending.extend(&output.tokens);
self.closed_streams.extend(sequence.streams);
self.refresh_streams(&mut output);
Ok(output)
}
fn apply_handler(
&mut self,
collection: &Collection,
item: &Flow,
extra: &Flow,
fresh: &mut BTreeMap<usize, BTreeSet<usize>>,
) -> Result<Flow, Diagnostic> {
let signature = &self.signatures[collection.handler];
let mut mapping = fresh.clone();
for template in &signature.input_flows {
for token in &template.tokens {
mapping.remove(token);
}
}
for (template, actual) in signature.input_flows.iter().zip([item, extra]) {
flow::bind(template, actual, &mut mapping);
}
let output = if let Some(value) = &signature.returns {
self.instantiate(value, &mut mapping, 0)?
} else {
Flow::default()
};
*fresh = mapping;
if collection.operation == Operation::ReduceUntil {
Ok(output.fields.get(&0).cloned().unwrap_or_default())
} else {
Ok(output)
}
}
}