use yog_ids::script_problem;
use super::Checker;
use super::members::Callee;
use super::model::Type;
use crate::ast::{Arg, Expr};
use crate::source::token::Span;
impl Checker<'_, '_, '_> {
pub(super) fn indexed(&mut self, on: Type, index: &Expr, at: Span) -> Type {
match on {
Type::List(item) => {
self.expr(index);
return *item;
}
Type::Map(_, value) => {
self.expr(index);
return *value;
}
_ => {}
}
let Some(callee) = self.indexer(&on) else {
self.expr(index);
return Type::Unknown;
};
let given = vec![self.expr(index)];
let args = [Arg {
name: None,
pass: None,
value: index.clone(),
}];
self.called(callee, &given, &args, at)
}
pub(super) fn index_written(&mut self, on: &Expr, at: Span) {
let Some(Type::Own(type_name, _)) = self.types.of(on).map(Type::non_null).cloned() else {
return;
};
let indexers: Vec<bool> = self
.own
.lineage(&type_name)
.iter()
.filter_map(|of| self.own.types.get(of))
.flat_map(|t| t.indexers.iter().map(|i| i.settable))
.collect();
if !indexers.is_empty() && !indexers.contains(&true) {
self.report.error(
script_problem::ASSIGN_TO_CONSTANT,
at,
format!(
"`{type_name}`'s indexer has no `set`: its items are read here, never written"
),
);
}
}
fn indexer(&self, on: &Type) -> Option<Callee> {
let Type::Own(type_name, args) = on.non_null() else {
return None;
};
let getters: Vec<_> = self
.own
.lineage(type_name)
.iter()
.filter_map(|of| self.own.types.get(of))
.flat_map(|t| t.indexers.iter().map(|i| i.get.clone()))
.collect();
(!getters.is_empty()).then(|| Callee::Own(getters, self.bound_of(type_name, args)))
}
}