diff --git a/src/term/check/shared_names.rs b/src/term/check/shared_names.rs index ac87b7290..bffb1f9a7 100644 --- a/src/term/check/shared_names.rs +++ b/src/term/check/shared_names.rs @@ -2,7 +2,10 @@ use std::fmt::Display; use indexmap::IndexMap; -use crate::term::{Ctx, Name}; +use crate::{ + diagnostics, + term::{Ctx, Name}, +}; #[derive(Debug, Clone)] pub struct TopLevelErr(Name); @@ -14,26 +17,70 @@ impl Display for TopLevelErr { } impl Ctx<'_> { - /// Checks if exists shared names from definitions, adts and constructors. pub fn check_shared_names(&mut self) { - let mut checked = IndexMap::<&Name, usize>::new(); + let mut checked = IndexMap::<&Name, NameInfo>::new(); for adt_name in self.book.adts.keys() { - *checked.entry(adt_name).or_default() += 1; + checked.entry(adt_name).or_insert(NameInfo::new(NameKind::Adt)).with_adt(adt_name, &mut self.info); } for ctr_name in self.book.ctrs.keys() { - *checked.entry(ctr_name).or_default() += 1; + checked.entry(ctr_name).or_insert(NameInfo::new(NameKind::Ctr)).with_ctr(ctr_name, &mut self.info); } for def_name in self.book.defs.keys() { - *checked.entry(def_name).or_default() += 1; + checked.entry(def_name).or_insert(NameInfo::new(NameKind::Def)).with_def(def_name, &mut self.info); } - for (name, n) in checked.into_iter() { - if n > 1 { + for (name, name_info) in checked.into_iter() { + if name_info.count > 1 { self.info.error(TopLevelErr(name.clone())); } } } } + +#[derive(Debug)] +enum NameKind { + Adt, + Def, + Ctr, +} + +#[derive(Debug)] +struct NameInfo { + kind: NameKind, + count: usize, +} + +impl NameInfo { + fn new(kind: NameKind) -> Self { + Self { kind, count: 0 } + } +} + +impl NameInfo { + fn with_ctr(&mut self, current_name: &Name, info: &mut diagnostics::Info) { + match self.kind { + NameKind::Adt => {} // Catch by the parser + NameKind::Def => info.error(TopLevelErr(current_name.clone())), + NameKind::Ctr => {} // Catch by the parser + } + } + + fn with_def(&mut self, current_name: &Name, info: &mut diagnostics::Info) { + match self.kind { + NameKind::Adt => self.count += 1, + NameKind::Def => {} + NameKind::Ctr => info.error(TopLevelErr(current_name.clone())), + } + } + + fn with_adt(&mut self, current_name: &Name, info: &mut diagnostics::Info) { + match self.kind { + NameKind::Adt => self.count += 1, + NameKind::Def => info.error(TopLevelErr(current_name.clone())), + NameKind::Ctr => self.count += 1, + } + } +} diff --git a/src/term/parser/parser.rs b/src/term/parser/parser.rs index 6c728f7cf..389236d37 100644 --- a/src/term/parser/parser.rs +++ b/src/term/parser/parser.rs @@ -14,7 +14,7 @@ use chumsky::{ util::MaybeRef, IterParser, Parser, }; -use indexmap::{map::Entry, IndexMap}; +use indexmap::map::Entry; use logos::{Logos, SpannedIter}; use std::{iter::Map, ops::Range, path::Path}; @@ -521,14 +521,14 @@ fn collect_book( } TopLevel::Adt((nam, nam_span), adt) => match book.adts.get(&nam) { None => { - let (ctrs, spans): (IndexMap<_, _>, Vec<_>) = adt.into_iter().unzip(); + let (ctrs, spans): (Vec<(_, _)>, Vec<_>) = adt.into_iter().unzip(); for ((ctr, _), span) in ctrs.iter().zip(spans.into_iter()) { match book.ctrs.entry(ctr.clone()) { Entry::Vacant(e) => _ = e.insert(nam.clone()), Entry::Occupied(e) => emit.emit(Rich::custom( span, - if book.adts[e.get()].builtin { + if book.adts.get(e.get()).is_some_and(|adt| adt.builtin) { format!("{} is a built-in constructor and should not be overridden.", e.key()) } else { format!("Repeated constructor '{}'", e.key()) @@ -537,7 +537,7 @@ fn collect_book( } } - let adt = Adt { ctrs, builtin }; + let adt = Adt { ctrs: ctrs.into_iter().collect(), builtin }; book.adts.insert(nam.clone(), adt); } Some(adt) => emit.emit(Rich::custom( diff --git a/tests/golden_tests/compile_file/error_messages.hvm b/tests/golden_tests/compile_file/error_messages.hvm index 22a2a83b7..04d9efbeb 100644 --- a/tests/golden_tests/compile_file/error_messages.hvm +++ b/tests/golden_tests/compile_file/error_messages.hvm @@ -1,5 +1,6 @@ data A = (A) data B = (B) +data C = (B) Foo (C) = * Foo (D) = * diff --git a/tests/snapshots/compile_file__error_messages.hvm.snap b/tests/snapshots/compile_file__error_messages.hvm.snap index bd2661e78..a24e2c01d 100644 --- a/tests/snapshots/compile_file__error_messages.hvm.snap +++ b/tests/snapshots/compile_file__error_messages.hvm.snap @@ -2,10 +2,5 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/compile_file/error_messages.hvm --- -Duplicated top-level name 'A'. -Duplicated top-level name 'B'. -In definition 'Foo': - Unbound constructor 'C'. - Unbound constructor 'D'. -In definition 'Foo2': - Unbound constructor 'E'. +At tests/golden_tests/compile_file/error_messages.hvm:3:10: Repeated constructor 'B' + 3 | data C = (B)