lib/std/lang/resolver/opaqueTests.rad 6.6 KiB raw
1
//! Module-owned record representation tests.
2
3
use std::testing;
4
use std::io;
5
use std::lang::ast;
6
use std::lang::resolver;
7
use super::tests;
8
9
/// Types used to check access to module-owned record representations.
10
constant OPAQUE_RECORD_MODEL: *[u8] = "export opaque record Value: Copy { number: u32 } export opaque record Word: Copy(u32); export opaque record Empty: Copy {} export opaque record View: 'r + Copy { number: &'r cell u32 } opaque record Hidden: Copy { number: u32 } export fn hidden() -> Hidden { return Hidden { number: 42 }; } export union Wrapped: Copy { Value(Value) }";
11
12
/// External record operations cannot expose or construct private fields.
13
@test unsafe fn testOpaqueRecordAccess() throws (testing::TestError) {
14
    for program in [
15
        "mod model; fn f(p: model::Value) -> u32 { return p.number; }",
16
        "mod model; fn f(p: &model::Value) -> u32 { return p.number; }",
17
        "mod model; fn f(p: &mut model::Value) { set p.number = 1; }",
18
        "mod model; fn f(p: &mut model::Value) { set p.number += 1; }",
19
        "mod model; fn f(p: &model::Value) { let field = &p.number; }",
20
        "mod model; fn f(p: &mut model::Value) { let field = &mut p.number; }",
21
        "mod model; unsafe fn f(p: model::Value) -> u32 { return p.number; }",
22
        "mod model; fn f() -> u32 { return model::hidden().number; }",
23
        "mod model; fn f() -> model::Value { return model::Value { number: 1 }; }",
24
        "mod model; fn f() -> model::Value { return { number: 1 }; }",
25
        "mod model; fn f() -> ?model::Value { return { number: 1 }; }",
26
        "mod model; fn f() -> model::Value { return model::Value { .. }; }",
27
        "mod model; fn f() -> model::Empty { return model::Empty {}; }",
28
        "mod model; fn f() -> model::Word { return model::Word(1); }",
29
        "mod model; fn f(p: model::Value) { let case model::Value { number } = p else panic; }",
30
        "mod model; fn f(p: &model::Value) { let case model::Value { number } = p else panic; }",
31
        "mod model; fn f(p: model::Value) { let case model::Value { .. } = p else panic; }",
32
        "mod model; fn f(p: model::Value) { if let case model::Value { number } = p; number > 0 {} }",
33
        "mod model; fn f(p: model::Value) { while let case model::Value { number } = p { break; } }",
34
        "mod model; fn f(p: model::Value) { match p { case model::Value { number } => {} } }",
35
        "mod model; fn f(p: model::Wrapped) { match p { case model::Wrapped::Value(model::Value { number }) => {} } }",
36
        "mod model; fn f(p: model::Word) { let case model::Word(number) = p else panic; }",
37
        "mod model; fn f(p: model::Word) -> u32 { return *p; }",
38
        "mod model; fn f(p: &mut model::Word) { set **p = 2; }",
39
        "mod model; fn f(p: model::Word) { let field = &*p; }",
40
        "mod model; fn f 'r (p: &model::View 'r) -> u32 { return *p.number; }",
41
        "mod model; fn f 'r (p: &model::View 'r) { set *p.number = 1; }",
42
        "mod model; fn f 'r (number: &'r cell u32) -> model::View 'r { return model::View 'r { number }; }",
43
        "mod model; fn f 'r (number: &'r cell u32) -> model::View 'r { return { number }; }",
44
        "mod model; fn f 'r (p: model::View 'r) { let case model::View 'r { number } = p else panic; }",
45
        "mod model; use root::model::*; fn f(p: Value) -> u32 { return p.number; }",
46
    ] {
47
        let mut storage = tests::testArena();
48
        let memory: 'test = &mut storage in {
49
            let mut res = tests::testResolver(memory);
50
            let mut arena = ast::nodeArena(&mut tests::AST_ARENA[..]);
51
            let root = try tests::registerModule(&mut tests::MODULE_GRAPH, nil, "root", program, &mut arena);
52
            let model = try tests::registerModule(&mut tests::MODULE_GRAPH, root, "model", OPAQUE_RECORD_MODEL, &mut arena);
53
            let result = try tests::resolveModuleTree(&mut res, root);
54
            try tests::expectErrorKind(&result, resolver::ErrorKind::OpaqueRecordAccess) catch error {
55
                io::print(program);
56
                io::print("\n");
57
                tests::printDiagnostics(&result.diagnostics, &res);
58
                throw error;
59
            };
60
        }
61
    }
62
}
63
64
/// Child and sibling modules cannot access an opaque record's fields.
65
@test unsafe fn testOpaqueRecordModuleBoundary() throws (testing::TestError) {
66
    for child in [false, true] {
67
        let mut storage = tests::testArena();
68
        let memory: 'test = &mut storage in {
69
            let mut res = tests::testResolver(memory);
70
            let mut arena = ast::nodeArena(&mut tests::AST_ARENA[..]);
71
            let root = try tests::registerModule(&mut tests::MODULE_GRAPH, nil, "root", "export mod model; mod client;", &mut arena);
72
            let model = try tests::registerModule(&mut tests::MODULE_GRAPH, root, "model", "mod child; export opaque record Value: Copy { number: u32 }", &mut arena);
73
            let program = "use root::model; fn f(p: model::Value) -> u32 { return p.number; }";
74
            let nested = try tests::registerModule(&mut tests::MODULE_GRAPH, model, "child", program if child else "", &mut arena);
75
            let client = try tests::registerModule(&mut tests::MODULE_GRAPH, root, "client", "" if child else program, &mut arena);
76
            let result = try tests::resolveModuleTree(&mut res, root);
77
            try tests::expectErrorKind(&result, resolver::ErrorKind::OpaqueRecordAccess) catch error {
78
                tests::printDiagnostics(&result.diagnostics, &res);
79
                throw error;
80
            };
81
        }
82
    }
83
}
84
85
/// Defining modules can access opaque representations through all source forms.
86
@test unsafe fn testOpaqueRecordLocalAccess() throws (testing::TestError) {
87
    let mut storage = tests::testArena();
88
    let memory: 'test = &mut storage in {
89
        let mut res = tests::testResolver(memory);
90
        let result = try tests::resolveProgramStr(&mut res,
91
            "opaque record Value: Copy { number: u32 } opaque record Word: Copy(u32); opaque record View: 'r + Copy { number: &'r cell u32 } fn f() { let mut p = Value { number: 1 }; set p.number += 2; let q: Value = { number: p.number }; let r: ?Value = { number: 4 }; let case Value { number } = q else panic; if let case Value { number: n } = p; n > 0 {} while let case Value { number: n } = p { break; } match p { case Value { number: n } => {} else => {} } let mut w = Word(1); set *w = 2; { let field = &mut *w; set *field = 3; } let case Word(n) = w else panic; } fn g 'r (number: &'r cell u32) -> View 'r { let p = View 'r { number }; set *p.number = 42; let case View 'r { number: value } = p else panic; return { number: value }; }"
92
        );
93
        try tests::expectNoErrors(&result) catch error {
94
            tests::printDiagnostics(&result.diagnostics, &res);
95
            throw error;
96
        };
97
    }
98
}