2019-10-16 19:51:43 -07:00
|
|
|
#![cfg(test)]
|
2021-10-21 14:46:42 -07:00
|
|
|
use assert_matches::assert_matches;
|
2019-10-16 19:51:43 -07:00
|
|
|
|
2021-10-29 00:28:05 -07:00
|
|
|
use super::*;
|
|
|
|
use crate::{tokenizing::Location, util::quick_ast};
|
|
|
|
|
2021-10-19 19:19:21 -07:00
|
|
|
fn add_symbols(src: &str) -> (SymbolTable, Result<(), Vec<SymbolError>>) {
|
2021-10-21 14:46:42 -07:00
|
|
|
let ast = quick_ast(src);
|
|
|
|
let mut symbol_table = SymbolTable::new();
|
2021-10-29 00:28:05 -07:00
|
|
|
let mut type_context = crate::type_inference::TypeContext::new();
|
2021-10-27 15:39:09 -07:00
|
|
|
let result = symbol_table.process_ast(&ast, &mut type_context);
|
2021-10-21 14:46:42 -07:00
|
|
|
(symbol_table, result)
|
2019-10-23 14:02:27 -07:00
|
|
|
}
|
|
|
|
|
2021-10-19 21:14:15 -07:00
|
|
|
fn make_fqsn(strs: &[&str]) -> Fqsn {
|
2021-10-21 14:46:42 -07:00
|
|
|
Fqsn::from_strs(strs)
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn basic_symbol_table() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let src = "let a = 10; fn b() { 20 }";
|
|
|
|
let (symbols, _) = add_symbols(src);
|
2021-10-18 22:51:36 -07:00
|
|
|
|
2021-10-21 14:46:42 -07:00
|
|
|
fn make_fqsn(strs: &[&str]) -> Fqsn {
|
|
|
|
Fqsn::from_strs(strs)
|
|
|
|
}
|
2021-10-18 22:51:36 -07:00
|
|
|
|
2021-10-21 14:46:42 -07:00
|
|
|
symbols.fq_names.table.get(&make_fqsn(&["b"])).unwrap();
|
|
|
|
|
|
|
|
let src = "type Option<T> = Some(T) | None";
|
|
|
|
let (symbols, _) = add_symbols(src);
|
|
|
|
|
|
|
|
symbols.types.table.get(&make_fqsn(&["Option"])).unwrap();
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-10-24 01:34:13 -07:00
|
|
|
fn no_function_definition_duplicates() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
2019-10-16 19:51:43 -07:00
|
|
|
fn a() { 1 }
|
|
|
|
fn b() { 2 }
|
|
|
|
fn a() { 3 }
|
|
|
|
"#;
|
2021-10-21 14:46:42 -07:00
|
|
|
let (_, output) = add_symbols(source);
|
|
|
|
let errs = output.unwrap_err();
|
|
|
|
assert_matches!(&errs[..], [
|
|
|
|
SymbolError::DuplicateName { prev_name, ..}
|
|
|
|
] if prev_name == &Fqsn::from_strs(&["a"])
|
|
|
|
);
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-10-24 01:34:13 -07:00
|
|
|
fn no_variable_definition_duplicates() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
2019-10-23 14:45:12 -07:00
|
|
|
let x = 9
|
|
|
|
let a = 20
|
|
|
|
let q = 39
|
|
|
|
let a = 30
|
2021-10-19 19:19:21 -07:00
|
|
|
let x = 34
|
2019-10-16 19:51:43 -07:00
|
|
|
"#;
|
2021-10-21 14:46:42 -07:00
|
|
|
let (_, output) = add_symbols(source);
|
|
|
|
let errs = output.unwrap_err();
|
|
|
|
|
|
|
|
assert_matches!(&errs[..], [
|
|
|
|
SymbolError::DuplicateName { prev_name: pn1, ..},
|
|
|
|
SymbolError::DuplicateName { prev_name: pn2, ..}
|
|
|
|
] if pn1 == &Fqsn::from_strs(&["a"]) && pn2 == &Fqsn::from_strs(&["x"])
|
|
|
|
);
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
2021-10-29 00:28:05 -07:00
|
|
|
#[test]
|
|
|
|
fn no_type_definition_duplicates() {
|
|
|
|
let source = r#"
|
|
|
|
let x = 9
|
|
|
|
type Food = Japchae | Burrito | Other
|
|
|
|
type Food = GoodJapchae | Breadfruit
|
|
|
|
"#;
|
|
|
|
let (_, output) = add_symbols(source);
|
|
|
|
let errs = output.unwrap_err();
|
|
|
|
let err = &errs[0];
|
|
|
|
|
|
|
|
match err {
|
|
|
|
SymbolError::DuplicateName { location, prev_name } => {
|
|
|
|
assert_eq!(prev_name, &Fqsn::from_strs(&["Food"]));
|
2021-11-12 01:18:57 -08:00
|
|
|
|
|
|
|
//TODO restore this Location test
|
|
|
|
//assert_eq!(location, &Location { line_num: 2, char_num: 2 });
|
2021-10-29 00:28:05 -07:00
|
|
|
}
|
|
|
|
_ => panic!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-29 00:48:44 -07:00
|
|
|
#[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");
|
|
|
|
}
|
|
|
|
|
2019-10-16 19:51:43 -07:00
|
|
|
#[test]
|
2019-10-24 01:34:13 -07:00
|
|
|
fn no_variable_definition_duplicates_in_function() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
2019-10-16 19:51:43 -07:00
|
|
|
fn a() {
|
|
|
|
let a = 20
|
|
|
|
let b = 40
|
|
|
|
a + b
|
|
|
|
}
|
|
|
|
|
|
|
|
fn q() {
|
2019-10-24 01:34:13 -07:00
|
|
|
let a = 29
|
2019-10-16 19:51:43 -07:00
|
|
|
let x = 30
|
|
|
|
let x = 33
|
|
|
|
}
|
|
|
|
"#;
|
2021-10-21 14:46:42 -07:00
|
|
|
let (_, output) = add_symbols(source);
|
|
|
|
let errs = output.unwrap_err();
|
|
|
|
assert_matches!(&errs[..], [
|
|
|
|
SymbolError::DuplicateName { prev_name: pn1, ..},
|
|
|
|
] if pn1 == &Fqsn::from_strs(&["q", "x"])
|
|
|
|
);
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dont_falsely_detect_duplicates() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
2019-10-16 19:51:43 -07:00
|
|
|
let a = 20;
|
|
|
|
fn some_func() {
|
|
|
|
let a = 40;
|
|
|
|
77
|
|
|
|
}
|
2021-11-14 00:34:21 -08:00
|
|
|
let q = 39
|
2019-10-16 19:51:43 -07:00
|
|
|
"#;
|
2021-10-21 14:46:42 -07:00
|
|
|
let (symbols, _) = add_symbols(source);
|
|
|
|
|
|
|
|
assert!(symbols.fq_names.table.get(&make_fqsn(&["a"])).is_some());
|
2021-10-29 00:28:05 -07:00
|
|
|
assert!(symbols.fq_names.table.get(&make_fqsn(&["some_func", "a"])).is_some());
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn enclosing_scopes() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
2019-10-16 19:51:43 -07:00
|
|
|
fn outer_func(x) {
|
|
|
|
fn inner_func(arg) {
|
|
|
|
arg
|
|
|
|
}
|
|
|
|
x + inner_func(x)
|
|
|
|
}"#;
|
2021-10-21 14:46:42 -07:00
|
|
|
let (symbols, _) = add_symbols(source);
|
2021-10-29 00:28:05 -07:00
|
|
|
assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func"])).is_some());
|
|
|
|
assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func", "inner_func"])).is_some());
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn enclosing_scopes_2() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
2019-10-16 19:51:43 -07:00
|
|
|
fn outer_func(x) {
|
|
|
|
fn inner_func(arg) {
|
|
|
|
arg
|
|
|
|
}
|
|
|
|
|
|
|
|
fn second_inner_func() {
|
|
|
|
fn another_inner_func() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inner_func(x)
|
2021-11-14 00:34:21 -08:00
|
|
|
}
|
|
|
|
"#;
|
2021-10-21 14:46:42 -07:00
|
|
|
let (symbols, _) = add_symbols(source);
|
2021-10-29 00:28:05 -07:00
|
|
|
assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func"])).is_some());
|
|
|
|
assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func", "inner_func"])).is_some());
|
|
|
|
assert!(symbols.fq_names.table.get(&make_fqsn(&["outer_func", "second_inner_func"])).is_some());
|
2021-10-21 14:46:42 -07:00
|
|
|
assert!(symbols
|
|
|
|
.fq_names
|
|
|
|
.table
|
2021-10-29 00:28:05 -07:00
|
|
|
.get(&make_fqsn(&["outer_func", "second_inner_func", "another_inner_func"]))
|
2021-10-21 14:46:42 -07:00
|
|
|
.is_some());
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn enclosing_scopes_3() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
2019-10-16 19:51:43 -07:00
|
|
|
fn outer_func(x) {
|
2021-11-14 00:34:21 -08:00
|
|
|
|
|
|
|
fn inner_func(arg) {
|
2019-10-16 19:51:43 -07:00
|
|
|
arg
|
|
|
|
}
|
|
|
|
|
|
|
|
fn second_inner_func() {
|
|
|
|
fn another_inner_func() {
|
|
|
|
}
|
|
|
|
fn another_inner_func() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inner_func(x)
|
|
|
|
}"#;
|
2021-10-21 14:46:42 -07:00
|
|
|
let (_, output) = add_symbols(source);
|
|
|
|
let _err = output.unwrap_err();
|
2019-10-16 19:51:43 -07:00
|
|
|
}
|
2019-10-24 01:34:13 -07:00
|
|
|
|
2019-10-24 03:02:52 -07:00
|
|
|
#[test]
|
|
|
|
fn modules() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
2019-10-24 03:02:52 -07:00
|
|
|
module stuff {
|
|
|
|
fn item() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn item()
|
|
|
|
"#;
|
2021-10-18 22:51:36 -07:00
|
|
|
|
2021-10-21 14:46:42 -07:00
|
|
|
let (symbols, _) = add_symbols(source);
|
|
|
|
symbols.fq_names.table.get(&make_fqsn(&["stuff"])).unwrap();
|
|
|
|
symbols.fq_names.table.get(&make_fqsn(&["item"])).unwrap();
|
2021-10-29 00:28:05 -07:00
|
|
|
symbols.fq_names.table.get(&make_fqsn(&["stuff", "item"])).unwrap();
|
2019-10-24 03:02:52 -07:00
|
|
|
}
|
|
|
|
|
2019-10-24 01:34:13 -07:00
|
|
|
#[test]
|
2019-10-24 02:13:07 -07:00
|
|
|
fn duplicate_modules() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
2019-10-24 02:13:07 -07:00
|
|
|
module q {
|
|
|
|
fn foo() { 4 }
|
|
|
|
}
|
2019-10-24 01:34:13 -07:00
|
|
|
|
|
|
|
module a {
|
2019-10-24 02:13:07 -07:00
|
|
|
fn foo() { 334 }
|
2019-10-24 01:34:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
module a {
|
2021-10-19 19:19:21 -07:00
|
|
|
fn sarat() { 39 }
|
2019-10-24 02:13:07 -07:00
|
|
|
fn foo() { 256.1 }
|
2019-10-24 01:34:13 -07:00
|
|
|
}
|
|
|
|
"#;
|
2021-10-21 14:46:42 -07:00
|
|
|
let (_, output) = add_symbols(source);
|
|
|
|
let errs = output.unwrap_err();
|
2021-10-19 19:19:21 -07:00
|
|
|
|
2021-10-21 14:46:42 -07:00
|
|
|
assert_matches!(&errs[..], [
|
|
|
|
SymbolError::DuplicateName { prev_name: pn1, ..},
|
|
|
|
] if pn1 == &Fqsn::from_strs(&["a"])
|
|
|
|
);
|
2019-10-24 01:34:13 -07:00
|
|
|
}
|
2021-10-19 20:35:53 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn duplicate_struct_members() {
|
2021-10-21 14:46:42 -07:00
|
|
|
let source = r#"
|
|
|
|
type Tarak = Tarak {
|
|
|
|
loujet: i32,
|
|
|
|
mets: i32,
|
|
|
|
mets: i32,
|
|
|
|
}
|
|
|
|
"#;
|
2021-10-19 20:35:53 -07:00
|
|
|
|
2021-10-21 14:46:42 -07:00
|
|
|
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"
|
|
|
|
);
|
2021-10-19 20:35:53 -07:00
|
|
|
}
|