Track duplicate record definitions

This commit is contained in:
Greg Shuflin 2021-10-19 20:35:53 -07:00
parent 15a08aa8f7
commit a9b8fdcad6
2 changed files with 50 additions and 21 deletions

View File

@ -1,5 +1,4 @@
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, hash_map::Entry};
use std::rc::Rc;
use std::fmt;
@ -58,6 +57,11 @@ pub enum SymbolError {
DuplicateName {
prev_name: FQSN,
location: Location
},
DuplicateRecord {
type_name: FQSN,
location: Location,
member: String,
}
}
@ -301,6 +305,7 @@ impl SymbolTable {
}
fn add_type_members(&mut self, type_name: &TypeSingletonName, type_body: &TypeBody, _mutable: &bool, location: Location, scope_stack: &mut Vec<Scope>) -> Vec<SymbolError> {
let mut member_errors = vec![];
let mut errors = vec![];
let mut register = |fqsn: FQSN, spec: SymbolSpec| {
@ -343,6 +348,23 @@ impl SymbolTable {
},
Variant::Record { name, members } => {
let fq_name = FQSN::from_scope_stack(scope_stack.as_ref(), name.clone());
let mut seen_members = HashMap::new();
for (member_name, _) in members.iter() {
match seen_members.entry(member_name.as_ref()) {
Entry::Occupied(o) => {
let location = *o.get();
member_errors.push(SymbolError::DuplicateRecord {
type_name: fq_name.clone(),
location,
member: member_name.as_ref().to_string(),
});
},
//TODO eventually this should track meaningful locations
Entry::Vacant(v) => { v.insert(Location::default()); }
}
}
let spec = SymbolSpec::RecordConstructor {
index,
type_name: name.clone(),
@ -350,30 +372,12 @@ impl SymbolTable {
.map(|(_, _)| (Rc::new("DUMMY_FIELD".to_string()), Rc::new("DUMMY_TYPE_ID".to_string()))).collect()
};
register(fq_name, spec);
//TODO check for duplicates among struct member definitions
/*
let mut duplicate_member_definitions = Vec::new();
for (member_name, member_type) in defined_members {
match members.entry(member_name.clone()) {
Entry::Occupied(_) => duplicate_member_definitions.push(member_name.clone()),
Entry::Vacant(v) => {
v.insert(match member_type {
TypeIdentifier::Singleton(TypeSingletonName { name, ..}) => name.clone(),
TypeIdentifier::Tuple(_) => unimplemented!(),
});
}
}
}
if duplicate_member_definitions.len() != 0 {
return Err(format!("Duplicate member(s) in definition of type {}: {:?}", type_name, duplicate_member_definitions));
}
*/
}
}
}
scope_stack.pop();
errors.extend(member_errors.into_iter());
errors
}
}

View File

@ -206,3 +206,28 @@ fn duplicate_modules() {
);
}
#[test]
fn duplicate_struct_members() {
//TODO this is a parser error
/*
let source = r#"
type Tarak = Tarak {
loujet: i32,
mets: i32,
mets: i32,
}
"#;
*/
let source = r#" type Tarak = Tarak { loujet: i32, mets: i32, mets: i32 } "#;
let (_, output) = add_symbols(source);
let errs = output.unwrap_err();
assert_matches!(&errs[..], [
SymbolError::DuplicateRecord {
type_name, member, ..},
] if type_name == &FQSN::from_strs(&["Tarak", "Tarak"]) && member == "mets"
);
}