Track duplicate record definitions
This commit is contained in:
parent
15a08aa8f7
commit
a9b8fdcad6
@ -1,5 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, hash_map::Entry};
|
||||||
use std::collections::hash_map::Entry;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
@ -58,6 +57,11 @@ pub enum SymbolError {
|
|||||||
DuplicateName {
|
DuplicateName {
|
||||||
prev_name: FQSN,
|
prev_name: FQSN,
|
||||||
location: Location
|
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> {
|
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 errors = vec![];
|
||||||
|
|
||||||
let mut register = |fqsn: FQSN, spec: SymbolSpec| {
|
let mut register = |fqsn: FQSN, spec: SymbolSpec| {
|
||||||
@ -343,6 +348,23 @@ impl SymbolTable {
|
|||||||
},
|
},
|
||||||
Variant::Record { name, members } => {
|
Variant::Record { name, members } => {
|
||||||
let fq_name = FQSN::from_scope_stack(scope_stack.as_ref(), name.clone());
|
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 {
|
let spec = SymbolSpec::RecordConstructor {
|
||||||
index,
|
index,
|
||||||
type_name: name.clone(),
|
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()
|
.map(|(_, _)| (Rc::new("DUMMY_FIELD".to_string()), Rc::new("DUMMY_TYPE_ID".to_string()))).collect()
|
||||||
};
|
};
|
||||||
register(fq_name, spec);
|
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();
|
scope_stack.pop();
|
||||||
|
errors.extend(member_errors.into_iter());
|
||||||
errors
|
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