Track duplicate record definitions
This commit is contained in:
parent
15a08aa8f7
commit
a9b8fdcad6
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
);
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user