From a179e1042fc5d5fe3dd5399344b61e96dcb39a2d Mon Sep 17 00:00:00 2001 From: imaqtkatt Date: Mon, 4 Mar 2024 09:05:32 -0300 Subject: [PATCH 1/3] Allow constructors share names with data types --- src/term/check/shared_names.rs | 63 ++++++++++++++++--- src/term/parser/parser.rs | 8 +-- .../compile_file/error_messages.hvm | 1 + .../compile_file__error_messages.hvm.snap | 9 +-- 4 files changed, 62 insertions(+), 19 deletions(-) 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) From 1f1f281133046c967d9d559ae8beb20c85416161 Mon Sep 17 00:00:00 2001 From: imaqtkatt Date: Mon, 4 Mar 2024 09:18:31 -0300 Subject: [PATCH 2/3] Update shared_names comments --- src/term/check/shared_names.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/term/check/shared_names.rs b/src/term/check/shared_names.rs index bffb1f9a7..0b2c7e958 100644 --- a/src/term/check/shared_names.rs +++ b/src/term/check/shared_names.rs @@ -17,6 +17,8 @@ impl Display for TopLevelErr { } impl Ctx<'_> { + /// Checks if exists shared names from definitions, adts and constructors, allowing constructors + /// share the adt name once. pub fn check_shared_names(&mut self) { let mut checked = IndexMap::<&Name, NameInfo>::new(); @@ -62,9 +64,9 @@ impl NameInfo { impl NameInfo { fn with_ctr(&mut self, current_name: &Name, info: &mut diagnostics::Info) { match self.kind { - NameKind::Adt => {} // Catch by the parser + NameKind::Adt => {} // Error caught by the parser NameKind::Def => info.error(TopLevelErr(current_name.clone())), - NameKind::Ctr => {} // Catch by the parser + NameKind::Ctr => {} // Error caught by the parser } } From e39c66fbbfa5d594dbbe9d73492b66e6ade5909b Mon Sep 17 00:00:00 2001 From: imaqtkatt Date: Mon, 4 Mar 2024 10:29:57 -0300 Subject: [PATCH 3/3] Add duplicated data with defname test --- tests/golden_tests/compile_file/error_data_def_name.hvm | 4 ++++ tests/snapshots/compile_file__error_data_def_name.hvm.snap | 5 +++++ 2 files changed, 9 insertions(+) create mode 100644 tests/golden_tests/compile_file/error_data_def_name.hvm create mode 100644 tests/snapshots/compile_file__error_data_def_name.hvm.snap diff --git a/tests/golden_tests/compile_file/error_data_def_name.hvm b/tests/golden_tests/compile_file/error_data_def_name.hvm new file mode 100644 index 000000000..00d636daf --- /dev/null +++ b/tests/golden_tests/compile_file/error_data_def_name.hvm @@ -0,0 +1,4 @@ +data A = A +A = 0 + +main = A diff --git a/tests/snapshots/compile_file__error_data_def_name.hvm.snap b/tests/snapshots/compile_file__error_data_def_name.hvm.snap new file mode 100644 index 000000000..6cb6428d2 --- /dev/null +++ b/tests/snapshots/compile_file__error_data_def_name.hvm.snap @@ -0,0 +1,5 @@ +--- +source: tests/golden_tests.rs +input_file: tests/golden_tests/compile_file/error_data_def_name.hvm +--- +Duplicated top-level name 'A'.