diff --git a/schala-lang/language/src/symbol_table/mod.rs b/schala-lang/language/src/symbol_table/mod.rs index 7d83fa1..c801c17 100644 --- a/schala-lang/language/src/symbol_table/mod.rs +++ b/schala-lang/language/src/symbol_table/mod.rs @@ -1,4 +1,4 @@ -use std::collections::{hash_map::Entry, HashMap}; +use std::collections::{hash_map::Entry, HashMap, HashSet}; use std::fmt; use std::rc::Rc; @@ -85,6 +85,10 @@ pub enum SymbolError { prev_name: Fqsn, location: Location, }, + DuplicateVariant { + type_fqsn: Fqsn, + name: String, + }, DuplicateRecord { type_name: Fqsn, location: Location, @@ -486,6 +490,30 @@ impl<'a> SymbolTableRunner<'a> { location: Location, scope_stack: &mut Vec, ) -> Vec { + + let type_fqsn = Fqsn::from_scope_stack(scope_stack, type_name.name.clone()); + + let TypeBody(variants) = type_body; + let mut duplicates = HashSet::new(); + let mut dup_errors = vec![]; + + for variant in variants { + if duplicates.contains(&variant.name) { + dup_errors.push(SymbolError::DuplicateVariant { + type_fqsn: type_fqsn.clone(), + name: variant.name.as_ref().to_string() + }) + } + duplicates.insert(variant.name.clone()); + } + + if !dup_errors.is_empty() { + return dup_errors; + } + + + + let mut member_errors = vec![]; let mut errors = vec![]; @@ -501,7 +529,6 @@ impl<'a> SymbolTableRunner<'a> { }; }; - let TypeBody(variants) = type_body; let new_scope = Scope::Name(type_name.name.clone()); scope_stack.push(new_scope); diff --git a/schala-lang/language/src/symbol_table/test.rs b/schala-lang/language/src/symbol_table/test.rs index d25c005..63aed0b 100644 --- a/schala-lang/language/src/symbol_table/test.rs +++ b/schala-lang/language/src/symbol_table/test.rs @@ -89,6 +89,23 @@ fn no_type_definition_duplicates() { } } +#[test] +fn no_variant_duplicates() { + let source = r#" +type Panda = FoolsGold | Kappa(i32) | Remix | Kappa | Thursday | Remix +"#; + let (_, output) = add_symbols(source); + let errs = output.unwrap_err(); + assert_eq!(errs.len(), 2); + assert_matches!(&errs[0], SymbolError::DuplicateVariant { + type_fqsn, name } if *type_fqsn == Fqsn::from_strs(&["Panda"]) && + name == "Kappa"); + + assert_matches!(&errs[1], SymbolError::DuplicateVariant { + type_fqsn, name } if *type_fqsn == Fqsn::from_strs(&["Panda"]) && + name == "Remix"); +} + #[test] fn no_variable_definition_duplicates_in_function() { let source = r#"