plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
plum-checker/tests/monomorphize_tests.rs
#![allow(non_snake_case)]
use plum_checker::monomorphize::*;
use plum_checker::types::PlumType;
use plum_core::ast;
#[test]
fn isGenericParamNameAcceptsSingleUppercaseLettersOnly() {
assert!(isGenericParamName("T"));
assert!(isGenericParamName("W"));
assert!(!isGenericParamName("Int"));
assert!(!isGenericParamName("TU"));
assert!(!isGenericParamName("a"));
assert!(!isGenericParamName(""));
}
#[test]
fn classGenericParamsReadsDeclaredGenericsList() {
let c = ast::Class {
name: "Box".to_string(),
implements: vec![],
generics: vec![ast::GenericParam { name: "T".to_string(), bounds: vec![] }],
fields: vec![ast::Field { name: "value".to_string(), ty: ast::Type { name: "T".to_string(), generics: vec![] } }],
};
assert_eq!(classGenericParams(&c), vec!["T".to_string()]);
}
#[test]
fn fnGenericParamsDetectsImplicitUppercaseLetterTypesInOrder() {
let f = ast::Fn {
is_extern: false,
name: "pair".to_string(),
type_param: None,
params: vec![
ast::Param { name: "first".to_string(), ty: ast::ParamType::Type(ast::Type { name: "T".to_string(), generics: vec![] }), default: None },
ast::Param { name: "second".to_string(), ty: ast::ParamType::Type(ast::Type { name: "U".to_string(), generics: vec![] }), default: None },
],
returns: Some(ast::Type { name: "Bool".to_string(), generics: vec![] }),
body: ast::FnBody::Block(ast::Block { stmts: vec![] }),
};
assert_eq!(fnGenericParams(&f), vec!["T".to_string(), "U".to_string()]);
}
#[test]
fn enumGenericParamsDetectsImplicitUppercaseLetterVariantFields() {
let e = ast::Enum {
name: "Option".to_string(),
params: vec![],
variants: vec![
ast::EnumVariant { name: "Some".to_string(), fields: vec!["T".to_string()], values: vec![] },
ast::EnumVariant { name: "None".to_string(), fields: vec![], values: vec![] },
],
};
assert_eq!(enumGenericParams(&e), vec!["T".to_string()]);
}
#[test]
fn mangleJoinsBaseNameAndTypeArgs() {
assert_eq!(mangle("Box", &[PlumType::TInt]), "Box$Int");
assert_eq!(mangle("Pair", &[PlumType::TInt, PlumType::TStr]), "Pair$Int$Str");
assert_eq!(mangle("Green", &[]), "Green");
}
#[test]
fn specializeClassSubstitutesGenericFieldTypesAndClearsGenericsList() {
let c = ast::Class {
name: "Box".to_string(),
implements: vec![],
generics: vec![ast::GenericParam { name: "T".to_string(), bounds: vec![] }],
fields: vec![ast::Field { name: "value".to_string(), ty: ast::Type { name: "T".to_string(), generics: vec![] } }],
};
let mut bindings = std::collections::BTreeMap::new();
bindings.insert("T".to_string(), PlumType::TInt);
let specialized = specializeClass(&c, &Substitution(bindings), "Box$Int");
assert_eq!(specialized.name, "Box$Int");
assert!(specialized.generics.is_empty());
assert_eq!(specialized.fields[0].ty.name, "Int");
}
#[test]
fn specializeFnSubstitutesGenericParamAndReturnTypes() {
let f = ast::Fn {
is_extern: false,
name: "wrap".to_string(),
type_param: None,
params: vec![ast::Param { name: "value".to_string(), ty: ast::ParamType::Type(ast::Type { name: "T".to_string(), generics: vec![] }), default: None }],
returns: Some(ast::Type { name: "T".to_string(), generics: vec![] }),
body: ast::FnBody::Expr(ast::Expr::Var("value".to_string())),
};
let mut bindings = std::collections::BTreeMap::new();
bindings.insert("T".to_string(), PlumType::TInt);
let specialized = specializeFn(&f, &Substitution(bindings), "wrap$Int", None);
assert_eq!(specialized.name, "wrap$Int");
match &specialized.params[0].ty {
ast::ParamType::Type(t) => assert_eq!(t.name, "Int"),
_ => panic!("expected ParamType::Type"),
}
assert_eq!(specialized.returns.unwrap().name, "Int");
}
#[test]
fn specializeFnSetsNewReceiverForAMethod() {
let f = ast::Fn {
is_extern: false,
name: "getValue".to_string(),
type_param: Some("Box".to_string()),
params: vec![],
returns: Some(ast::Type { name: "T".to_string(), generics: vec![] }),
body: ast::FnBody::Expr(ast::Expr::Self_),
};
let mut bindings = std::collections::BTreeMap::new();
bindings.insert("T".to_string(), PlumType::TStr);
let specialized = specializeFn(&f, &Substitution(bindings), "getValue", Some("Box$Str".to_string()));
assert_eq!(specialized.name, "getValue");
assert_eq!(specialized.type_param, Some("Box$Str".to_string()));
assert_eq!(specialized.returns.unwrap().name, "Str");
}
#[test]
fn specializeEnumSubstitutesGenericVariantFieldNames() {
let e = ast::Enum {
name: "Option".to_string(),
params: vec![],
variants: vec![
ast::EnumVariant { name: "Some".to_string(), fields: vec!["T".to_string()], values: vec![] },
ast::EnumVariant { name: "None".to_string(), fields: vec![], values: vec![] },
],
};
let mut bindings = std::collections::BTreeMap::new();
bindings.insert("T".to_string(), PlumType::TInt);
let specialized = specializeEnum(&e, &Substitution(bindings), "Option$Int");
assert_eq!(specialized.name, "Option$Int");
assert_eq!(specialized.variants[0].fields, vec!["Int".to_string()]);
assert!(specialized.variants[1].fields.is_empty());
}