diff --git a/tests/programs/specializations.vi b/tests/programs/specializations.vi new file mode 100644 index 0000000..cc4e051 --- /dev/null +++ b/tests/programs/specializations.vi @@ -0,0 +1,10 @@ + +use std::tuple::Pair; + +pub fn main(&io: &IO) { + io.println([1, 2, 3, 4].to_string[; N32::to_string]()); + io.println(["abc", "def", "ghi"].to_string[; String::to_string]()); + io.println(['x', 'y', 'z'].to_string[; Char::to_string]()); + io.println([true, false].to_string[; Bool::to_string]()); + io.println([(1, 'a'), (2, 'b')].to_string[; Pair::to_string[; N32::to_string, Char::to_string]]()); +} diff --git a/vine/examples/sub_min.vi b/vine/examples/sub_min.vi index 17b7ca2..37e4abb 100644 --- a/vine/examples/sub_min.vi +++ b/vine/examples/sub_min.vi @@ -2,7 +2,7 @@ pub fn main(&io: &IO) { let list = [4, 3, 7, 9]; sub_min(&list); - io.println(list.to_string[;N32::to_string]()); + io.println(list.to_string[; N32::to_string]()); } pub fn sub_min(&list: &List[N32]) { diff --git a/vine/src/checker/typeof_def.rs b/vine/src/checker/typeof_def.rs index d60991c..63099af 100644 --- a/vine/src/checker/typeof_def.rs +++ b/vine/src/checker/typeof_def.rs @@ -141,7 +141,6 @@ impl<'core> Checker<'core, '_> { if path.generics.as_ref().is_some_and(|g| !g.impls.is_empty()) { self.core.report(Diag::UnexpectedImplArgs { span }); } - // dbg!(&path); let def_id = path.path.resolved.unwrap(); let def = &self.resolver.defs[def_id]; let Some(type_def) = &def.type_def else { diff --git a/vine/src/emitter.rs b/vine/src/emitter.rs index 9a9e816..4969d6b 100644 --- a/vine/src/emitter.rs +++ b/vine/src/emitter.rs @@ -309,8 +309,9 @@ impl<'core, 'a> VirEmitter<'core, 'a> { Port::Wire(w) => Tree::Var(format!("w{}", wire_offset + w.0)), Port::Const(def) => Tree::Global(resolver.defs[*def].canonical.to_string()), Port::Rel(rel) => { - let (def, spec) = spec.rels[*rel]; - Tree::Global(format!("{}::{}", resolver.defs[def].canonical, spec.0)) + let (def, spec, singular) = spec.rels[*rel]; + let path = &resolver.defs[def].canonical; + Tree::Global(if singular { path.to_string() } else { format!("{}::{}", path, spec.0) }) } } } diff --git a/vine/src/resolver/resolve_defs.rs b/vine/src/resolver/resolve_defs.rs index 377093f..ff62c08 100644 --- a/vine/src/resolver/resolve_defs.rs +++ b/vine/src/resolver/resolve_defs.rs @@ -368,7 +368,7 @@ impl<'core> VisitMut<'core, '_> for ResolveVisitor<'core, '_> { self._visit_type(ty); } - fn _visit_impl(&mut self, impl_: &mut Impl<'core>) { + fn visit_impl(&mut self, impl_: &mut Impl<'core>) { if let ImplKind::Path(path) = &mut impl_.kind { if path.generics.is_none() { if let Some(ident) = path.path.as_ident() { @@ -383,6 +383,7 @@ impl<'core> VisitMut<'core, '_> for ResolveVisitor<'core, '_> { impl_.kind = ImplKind::Error(self.resolver.core.report(diag)); } } + self._visit_impl(impl_); } } diff --git a/vine/src/specializer.rs b/vine/src/specializer.rs index c7366e8..6e02303 100644 --- a/vine/src/specializer.rs +++ b/vine/src/specializer.rs @@ -28,18 +28,15 @@ impl<'core, 'a> Specializer<'core, 'a> { fn initialize(&mut self) { for def_id in self.resolver.defs.keys() { let def = &mut self.resolver.defs[def_id]; - let def_info = if let Some(mut value) = def.value_def.take() { - let impl_params = value.impl_params.len(); + let def_info = if let Some(mut value_def) = def.value_def.take() { + let impl_params = value_def.impl_params.len(); let mut extractor = RelExtractor { rels: IdxVec::new(), resolver: self.resolver }; - if let ValueDefKind::Expr(expr) = &mut value.kind { + if let ValueDefKind::Expr(expr) = &mut value_def.kind { extractor.visit_expr(expr); } - DefInfo { - impl_params, - rels: extractor.rels, - specs_lookup: HashMap::new(), - specs: IdxVec::new(), - } + let rels = extractor.rels; + self.resolver.defs[def_id].value_def = Some(value_def); + DefInfo { impl_params, rels, specs_lookup: HashMap::new(), specs: IdxVec::new() } } else { DefInfo::default() }; @@ -68,11 +65,10 @@ impl<'core, 'a> Specializer<'core, 'a> { let mut spec = Spec::default(); for rel_id in def.rels.keys() { let rel = &self.defs[def_id].rels[rel_id]; - spec.rels.push(match rel { - Rel::Def(rel_def_id, impls) => ( - *rel_def_id, - self.specialize(*rel_def_id, impls.iter().map(|x| instantiate(x, &impl_args)).collect()), - ), + let (rel_def_id, rel_impl_args) = match rel { + Rel::Def(rel_def_id, impls) => { + (*rel_def_id, impls.iter().map(|x| instantiate(x, &impl_args)).collect()) + } Rel::Subitem(impl_, name) => { let impl_ = instantiate(impl_, &impl_args); let subitem_id = self.resolver.defs[impl_.0] @@ -84,9 +80,12 @@ impl<'core, 'a> Specializer<'core, 'a> { .find(|(_, n, _)| n == name) .unwrap() .2; - (subitem_id, self.specialize(subitem_id, impl_.1)) + (subitem_id, impl_.1) } - }); + }; + let singular = rel_impl_args.is_empty(); + let rel_spec_id = self.specialize(rel_def_id, rel_impl_args); + spec.rels.push((rel_def_id, rel_spec_id, singular)); } self.defs[def_id].specs[spec_id] = Some(spec); spec_id @@ -117,6 +116,7 @@ impl<'core> VisitMut<'core, '_> for RelExtractor<'core, '_> { } } } + self._visit_expr(expr); } } @@ -135,7 +135,7 @@ new_idx!(pub ImplId); #[derive(Debug, Default)] pub struct Spec { pub singular: bool, - pub rels: IdxVec, + pub rels: IdxVec, } #[derive(Debug, Clone, PartialEq, Eq, Hash)]