mod test_helpers;
mod scope_resolution {
use crate::test_helpers::*;
use slicec::diagnostics::{Diagnostic, Error};
use slicec::grammar::*;
#[test]
fn identifier_exists_in_module_and_submodule() {
let slice1 = "
module A
typealias S = int32
struct C {
s1: S
s2: A::S
s3: B::S
s4: A::B::S
}
";
let slice2 = "
module A::B
struct S {
v: string
}
";
let ast = parse_multiple_for_ast(&[slice1, slice2]);
let s1_type = ast.find_element::<Field>("A::C::s1").unwrap().data_type();
let s2_type = ast.find_element::<Field>("A::C::s2").unwrap().data_type();
let s3_type = ast.find_element::<Field>("A::C::s3").unwrap().data_type();
let s4_type = ast.find_element::<Field>("A::C::s4").unwrap().data_type();
assert!(matches!(s1_type.concrete_type(), Types::Primitive(Primitive::Int32)));
assert!(matches!(s2_type.concrete_type(), Types::Primitive(Primitive::Int32)));
assert!(matches!(s3_type.concrete_type(), Types::Struct(_)));
assert!(matches!(s4_type.concrete_type(), Types::Struct(_)));
}
#[test]
fn identifier_exists_in_module_and_parent_module() {
let slice1 = "
module A
typealias S = int32
";
let slice2 = "
module A::B
typealias S = string
struct C {
s1: S
s2: B::S
s3: A::B::S
s4: A::S
}
";
let ast = parse_multiple_for_ast(&[slice1, slice2]);
let s1_type = ast.find_element::<Field>("A::B::C::s1").unwrap().data_type();
let s2_type = ast.find_element::<Field>("A::B::C::s2").unwrap().data_type();
let s3_type = ast.find_element::<Field>("A::B::C::s3").unwrap().data_type();
let s4_type = ast.find_element::<Field>("A::B::C::s4").unwrap().data_type();
assert!(matches!(s1_type.concrete_type(), Types::Primitive(Primitive::String)));
assert!(matches!(s2_type.concrete_type(), Types::Primitive(Primitive::String)));
assert!(matches!(s3_type.concrete_type(), Types::Primitive(Primitive::String)));
assert!(matches!(s4_type.concrete_type(), Types::Primitive(Primitive::Int32)));
}
#[test]
fn identifier_exists_in_multiple_parent_modules() {
let slice1 = "
module A
typealias S = int32
";
let slice2 = "
module A::B
struct S {
v: string
}
";
let slice3 = "
module A::B::B
struct C {
s1: S
s2: B::S
s3: A::S
}
";
let ast = parse_multiple_for_ast(&[slice1, slice2, slice3]);
let s1_type = ast.find_element::<Field>("A::B::B::C::s1").unwrap().data_type();
let s2_type = ast.find_element::<Field>("A::B::B::C::s2").unwrap().data_type();
let s3_type = ast.find_element::<Field>("A::B::B::C::s3").unwrap().data_type();
assert!(matches!(s1_type.concrete_type(), Types::Struct(_)));
assert!(matches!(s2_type.concrete_type(), Types::Struct(_)));
assert!(matches!(s3_type.concrete_type(), Types::Primitive(Primitive::Int32)));
}
#[test]
fn identifier_exists_in_multiple_modules_with_common_partial_scope() {
let slice1 = "
module A
struct C {
s1: A::B::S
s2: ::A::B::S
}
";
let slice2 = "
module A::B
typealias S = string
";
let slice3 = "
module A::B::A::B
typealias S = int32
struct C {
s1: A::B::S
s2: ::A::B::S
}
";
let ast = parse_multiple_for_ast(&[slice1, slice2, slice3]);
let nested_s1_type = ast.find_element::<Field>("A::B::A::B::C::s1").unwrap().data_type();
let nested_s2_type = ast.find_element::<Field>("A::B::A::B::C::s2").unwrap().data_type();
let s1_type = ast.find_element::<Field>("A::C::s1").unwrap().data_type();
let s2_type = ast.find_element::<Field>("A::C::s2").unwrap().data_type();
assert!(matches!(
nested_s1_type.concrete_type(),
Types::Primitive(Primitive::Int32),
));
assert!(matches!(
nested_s2_type.concrete_type(),
Types::Primitive(Primitive::String),
));
assert!(matches!(s1_type.concrete_type(), Types::Primitive(Primitive::String)));
assert!(matches!(s2_type.concrete_type(), Types::Primitive(Primitive::String)));
}
#[test]
fn relative_scope_is_module_before_interface() {
let slice1 = "
module A::B::C
struct S {
c: C
}
";
let slice2 = "
module A
interface C {}
";
let diagnostics = parse_multiple_for_diagnostics(&[slice1, slice2]);
let expected = Diagnostic::new(Error::TypeMismatch {
expected: "type".to_string(),
actual: "module".to_string(),
is_concrete: false,
});
check_diagnostics(diagnostics, [expected]);
}
#[test]
fn missing_type_should_fail() {
let slice = "
module A
struct C {
b: Nested::C
}
";
let diagnostics = parse_for_diagnostics(slice);
let expected = Diagnostic::new(Error::DoesNotExist {
identifier: "Nested::C".to_string(),
});
check_diagnostics(diagnostics, [expected]);
}
}