use super::super::common::*;
use luau_common::flags;
#[test]
fn type_alias_to_a_typeof() {
with_parse(
r#"
type A = typeof(1)
"#,
ParseOptions::default(),
|result| {
let result = result.unwrap();
let [statement] = statement_kinds(result.root.as_slice()).exact();
let type_alias = statement.as_type_alias().expect("expected type alias");
assert_eq!(type_alias.location(), loc!(pos!(1, 8), pos!(1, 26)));
},
);
}
#[test]
fn type_alias_should_point_to_string() {
with_parse(
r#"
type A = string
"#,
ParseOptions::default(),
|result| {
let result = result.unwrap();
let [statement] = statement_kinds(result.root.as_slice()).exact();
assert_eq!(statement.tag, StatementTag::TypeAlias);
},
);
}
#[test]
fn type_alias_should_not_interfere_with_type_function_call_or_assignment() {
with_parse(
r#"
type("a")
type = nil
"#,
ParseOptions::default(),
|result| {
let result = result.unwrap();
let [first, second] = statement_kinds(result.root.as_slice()).exact();
assert!(matches!(
first.as_expression().map(|statement| statement.expr.kind()),
Some(ExpressionKind::Call { .. })
));
assert_eq!(second.tag, StatementTag::Assign);
},
);
}
#[test]
fn type_alias_should_work_when_name_is_also_local() {
with_parse(
r#"
local A = nil
type A = string
"#,
ParseOptions::default(),
|result| {
let result = result.unwrap();
let [first, second] = statement_kinds(result.root.as_slice()).exact();
assert_eq!(first.tag, StatementTag::Local);
assert_eq!(second.tag, StatementTag::TypeAlias);
},
);
}
#[test]
fn type_alias_span_is_correct() {
with_parse(
r#"
type Packed1<T...> = (T...) -> (T...)
type Packed2<T...> = (Packed1<T...>, T...) -> (Packed1<T...>, T...)
"#,
ParseOptions::default().with_cst_data(true),
|result| {
let result = result.unwrap();
let [first, second] = statement_kinds(result.root.as_slice()).exact();
let first = first.as_type_alias().expect("expected packed type alias");
let second = second.as_type_alias().expect("expected packed type alias");
assert_eq!(first.location(), loc!(pos!(1, 8), pos!(1, 45)));
assert_eq!(second.location(), loc!(pos!(2, 8), pos!(2, 75)));
},
);
}
#[test]
fn prefixed_type_reference_links_to_local() {
let _prefix_local = flags::LuauTrackPrefixLocal.scoped(true);
with_parse_ok(
r#"
local Types = nil
type Foo = Types.Bar
"#,
|result| {
let [local, alias] = statement_kinds(result.root.as_slice()).exact();
let local = local.as_local().expect("expected local statement").bindings[0];
let alias = alias.as_type_alias().expect("expected type alias");
let TypeKind::Reference {
prefix,
prefix_local,
name,
..
} = alias.ty.kind()
else {
panic!("expected type reference");
};
assert_eq!(prefix.expect("expected prefix"), "Types");
assert_eq!(name, "Bar");
assert!(prefix_local.is_some_and(|prefix| std::ptr::eq(prefix, local)));
},
);
}
#[test]
fn unknown_prefixed_type_reference_has_no_local() {
let _prefix_local = flags::LuauTrackPrefixLocal.scoped(true);
with_parse_ok("type Foo = Unknown.Bar", |result| {
let [alias] = statement_kinds(result.root.as_slice()).exact();
let alias = alias.as_type_alias().expect("expected type alias");
let TypeKind::Reference {
prefix,
prefix_local,
..
} = alias.ty.kind()
else {
panic!("expected type reference");
};
assert_eq!(prefix.expect("expected prefix"), "Unknown");
assert!(prefix_local.is_none());
});
}
#[test]
fn prefixed_type_reference_shadowing() {
let _prefix_local = flags::LuauTrackPrefixLocal.scoped(true);
with_parse_ok(
r#"
local Types = nil
do
local Types = nil
type Foo = Types.Bar
end
type Bar = Types.Baz
"#,
|result| {
let [outer_local, inner_block, outer_alias] =
statement_kinds(result.root.as_slice()).exact();
let outer_local = outer_local
.as_local()
.expect("expected outer local")
.bindings[0];
let [inner_local, inner_alias] = statement_kinds(
inner_block
.as_block()
.expect("expected do block")
.as_slice(),
)
.exact();
let inner_local = inner_local
.as_local()
.expect("expected inner local")
.bindings[0];
let inner_alias = inner_alias.as_type_alias().expect("expected inner alias");
let TypeKind::Reference {
prefix_local: Some(inner_prefix),
..
} = inner_alias.ty.kind()
else {
panic!("expected linked inner type reference");
};
assert!(std::ptr::eq(inner_prefix, inner_local));
let outer_alias = outer_alias.as_type_alias().expect("expected outer alias");
let TypeKind::Reference {
prefix_local: Some(outer_prefix),
..
} = outer_alias.ty.kind()
else {
panic!("expected linked outer type reference");
};
assert!(std::ptr::eq(outer_prefix, outer_local));
assert!(!std::ptr::eq(inner_prefix, outer_prefix));
},
);
}
#[test]
fn parse_export_type() {
with_parse(
r#"
export()
export = 5
export, export = export
export type A = number
type A = number
"#,
ParseOptions::default(),
|result| {
let result = result.unwrap();
let statements = statement_kinds(result.root.as_slice()).exact::<5>();
assert_eq!(statements[0].tag, StatementTag::Expression);
assert_eq!(statements[1].tag, StatementTag::Assign);
assert_eq!(statements[2].tag, StatementTag::Assign);
assert_eq!(statements[3].tag, StatementTag::TypeAlias);
assert_eq!(statements[4].tag, StatementTag::TypeAlias);
},
);
}