lang: Parse linear and pointer types

8ed9e8cc40e335d07b37836be7c4d3e7d53c243a3dfb968507a20122b6bfab7a
Alexis Sellier committed ago 1 parent 6bcd1af1
lib/std/lang.rad +1 -0
1 1
//! Radiance language implementation.
2 2
export mod alloc;
3 3
export mod sexpr;
4 +
export mod types;
4 5
export mod strings;
5 6
export mod scanner;
6 7
export mod ast;
7 8
export mod parser;
8 9
export mod module;
lib/std/lang/ast.rad +15 -3
2 2
export mod printer;
3 3
4 4
use std::io;
5 5
use std::fmt;
6 6
use std::lang::alloc;
7 +
use std::lang::types;
7 8
8 9
/// Maximum number of trait methods.
9 10
export constant MAX_TRAIT_METHODS: u32 = 8;
10 11
11 12
/// Arena for all parser allocations.
46 47
    Extern = 0b100,
47 48
    /// Test-only declaration attribute.
48 49
    Test = 0b1000,
49 50
    /// Compiler intrinsic attribute.
50 51
    Intrinsic = 0b10000,
52 +
    /// Declaration may perform unsafe pointer operations.
53 +
    Unsafe = 0b100000,
51 54
}
52 55
53 56
/// Ordered collection of attribute nodes applied to a declaration.
54 57
export record Attributes {
55 58
    list: *mut [*Node],
170 173
        /// Array element type.
171 174
        itemType: *Node,
172 175
        /// Expression that evaluates to the array length.
173 176
        length: *Node,
174 177
    },
175 -
    /// Slice type, eg. `*[i32]` or `*mut [i32]`.
178 +
    /// Slice type, eg. `*[i32]`, `&[i32]`, or `*unsafe [i32]`.
176 179
    Slice {
180 +
        /// Ownership and safety class.
181 +
        class: types::PointerClass,
177 182
        /// Slice element type.
178 183
        itemType: *Node,
179 184
        /// Whether the slice is mutable.
180 185
        mutable: bool,
181 186
    },
182 -
    /// Pointer, eg. `*i32` or `*mut i32`.
187 +
    /// Pointer type, eg. `*i32`, `&i32`, or `*unsafe i32`.
183 188
    Pointer {
189 +
        /// Ownership and safety class.
190 +
        class: types::PointerClass,
184 191
        /// Pointer target type.
185 192
        valueType: *Node,
186 193
        /// Whether the pointer is mutable.
187 194
        mutable: bool,
188 195
    },
200 207
        /// Whether this record has labeled fields.
201 208
        labeled: bool,
202 209
    },
203 210
    /// Anonymous function type.
204 211
    Fn(FnSig),
205 -
    /// Trait object type, eg. `*opaque Allocator`.
212 +
    /// Trait object type, eg. `*opaque Allocator`, `&opaque Allocator`, or
213 +
    /// `*unsafe opaque Allocator`.
206 214
    TraitObject {
215 +
        /// Ownership and safety class.
216 +
        class: types::PointerClass,
207 217
        /// Trait name identifier.
208 218
        traitName: *Node,
209 219
        /// Whether the pointer is mutable.
210 220
        mutable: bool,
211 221
    },
752 762
        name: *Node,
753 763
        /// Receiver type node (eg. `*mut Allocator`).
754 764
        receiver: *Node,
755 765
        /// Function signature.
756 766
        sig: FnSig,
767 +
        /// Optional declaration modifiers.
768 +
        attrs: ?Attributes,
757 769
    },
758 770
    /// Instance block.
759 771
    InstanceDecl {
760 772
        /// Trait name identifier.
761 773
        traitName: *Node,
lib/std/lang/ast/printer.rad +64 -13
1 1
//! AST pretty printer using S-expression syntax.
2 2
3 3
use std::io;
4 4
use std::lang::sexpr;
5 5
use std::lang::alloc;
6 +
use std::lang::types;
6 7
7 8
/// Return the symbol for a binary operator.
8 9
fn binOpName(op: super::BinaryOp) -> *[u8] {
9 10
    match op {
10 11
        case super::BinaryOp::Add => return "+",
66 67
            else => panic,
67 68
        }
68 69
    }
69 70
}
70 71
72 +
/// Return the S-expression head for a pointer class.
73 +
fn pointerClassHead(
74 +
    class: types::PointerClass,
75 +
    ownedHead: *[u8],
76 +
    refHead: *[u8],
77 +
    unsafeHead: *[u8],
78 +
) -> *[u8] {
79 +
    match class {
80 +
        case types::PointerClass::Owned => return ownedHead,
81 +
        case types::PointerClass::Ref => return refHead,
82 +
        case types::PointerClass::Unsafe => return unsafeHead,
83 +
    }
84 +
}
85 +
71 86
/// Convert a type signature to an S-expression.
72 87
fn typeSigToExpr(a: *mut alloc::Arena, sig: super::TypeSig) -> sexpr::Expr {
73 88
    match sig {
74 89
        case super::TypeSig::Void => return sexpr::sym("void"),
75 90
        case super::TypeSig::Opaque => return sexpr::sym("opaque"),
76 91
        case super::TypeSig::Bool => return sexpr::sym("bool"),
77 92
        case super::TypeSig::Integer { width, sign } => return sexpr::sym(intTypeName(width, sign)),
78 93
        case super::TypeSig::Array { itemType, length } =>
79 94
            return sexpr::list(a, "array", &[toExpr(a, itemType), toExpr(a, length)]),
80 -
        case super::TypeSig::Slice { itemType, mutable } =>
81 -
            return sexpr::list(a, "slice", &[sexpr::sym("mut"), toExpr(a, itemType)]) if mutable
82 -
                else sexpr::list(a, "slice", &[toExpr(a, itemType)]),
83 -
        case super::TypeSig::Pointer { valueType, mutable } =>
84 -
            return sexpr::list(a, "ptr", &[sexpr::sym("mut"), toExpr(a, valueType)]) if mutable
85 -
                else sexpr::list(a, "ptr", &[toExpr(a, valueType)]),
95 +
        case super::TypeSig::Slice { class, itemType, mutable } => {
96 +
            let head = pointerClassHead(class, "slice", "slice-ref", "unsafe-slice");
97 +
            return sexpr::list(a, head, &[sexpr::sym("mut"), toExpr(a, itemType)]) if mutable
98 +
                else sexpr::list(a, head, &[toExpr(a, itemType)]);
99 +
        }
100 +
        case super::TypeSig::Pointer { class, valueType, mutable } => {
101 +
            let head = pointerClassHead(class, "ptr", "ref", "unsafe-ptr");
102 +
            return sexpr::list(a, head, &[sexpr::sym("mut"), toExpr(a, valueType)]) if mutable
103 +
                else sexpr::list(a, head, &[toExpr(a, valueType)]);
104 +
        }
86 105
        case super::TypeSig::Optional { valueType } =>
87 106
            return sexpr::list(a, "?", &[toExpr(a, valueType)]),
88 107
        case super::TypeSig::Nominal(name) => return toExpr(a, name),
89 108
        case super::TypeSig::Record { fields, .. } =>
90 109
            return sexpr::list(a, "record", nodeListToExprs(a, &fields[..])),
93 112
            if let rt = sig.returnType {
94 113
                set ret = toExpr(a, rt);
95 114
            }
96 115
            return sexpr::list(a, "fn", &[sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..])), ret]);
97 116
        }
98 -
        case super::TypeSig::TraitObject { traitName, mutable } =>
99 -
            return sexpr::list(a, "obj", &[sexpr::sym("mut"), toExpr(a, traitName)]) if mutable
100 -
                else sexpr::list(a, "obj", &[toExpr(a, traitName)]),
117 +
        case super::TypeSig::TraitObject { class, traitName, mutable } => {
118 +
            let head = pointerClassHead(class, "obj", "obj-ref", "unsafe-obj");
119 +
            return sexpr::list(a, head, &[sexpr::sym("mut"), toExpr(a, traitName)]) if mutable
120 +
                else sexpr::list(a, head, &[toExpr(a, traitName)]);
121 +
        }
101 122
    }
102 123
}
103 124
104 125
/// Convert a node slice to a slice of expressions.
105 126
fn nodeListToExprs(a: *mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] {
111 132
        set buf[i] = toExpr(a, node);
112 133
    }
113 134
    return buf;
114 135
}
115 136
137 +
/// Convert optional attributes to an attribute list expression.
138 +
fn attributesToExpr(a: *mut alloc::Arena, attrs: ?super::Attributes) -> sexpr::Expr {
139 +
    let mut exprs: *[sexpr::Expr] = &[];
140 +
    if let list = attrs {
141 +
        set exprs = nodeListToExprs(a, &list.list[..]);
142 +
    }
143 +
    return sexpr::list(a, "attrs", exprs);
144 +
}
145 +
116 146
/// Convert an optional node to an expression, or return placeholder.
117 147
fn toExprOpt(a: *mut alloc::Arena, opt: ?*super::Node) -> sexpr::Expr {
118 148
    if let n = opt {
119 149
        return toExpr(a, n);
120 150
    }
305 335
                case super::Attribute::Export => return sexpr::sym("@export"),
306 336
                case super::Attribute::Default => return sexpr::sym("@default"),
307 337
                case super::Attribute::Extern => return sexpr::sym("@extern"),
308 338
                case super::Attribute::Test => return sexpr::sym("@test"),
309 339
                case super::Attribute::Intrinsic => return sexpr::sym("@intrinsic"),
340 +
                case super::Attribute::Unsafe => return sexpr::sym("@unsafe"),
310 341
            }
311 342
        }
312 343
        case super::NodeValue::Try(t) => {
313 344
            let mut head = "try";
314 345
            if t.shouldPanic { set head = "try!"; }
444 475
        case super::NodeValue::TraitDecl { name, supertraits, methods, .. } => {
445 476
            let children = nodeListToExprs(a, &methods[..]);
446 477
            let supers = sexpr::list(a, "supertraits", nodeListToExprs(a, &supertraits[..]));
447 478
            return sexpr::block(a, "trait", &[toExpr(a, name), supers], children);
448 479
        }
449 -
        case super::NodeValue::TraitMethodSig { name, receiver, sig } => {
480 +
        case super::NodeValue::TraitMethodSig { name, receiver, sig, attrs } => {
450 481
            let params = sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..]));
451 482
            let ret = toExprOrNull(a, sig.returnType);
452 -
            return sexpr::list(a, "methodSig", &[toExpr(a, receiver), toExpr(a, name), params, ret]);
483 +
            let attributes = attributesToExpr(a, attrs);
484 +
            return sexpr::list(
485 +
                a,
486 +
                "methodSig",
487 +
                &[attributes, toExpr(a, receiver), toExpr(a, name), params, ret],
488 +
            );
453 489
        }
454 490
        case super::NodeValue::InstanceDecl { traitName, targetType, methods } => {
455 491
            let children = nodeListToExprs(a, &methods[..]);
456 492
            return sexpr::block(a, "instance", &[toExpr(a, traitName), toExpr(a, targetType)], children);
457 493
        }
458 -
        case super::NodeValue::MethodDecl { name, receiverName, receiverType, sig, body, .. } => {
494 +
        case super::NodeValue::MethodDecl {
495 +
            name, receiverName, receiverType, sig, body, attrs,
496 +
        } => {
459 497
            let params = sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..]));
460 498
            let ret = toExprOrNull(a, sig.returnType);
461 -
            return sexpr::block(a, "method", &[toExpr(a, receiverType), toExpr(a, receiverName), toExpr(a, name), params, ret], &[toExpr(a, body)]);
499 +
            let attributes = attributesToExpr(a, attrs);
500 +
            return sexpr::block(
501 +
                a,
502 +
                "method",
503 +
                &[
504 +
                    attributes,
505 +
                    toExpr(a, receiverType),
506 +
                    toExpr(a, receiverName),
507 +
                    toExpr(a, name),
508 +
                    params,
509 +
                    ret,
510 +
                ],
511 +
                &[toExpr(a, body)],
512 +
            );
462 513
        }
463 514
        else => return sexpr::sym("?"),
464 515
    }
465 516
}
466 517
lib/std/lang/lower.rad +16 -9
88 88
//!   il::Data
89 89
//!
90 90
use std::fmt;
91 91
use std::io;
92 92
use std::lang::alloc;
93 +
use std::lang::types;
93 94
use std::mem;
94 95
use std::lang::ast;
95 96
use std::lang::il;
96 97
use std::lang::module;
97 98
use std::lang::resolver;
4220 4221
fn buildNilOptional(self: *mut FnLowerer, optType: resolver::Type) -> il::Val throws (LowerError) {
4221 4222
    match optType {
4222 4223
        case resolver::Type::Optional(resolver::Type::Pointer { .. }) => {
4223 4224
            return il::Val::Imm(0);
4224 4225
        }
4225 -
        case resolver::Type::Optional(resolver::Type::Slice { item, mutable }) => {
4226 +
        case resolver::Type::Optional(resolver::Type::Slice { item, mutable, .. }) => {
4226 4227
            return try buildSliceValue(self, item, mutable, il::Val::Imm(0), il::Val::Imm(0), il::Val::Imm(0));
4227 4228
        }
4228 4229
        case resolver::Type::Optional(inner) => {
4229 4230
            let valOffset = resolver::getOptionalValOffset(*inner) as i32;
4230 4231
            return try buildTagged(self, resolver::getTypeLayout(optType), 0, nil, *inner, 1, valOffset);
4254 4255
    mutable: bool,
4255 4256
    ptrVal: il::Val,
4256 4257
    lenVal: il::Val,
4257 4258
    capVal: il::Val
4258 4259
) -> il::Val throws (LowerError) {
4259 -
    let sliceType = resolver::Type::Slice { item: elemTy, mutable };
4260 +
    let sliceType = resolver::Type::Slice {
4261 +
        class: types::PointerClass::Owned, item: elemTy, mutable,
4262 +
    };
4260 4263
    let dst = try emitReserve(self, sliceType);
4261 -
    let ptrTy = resolver::Type::Pointer { target: elemTy, mutable };
4264 +
    let ptrTy = resolver::Type::Pointer {
4265 +
        class: types::PointerClass::Owned, target: elemTy, mutable,
4266 +
    };
4262 4267
4263 4268
    try emitStore(self, dst, SLICE_PTR_OFFSET, ptrTy, ptrVal);
4264 4269
    try emitStore(self, dst, SLICE_LEN_OFFSET, resolver::Type::U32, lenVal);
4265 4270
    try emitStore(self, dst, SLICE_CAP_OFFSET, resolver::Type::U32, capVal);
4266 4271
4444 4449
    mutable: bool,
4445 4450
    a: il::Reg,
4446 4451
    b: il::Reg,
4447 4452
    offset: i32
4448 4453
) -> il::Val throws (LowerError) {
4449 -
    let ptrTy = resolver::Type::Pointer { target: elemTy, mutable };
4454 +
    let ptrTy = resolver::Type::Pointer {
4455 +
        class: types::PointerClass::Owned, target: elemTy, mutable,
4456 +
    };
4450 4457
    let ptrEq = try emitEqAtOffset(self, a, b, offset + SLICE_PTR_OFFSET, ptrTy);
4451 4458
    let lenEq = try emitEqAtOffset(self, a, b, offset + SLICE_LEN_OFFSET, resolver::Type::U32);
4452 4459
4453 4460
    return emitTypedBinOp(self, il::BinOp::And, il::Type::W32, ptrEq, lenEq);
4454 4461
}
4693 4700
    a: il::Reg,
4694 4701
    b: il::Reg,
4695 4702
    offset: i32
4696 4703
) -> il::Val throws (LowerError) {
4697 4704
    match typ {
4698 -
        case resolver::Type::Optional(resolver::Type::Slice { item, mutable }) => {
4705 +
        case resolver::Type::Optional(resolver::Type::Slice { item, mutable, .. }) => {
4699 4706
            // Optional slices use null pointer optimization.
4700 4707
            return try lowerSliceEq(self, item, mutable, a, b, offset);
4701 4708
        }
4702 4709
        case resolver::Type::Optional(inner) => {
4703 4710
            return try lowerOptionalEq(self, *inner, a, b, offset);
4704 4711
        }
4705 -
        case resolver::Type::Slice { item, mutable } =>
4712 +
        case resolver::Type::Slice { item, mutable, .. } =>
4706 4713
            return try lowerSliceEq(self, item, mutable, a, b, offset),
4707 4714
        case resolver::Type::Array(arr) =>
4708 4715
            return try lowerArrayEq(self, arr, a, b, offset),
4709 4716
        case resolver::Type::Nominal(resolver::NominalType::Record(recInfo)) =>
4710 4717
            return try lowerRecordEq(self, recInfo, a, b, offset),
5058 5065
    self: *mut FnLowerer,
5059 5066
    sliceNode: *ast::Node,
5060 5067
    arrayNode: *ast::Node
5061 5068
) -> il::Val throws (LowerError) {
5062 5069
    let sliceTy = try typeOf(self, sliceNode);
5063 -
    let case resolver::Type::Slice { item, mutable } = sliceTy else {
5070 +
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy else {
5064 5071
        throw LowerError::UnexpectedType(&sliceTy);
5065 5072
    };
5066 5073
    let arrayTy = try typeOf(self, arrayNode);
5067 5074
    let case resolver::Type::Array(arrayInfo) = arrayTy else {
5068 5075
        throw LowerError::ExpectedArray;
6140 6147
/// String literals are stored as global data and the result is a slice
6141 6148
/// pointing to the data with the appropriate length.
6142 6149
fn lowerStringLit(self: *mut FnLowerer, node: *ast::Node, s: *[u8]) -> il::Val throws (LowerError) {
6143 6150
    // Get the slice type from the node.
6144 6151
    let sliceTy = try typeOf(self, node);
6145 -
    let case resolver::Type::Slice { item, mutable } = sliceTy else {
6152 +
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy else {
6146 6153
        throw LowerError::ExpectedSliceOrArray;
6147 6154
    };
6148 6155
    // Build the string data value.
6149 6156
    let ptr = try! alloc::alloc(
6150 6157
        self.low.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue)
6172 6179
fn lowerSliceOf(self: *mut FnLowerer, node: *ast::Node, args: *mut [*ast::Node]) -> il::Val throws (LowerError) {
6173 6180
    if args.len <> 2 and args.len <> 3 {
6174 6181
        throw LowerError::InvalidArgCount;
6175 6182
    }
6176 6183
    let sliceTy = try typeOf(self, node);
6177 -
    let case resolver::Type::Slice { item, mutable } = sliceTy else {
6184 +
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy else {
6178 6185
        throw LowerError::ExpectedSliceOrArray;
6179 6186
    };
6180 6187
    let ptrVal = try lowerExpr(self, args[0]);
6181 6188
    let lenVal = try lowerExpr(self, args[1]);
6182 6189
    let mut capVal = lenVal;
lib/std/lang/parser.rad +39 -21
3 3
4 4
use std::mem;
5 5
use std::io;
6 6
use std::fmt;
7 7
use std::lang::alloc;
8 +
use std::lang::types;
8 9
use std::lang::ast;
9 10
use std::lang::strings;
10 11
use std::lang::scanner;
11 12
12 13
/// Maximum `u32` value.
779 780
        ));
780 781
    }
781 782
    throw failParsing(p, "expected assignment after `set`");
782 783
}
783 784
784 -
/// Parse leading attributes attached to the next declaration statement.
785 +
/// Parse leading attributes and declaration modifiers.
785 786
fn parseAttributes(p: *mut Parser) -> ?ast::Attributes {
786 787
    let mut attrs = ast::nodeSlice(p.arena, 4);
787 788
788 789
    if let attr = tryParseAnnotation(p) {
789 790
        attrs.append(attr, p.allocator);
790 791
    }
791 792
    if consume(p, scanner::TokenKind::Export) {
792 -
        let attrNode = nodeAttribute(p, ast::Attribute::Export);
793 -
        attrs.append(attrNode, p.allocator);
793 +
        attrs.append(nodeAttribute(p, ast::Attribute::Export), p.allocator);
794 +
    }
795 +
    if consume(p, scanner::TokenKind::Unsafe) {
796 +
        attrs.append(nodeAttribute(p, ast::Attribute::Unsafe), p.allocator);
794 797
    }
795 798
    if attrs.len > 0 {
796 799
        return ast::Attributes { list: attrs };
797 800
    }
798 801
    return nil;
831 834
{
832 835
    // TODO: Why is `parseStmt` checking for attributes?
833 836
    // We should have a `parseDecl` which is top-level, and `parseStmt` which
834 837
    // is inside functions.
835 838
    let attrs = parseAttributes(p);
836 -
    if attrs <> nil {
839 +
    if let list = attrs {
840 +
        if ast::attributesContains(&list, ast::Attribute::Unsafe)
841 +
            and p.current.kind <> scanner::TokenKind::Fn
842 +
            and p.current.kind <> scanner::TokenKind::Mod
843 +
        {
844 +
            throw failParsing(p, "`unsafe` is only allowed on functions and modules");
845 +
        }
837 846
        let allowed: bool =
838 847
            p.current.kind == scanner::TokenKind::Fn or
839 848
            p.current.kind == scanner::TokenKind::Union or
840 849
            p.current.kind == scanner::TokenKind::Record or
841 850
            p.current.kind == scanner::TokenKind::Mod or
1856 1865
    return node(p, ast::NodeValue::FnDecl(
1857 1866
        ast::FnDecl { name, sig, body, attrs: fnAttrs }
1858 1867
    ));
1859 1868
}
1860 1869
1861 -
/// Parse a pointer or slice type.
1862 -
fn parsePointerType(p: *mut Parser) -> *ast::Node
1863 -
    throws (ParseError)
1864 -
{
1865 -
    try expect(p, scanner::TokenKind::Star, "expected `*`");
1870 +
/// Parse a pointer-like type after its ownership prefix.
1871 +
fn parsePointerLikeType(
1872 +
    p: *mut Parser,
1873 +
    class: types::PointerClass,
1874 +
) -> *ast::Node throws (ParseError) {
1866 1875
    let mutable = consume(p, scanner::TokenKind::Mut);
1867 1876
1868 1877
    if consume(p, scanner::TokenKind::LBracket) {
1869 1878
        let itemType = try parseType(p);
1870 1879
        try expect(p, scanner::TokenKind::RBracket, "expected `]` after slice element type");
1871 1880
1872 1881
        return node(p, ast::NodeValue::TypeSig(
1873 -
            ast::TypeSig::Slice { itemType, mutable }
1882 +
            ast::TypeSig::Slice { class, itemType, mutable }
1874 1883
        ));
1875 1884
    }
1876 -
    // Check for `*opaque Trait` or `*mut opaque Trait`.
1885 +
    // Check for an opaque trait object.
1877 1886
    if consume(p, scanner::TokenKind::Opaque) {
1878 1887
        if check(p, scanner::TokenKind::Ident) or check(p, scanner::TokenKind::Super) {
1879 1888
            let traitName = try parseTypePath(p);
1880 1889
            return node(p, ast::NodeValue::TypeSig(
1881 -
                ast::TypeSig::TraitObject { traitName, mutable }
1890 +
                ast::TypeSig::TraitObject { class, traitName, mutable }
1882 1891
            ));
1883 1892
        }
1884 -
        // Plain `*opaque`.
1893 +
        // Plain opaque target.
1894 +
        let valueType = node(p, ast::NodeValue::TypeSig(ast::TypeSig::Opaque));
1885 1895
        return node(p, ast::NodeValue::TypeSig(
1886 -
            ast::TypeSig::Pointer {
1887 -
                valueType: node(p, ast::NodeValue::TypeSig(ast::TypeSig::Opaque)),
1888 -
                mutable,
1889 -
            }
1896 +
            ast::TypeSig::Pointer { class, valueType, mutable }
1890 1897
        ));
1891 1898
    }
1892 1899
    let valueType = try parseType(p);
1893 1900
1894 1901
    return node(p, ast::NodeValue::TypeSig(
1895 -
        ast::TypeSig::Pointer { valueType, mutable }
1902 +
        ast::TypeSig::Pointer { class, valueType, mutable }
1896 1903
    ));
1897 1904
}
1898 1905
1899 1906
/// Parse an array type.
1900 1907
fn parseArrayType(p: *mut Parser) -> *ast::Node
1945 1952
            return node(p, ast::NodeValue::TypeSig(
1946 1953
                ast::TypeSig::Optional { valueType }
1947 1954
            ));
1948 1955
        }
1949 1956
        case scanner::TokenKind::Star => {
1950 -
            return try parsePointerType(p);
1957 +
            advance(p);
1958 +
            let class = types::PointerClass::Unsafe
1959 +
                if consume(p, scanner::TokenKind::Unsafe)
1960 +
                else types::PointerClass::Owned;
1961 +
            return try parsePointerLikeType(p, class);
1962 +
        }
1963 +
        case scanner::TokenKind::Amp => {
1964 +
            advance(p);
1965 +
            return try parsePointerLikeType(p, types::PointerClass::Ref);
1951 1966
        }
1952 1967
        case scanner::TokenKind::LBracket => {
1953 1968
            return try parseArrayType(p);
1954 1969
        }
1955 1970
        case scanner::TokenKind::Super, scanner::TokenKind::Ident => {
2252 2267
/// Parse a trait method signature.
2253 2268
/// Syntax: `fn (*Trait) fnord(<params>) -> ReturnType;`
2254 2269
fn parseTraitMethodSig(p: *mut Parser) -> *ast::Node
2255 2270
    throws (ParseError)
2256 2271
{
2272 +
    let attrs = parseAttributes(p);
2257 2273
    try expect(p, scanner::TokenKind::Fn, "expected `fn`");
2258 2274
    try expect(p, scanner::TokenKind::LParen, "expected `(` before receiver");
2259 2275
2260 2276
    let receiver = try parseType(p);
2261 2277
2263 2279
2264 2280
    let name = try parseIdent(p, "expected method name");
2265 2281
    let sig = try parseFnTypeSig(p);
2266 2282
    try expect(p, scanner::TokenKind::Semicolon, "expected `;` after method signature");
2267 2283
2268 -
    return node(p, ast::NodeValue::TraitMethodSig { name, receiver, sig });
2284 +
    return node(p, ast::NodeValue::TraitMethodSig { name, receiver, sig, attrs });
2269 2285
}
2270 2286
2271 2287
/// Parse an instance block.
2272 2288
/// Syntax: `instance Trait for Type { fn (t: *mut Type) fnord(..) {..} }`
2273 2289
///
2281 2297
    try expect(p, scanner::TokenKind::For, "expected `for` after trait name");
2282 2298
    let targetType = try parseTypePath(p);
2283 2299
    try expect(p, scanner::TokenKind::LBrace, "expected `{` after target type");
2284 2300
2285 2301
    let mut methods = ast::nodeSlice(p.arena, ast::MAX_TRAIT_METHODS);
2302 +
2286 2303
    while not check(p, scanner::TokenKind::RBrace) and
2287 2304
          not check(p, scanner::TokenKind::Eof)
2288 2305
    {
2306 +
        let attrs = parseAttributes(p);
2289 2307
        try expect(p, scanner::TokenKind::Fn, "expected `fn`");
2290 -
        let method = try parseMethodDecl(p, nil);
2308 +
        let method = try parseMethodDecl(p, attrs);
2291 2309
2292 2310
        methods.append(method, p.allocator);
2293 2311
    }
2294 2312
    try expect(p, scanner::TokenKind::RBrace, "expected `}` after instance methods");
2295 2313
lib/std/lang/parser/tests.rad +153 -21
2 2
3 3
use std::mem;
4 4
use std::fmt;
5 5
use std::testing;
6 6
use std::lang::ast;
7 +
use std::lang::types;
8 +
use std::lang::alloc;
9 +
use std::lang::sexpr;
10 +
use std::lang::ast::printer;
7 11
use std::lang::scanner;
8 12
use std::lang::strings;
9 13
10 14
/// Unified arena size.
11 15
constant ARENA_SIZE: u32 = 2097152;
783 787
        else throw testing::TestError::Failed;
784 788
785 789
    try expectIntType(opt, 4, ast::Signedness::Signed);
786 790
}
787 791
788 -
/// Test parsing a pointer type, including `mut`.
789 -
@test fn testParseTypePointer() throws (testing::TestError) {
790 -
    let node = try! parseTypeStr("*mut i32");
792 +
/// Parse an `i32` pointer type and verify its class and mutability.
793 +
fn expectI32Pointer(
794 +
    source: *[u8],
795 +
    class: types::PointerClass,
796 +
    mutable: bool,
797 +
) throws (testing::TestError) {
798 +
    let node = try! parseTypeStr(source);
791 799
    let case ast::NodeValue::TypeSig(sig) = node.value
792 800
        else throw testing::TestError::Failed;
793 -
    let case ast::TypeSig::Pointer { valueType, mutable } = sig
794 -
        else throw testing::TestError::Failed;
801 +
    let case ast::TypeSig::Pointer {
802 +
        class: actualClass, valueType, mutable: actualMutable,
803 +
    } = sig else throw testing::TestError::Failed;
795 804
805 +
    assert actualClass == class;
796 806
    try expectIntType(valueType, 4, ast::Signedness::Signed);
797 -
    try testing::expect(mutable);
807 +
    assert actualMutable == mutable;
808 +
}
809 +
810 +
/// Test parsing a mutable owned pointer.
811 +
@test fn testParseTypePointer() throws (testing::TestError) {
812 +
    try expectI32Pointer("*mut i32", types::PointerClass::Owned, true);
798 813
}
799 814
800 -
/// Test parsing an immutable pointer type.
815 +
/// Test parsing an immutable owned pointer.
801 816
@test fn testParseTypePointerImmutable() throws (testing::TestError) {
802 -
    let node = try! parseTypeStr("*i32");
803 -
    let case ast::NodeValue::TypeSig(sig) = node.value
804 -
        else throw testing::TestError::Failed;
805 -
    let case ast::TypeSig::Pointer { valueType, mutable } = sig
806 -
        else throw testing::TestError::Failed;
817 +
    try expectI32Pointer("*i32", types::PointerClass::Owned, false);
818 +
}
807 819
808 -
    try expectIntType(valueType, 4, ast::Signedness::Signed);
809 -
    try testing::expect(not mutable);
820 +
/// Test parsing immutable and mutable references.
821 +
@test fn testParseTypeRef() throws (testing::TestError) {
822 +
    try expectI32Pointer("&i32", types::PointerClass::Ref, false);
823 +
    try expectI32Pointer("&mut i32", types::PointerClass::Ref, true);
824 +
}
825 +
826 +
/// Test parsing immutable and mutable unsafe pointers.
827 +
@test fn testParseTypeUnsafePointer() throws (testing::TestError) {
828 +
    try expectI32Pointer("*unsafe i32", types::PointerClass::Unsafe, false);
829 +
    try expectI32Pointer("*unsafe mut i32", types::PointerClass::Unsafe, true);
810 830
}
811 831
812 832
/// Test parsing a slice type.
813 833
@test fn testParseTypeSlice() throws (testing::TestError) {
814 834
    let node = try! parseTypeStr("*[u8]");
815 835
    let case ast::NodeValue::TypeSig(sig) = node.value
816 836
        else throw testing::TestError::Failed;
817 -
    let case ast::TypeSig::Slice { itemType, mutable } = sig
837 +
    let case ast::TypeSig::Slice { class, itemType, mutable } = sig
818 838
        else throw testing::TestError::Failed;
819 839
840 +
    assert class == types::PointerClass::Owned;
820 841
    try expectIntType(itemType, 1, ast::Signedness::Unsigned);
821 -
    try testing::expect(not mutable);
842 +
    assert not mutable;
822 843
}
823 844
824 845
/// Test parsing a mutable slice type.
825 846
@test fn testParseTypeSliceMutable() throws (testing::TestError) {
826 847
    let node = try! parseTypeStr("*mut [u8]");
827 848
    let case ast::NodeValue::TypeSig(sig) = node.value
828 849
        else throw testing::TestError::Failed;
829 -
    let case ast::TypeSig::Slice { itemType, mutable } = sig
850 +
    let case ast::TypeSig::Slice { class, itemType, mutable } = sig
830 851
        else throw testing::TestError::Failed;
831 852
853 +
    assert class == types::PointerClass::Owned;
832 854
    try expectIntType(itemType, 1, ast::Signedness::Unsigned);
833 -
    try testing::expect(mutable);
855 +
    assert mutable;
856 +
}
857 +
858 +
/// Test parsing reference and unsafe slice classes.
859 +
@test fn testParseTypeSliceClasses() throws (testing::TestError) {
860 +
    let refNode = try! parseTypeStr("&[u8]");
861 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Slice {
862 +
        class: refClass, ..
863 +
    }) = refNode.value else throw testing::TestError::Failed;
864 +
    assert refClass == types::PointerClass::Ref;
865 +
866 +
    let unsafeNode = try! parseTypeStr("*unsafe [u8]");
867 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::Slice {
868 +
        class: unsafeClass, ..
869 +
    }) = unsafeNode.value else throw testing::TestError::Failed;
870 +
    assert unsafeClass == types::PointerClass::Unsafe;
871 +
}
872 +
873 +
/// Test parsing trait object pointer classes.
874 +
@test fn testParseTypeTraitObjectClasses() throws (testing::TestError) {
875 +
    let ownedNode = try! parseTypeStr("*opaque Read");
876 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::TraitObject {
877 +
        class: ownedClass, ..
878 +
    }) = ownedNode.value else throw testing::TestError::Failed;
879 +
    assert ownedClass == types::PointerClass::Owned;
880 +
881 +
    let refNode = try! parseTypeStr("&opaque Read");
882 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::TraitObject {
883 +
        class: refClass, ..
884 +
    }) = refNode.value else throw testing::TestError::Failed;
885 +
    assert refClass == types::PointerClass::Ref;
886 +
887 +
    let unsafeNode = try! parseTypeStr("*unsafe opaque Read");
888 +
    let case ast::NodeValue::TypeSig(ast::TypeSig::TraitObject {
889 +
        class: unsafeClass, ..
890 +
    }) = unsafeNode.value else throw testing::TestError::Failed;
891 +
    assert unsafeClass == types::PointerClass::Unsafe;
834 892
}
835 893
836 894
/// Test parsing an array type.
837 895
@test fn testParseTypeArray() throws (testing::TestError) {
838 896
    let node = try! parseTypeStr("[i32; 4]");
964 1022
    try expectIntType(param0, 4, ast::Signedness::Signed);
965 1023
966 1024
    let param1 = sig.params[1];
967 1025
    let case ast::NodeValue::TypeSig(p1) = param1.value
968 1026
        else throw testing::TestError::Failed;
969 -
    let case ast::TypeSig::Pointer { valueType: ptrTarget, mutable: _ } = p1
1027 +
    let case ast::TypeSig::Pointer { valueType: ptrTarget, .. } = p1
970 1028
        else throw testing::TestError::Failed;
971 1029
    try expectIntType(ptrTarget, 1, ast::Signedness::Unsigned);
972 1030
973 1031
    try testing::expect(sig.returnType <> nil);
974 1032
}
1071 1129
    let mut parser = super::mkParser(scanner::SourceLoc::String, "void", &mut arena, &mut STRING_POOL);
1072 1130
    super::advance(&mut parser);
1073 1131
    try testing::expect(super::check(&parser, scanner::TokenKind::Ident));
1074 1132
}
1075 1133
1134 +
/// Test parsing the unsafe function modifier.
1135 +
@test fn testParseUnsafeFnDecl() throws (testing::TestError) {
1136 +
    let node = try! parseStmtStr("unsafe fn run() {}");
1137 +
    let case ast::NodeValue::FnDecl(decl) = node.value
1138 +
        else throw testing::TestError::Failed;
1139 +
    let attrs = decl.attrs
1140 +
        else throw testing::TestError::Failed;
1141 +
1142 +
    try testing::expect(attrs.list.len == 1);
1143 +
    try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Unsafe));
1144 +
}
1145 +
1146 +
/// Test rejecting `unsafe` on declarations where it has no semantics.
1147 +
@test fn testParseUnsafeUnsupportedDecl() throws (testing::TestError) {
1148 +
    let recordDecl: ?*ast::Node = try? parseStmtStr("unsafe record R {}");
1149 +
    try testing::expect(recordDecl == nil);
1150 +
    let constDecl: ?*ast::Node = try? parseStmtStr("unsafe constant X = 1;");
1151 +
    try testing::expect(constDecl == nil);
1152 +
}
1153 +
1154 +
/// Test `unsafe` on the other declaration forms that support it.
1155 +
@test fn testParseUnsafeMethodAndModule() throws (testing::TestError) {
1156 +
    let moduleNode = try! parseStmtStr("unsafe mod io;");
1157 +
    let case ast::NodeValue::Mod(moduleDecl) = moduleNode.value
1158 +
        else throw testing::TestError::Failed;
1159 +
    let moduleAttrs = moduleDecl.attrs else throw testing::TestError::Failed;
1160 +
    assert ast::attributesContains(&moduleAttrs, ast::Attribute::Unsafe);
1161 +
1162 +
    let instanceNode = try! parseStmtStr(
1163 +
        "instance Read for Value { unsafe fn (value: &Value) get() {} }"
1164 +
    );
1165 +
    let case ast::NodeValue::InstanceDecl { methods, .. } = instanceNode.value
1166 +
        else throw testing::TestError::Failed;
1167 +
    try testing::expect(methods.len == 1);
1168 +
    let case ast::NodeValue::MethodDecl { attrs, .. } = methods[0].value
1169 +
        else throw testing::TestError::Failed;
1170 +
    let methodAttrs = attrs else throw testing::TestError::Failed;
1171 +
    assert ast::attributesContains(&methodAttrs, ast::Attribute::Unsafe);
1172 +
1173 +
    let mut printStorage: [u8; 4096] = undefined;
1174 +
    let mut printArena = alloc::new(&mut printStorage[..]);
1175 +
    let methodExpr = printer::toExpr(&mut printArena, methods[0]);
1176 +
    let case sexpr::Expr::Block { items: methodItems, .. } = methodExpr
1177 +
        else throw testing::TestError::Failed;
1178 +
    let case sexpr::Expr::List {
1179 +
        head: methodAttrsHead, tail: printedMethodAttrs, ..
1180 +
    } = methodItems[0] else throw testing::TestError::Failed;
1181 +
    assert mem::eq(methodAttrsHead, "attrs");
1182 +
    let case sexpr::Expr::Sym(methodAttr) = printedMethodAttrs[0]
1183 +
        else throw testing::TestError::Failed;
1184 +
    assert mem::eq(methodAttr, "@unsafe");
1185 +
1186 +
    let traitNode = try! parseStmtStr(
1187 +
        "trait Read { unsafe fn (&Read) get(); }"
1188 +
    );
1189 +
    let case ast::NodeValue::TraitDecl { methods: traitMethods, .. } = traitNode.value
1190 +
        else throw testing::TestError::Failed;
1191 +
    let case ast::NodeValue::TraitMethodSig {
1192 +
        attrs: traitAttrs, ..
1193 +
    } = traitMethods[0].value else throw testing::TestError::Failed;
1194 +
    let traitMethodAttrs = traitAttrs else throw testing::TestError::Failed;
1195 +
    assert ast::attributesContains(&traitMethodAttrs, ast::Attribute::Unsafe);
1196 +
1197 +
    let traitMethodExpr = printer::toExpr(&mut printArena, traitMethods[0]);
1198 +
    let case sexpr::Expr::List { tail: traitMethodItems, .. } = traitMethodExpr
1199 +
        else throw testing::TestError::Failed;
1200 +
    let case sexpr::Expr::List {
1201 +
        head: traitAttrsHead, tail: printedTraitAttrs, ..
1202 +
    } = traitMethodItems[0] else throw testing::TestError::Failed;
1203 +
    assert mem::eq(traitAttrsHead, "attrs");
1204 +
    let case sexpr::Expr::Sym(traitAttr) = printedTraitAttrs[0]
1205 +
        else throw testing::TestError::Failed;
1206 +
    assert mem::eq(traitAttr, "@unsafe");
1207 +
}
1208 +
1076 1209
/// Test parsing a function declaration with attributes.
1077 1210
@test fn testParseFnDeclAttributes() throws (testing::TestError) {
1078 1211
    let node = try! parseStmtStr("export fn run();");
1079 1212
    let case ast::NodeValue::FnDecl(decl) = node.value
1080 1213
        else throw testing::TestError::Failed;
1164 1297
@test fn testParseTypeBool() throws (testing::TestError) {
1165 1298
    let node = try! parseTypeStr("bool");
1166 1299
    try expectType(node, ast::TypeSig::Bool);
1167 1300
}
1168 1301
1169 -
1170 1302
/// Test parsing an unsigned integer type.
1171 1303
@test fn testParseTypeUnsigned() throws (testing::TestError) {
1172 1304
    let node = try! parseTypeStr("u8");
1173 1305
    try expectType(node, ast::TypeSig::Integer {
1174 1306
        width: 1,
2081 2213
        try expectIdent(access.child, "field");
2082 2214
    }
2083 2215
}
2084 2216
2085 2217
/// Test parsing reference (address-of) expressions.
2086 -
@test fn testParseReferences() throws (testing::TestError) {
2218 +
@test fn testParseRefs() throws (testing::TestError) {
2087 2219
    {
2088 2220
        let refExpr = try! parseExprStr("&foo");
2089 2221
        let case ast::NodeValue::AddressOf(refNode) = refExpr.value
2090 2222
            else throw testing::TestError::Failed;
2091 2223
        try testing::expect(refNode.mutable == false);
lib/std/lang/resolver.rad +76 -38
14 14
// TODO: Have different types for positional vs. named field records.
15 15
16 16
use std::mem;
17 17
use std::io;
18 18
use std::lang::alloc;
19 +
use std::lang::types;
19 20
use std::lang::ast;
20 21
use std::lang::parser;
21 22
use std::lang::module;
22 23
23 24
/// Maximum number of diagnostics recorded.
276 277
    /// Range types, eg. `start..end`.
277 278
    Range {
278 279
        start: ?*Type,
279 280
        end: ?*Type,
280 281
    },
281 -
    /// Eg. `*T`.
282 +
    /// Pointer-like address.
282 283
    Pointer {
284 +
        class: types::PointerClass,
283 285
        target: *Type,
284 286
        mutable: bool,
285 287
    },
286 -
    /// Eg. `*[i32]`.
288 +
    /// Pointer-like slice.
287 289
    Slice {
290 +
        class: types::PointerClass,
288 291
        item: *Type,
289 292
        mutable: bool,
290 293
    },
291 294
    /// Eg. `[i32; 32]`.
292 295
    Array(ArrayType),
294 297
    Optional(*Type),
295 298
    /// Eg. `fn id(i32) -> i32`.
296 299
    Fn(*FnType),
297 300
    /// Named, ie. user-defined types, includes union variants.
298 301
    Nominal(*NominalType),
299 -
    /// Trait object. An erased type with v-table.
302 +
    /// An erased pointer-like type with a v-table.
300 303
    TraitObject {
304 +
        /// Ownership and safety class.
305 +
        class: types::PointerClass,
301 306
        /// Trait definition.
302 307
        traitInfo: *TraitType,
303 308
        /// Whether the pointer is mutable.
304 309
        mutable: bool,
305 310
    },
725 730
    by: MatchBy,
726 731
}
727 732
728 733
/// Unwrap a pointer type for pattern matching.
729 734
export fn unwrapMatchSubject(ty: Type) -> MatchSubject {
730 -
    if let case Type::Pointer { target, mutable } = ty {
735 +
    if let case Type::Pointer { target, mutable, .. } = ty {
731 736
        let by = MatchBy::MutRef if mutable else MatchBy::Ref;
732 737
        return MatchSubject { effectiveTy: *target, by };
733 738
    }
734 739
    return MatchSubject { effectiveTy: ty, by: MatchBy::Value };
735 740
}
1707 1712
                    }
1708 1713
                    return nil;
1709 1714
                }
1710 1715
            }
1711 1716
        }
1712 -
        case Type::Pointer { target: lhsTarget, mutable: lhsMutable } => {
1713 -
            let case Type::Pointer { target: rhsTarget, mutable: rhsMutable } = from
1717 +
        case Type::Pointer { target: lhsTarget, mutable: lhsMutable, .. } => {
1718 +
            let case Type::Pointer { target: rhsTarget, mutable: rhsMutable, .. } = from
1714 1719
                else return nil;
1715 1720
1716 1721
            // Allow coercion from `*T` to `*opaque`, and `*mut T` to `*mut opaque`.
1717 1722
            if *lhsTarget == Type::Opaque {
1718 1723
                if lhsMutable and not rhsMutable {
1735 1740
            if let case Type::Optional(fromInner) = from {
1736 1741
                return isAssignable(self, *inner, *fromInner, rval);
1737 1742
            }
1738 1743
            return nil;
1739 1744
        }
1740 -
        case Type::TraitObject { traitInfo, mutable: lhsMutable } => {
1745 +
        case Type::TraitObject {
1746 +
            class: lhsClass, traitInfo, mutable: lhsMutable,
1747 +
        } => {
1741 1748
            // Coerce `*T` or `*mut T` where `T` implements the trait.
1742 -
            if let case Type::Pointer { target, mutable: rhsMutable } = from {
1749 +
            if let case Type::Pointer { target, mutable: rhsMutable, .. } = from {
1743 1750
                if lhsMutable and not rhsMutable {
1744 1751
                    return nil;
1745 1752
                }
1746 1753
                // Look up instance registry.
1747 1754
                if let inst = findInstance(self, traitInfo, *target) {
1748 1755
                    return Coercion::TraitObject { traitInfo, inst };
1749 1756
                }
1750 1757
            }
1751 1758
            // Identity: same trait object.
1752 -
            if let case Type::TraitObject { traitInfo: rhsTrait, mutable: rhsMutable } = from {
1753 -
                if traitInfo <> rhsTrait {
1759 +
            if let case Type::TraitObject {
1760 +
                class: rhsClass, traitInfo: rhsTrait, mutable: rhsMutable,
1761 +
            } = from {
1762 +
                if lhsClass <> rhsClass or traitInfo <> rhsTrait {
1754 1763
                    return nil;
1755 1764
                }
1756 1765
                if lhsMutable and not rhsMutable {
1757 1766
                    return nil;
1758 1767
                }
1759 1768
                return Coercion::Identity;
1760 1769
            }
1761 1770
            return nil;
1762 1771
        }
1763 -
        case Type::Slice { item: lhsItem, mutable: lhsMutable } => {
1772 +
        case Type::Slice { class: lhsClass, item: lhsItem, mutable: lhsMutable } => {
1764 1773
            match from {
1765 -
                case Type::Slice { item: rhsItem, mutable: rhsMutable } => {
1774 +
                case Type::Slice { class: rhsClass, item: rhsItem, mutable: rhsMutable } => {
1775 +
                    if lhsClass <> rhsClass {
1776 +
                        return nil;
1777 +
                    }
1766 1778
                    if lhsMutable and not rhsMutable {
1767 1779
                        return nil;
1768 1780
                    }
1769 1781
                    // Allow coercion from `*[T]` to `*[opaque]`, and `*mut [T]` to `*mut [opaque]`.
1770 1782
                    if *lhsItem == Type::Opaque {
1845 1857
export fn typesEqual(a: Type, b: Type) -> bool {
1846 1858
    if a == b {
1847 1859
        return true;
1848 1860
    }
1849 1861
    match a {
1850 -
        case Type::Pointer { target: aTarget, mutable: aMutable } => {
1851 -
            let case Type::Pointer { target: bTarget, mutable: bMutable } = b else return false;
1852 -
            return aMutable == bMutable and typesEqual(*aTarget, *bTarget);
1862 +
        case Type::Pointer { class: aClass, target: aTarget, mutable: aMutable } => {
1863 +
            let case Type::Pointer { class: bClass, target: bTarget, mutable: bMutable } = b
1864 +
                else return false;
1865 +
            return aClass == bClass and aMutable == bMutable and typesEqual(*aTarget, *bTarget);
1853 1866
        }
1854 -
        case Type::Slice { item: aItem, mutable: aMutable } => {
1855 -
            let case Type::Slice { item: bItem, mutable: bMutable } = b else return false;
1856 -
            return aMutable == bMutable and typesEqual(*aItem, *bItem);
1867 +
        case Type::Slice { class: aClass, item: aItem, mutable: aMutable } => {
1868 +
            let case Type::Slice { class: bClass, item: bItem, mutable: bMutable } = b
1869 +
                else return false;
1870 +
            return aClass == bClass and aMutable == bMutable and typesEqual(*aItem, *bItem);
1857 1871
        }
1858 1872
        case Type::Array(aa) => {
1859 1873
            let case Type::Array(ab) = b else return false;
1860 1874
            return aa.length == ab.length and typesEqual(*aa.item, *ab.item);
1861 1875
        }
1892 1906
            if index >= recInfo.fields.len {
1893 1907
                return nil;
1894 1908
            }
1895 1909
            return recInfo.fields[index];
1896 1910
        }
1897 -
        case Type::Slice { item, mutable } => {
1911 +
        case Type::Slice { item, mutable, .. } => {
1898 1912
            match index {
1899 1913
                case 0 => return RecordField {
1900 1914
                    name: PTR_FIELD,
1901 -
                    fieldType: Type::Pointer { target: item, mutable },
1915 +
                    fieldType: Type::Pointer {
1916 +
                        class: types::PointerClass::Owned, target: item, mutable,
1917 +
                    },
1902 1918
                    offset: 0,
1903 1919
                },
1904 1920
                case 1 => return RecordField {
1905 1921
                    name: LEN_FIELD,
1906 1922
                    fieldType: Type::U32,
2618 2634
        case ast::NodeValue::Try(expr) => return try resolveTry(self, node, expr, hint),
2619 2635
        case ast::NodeValue::Return { value } => return try resolveReturn(self, node, value),
2620 2636
        case ast::NodeValue::Throw { expr } => return try resolveThrow(self, node, expr),
2621 2637
        case ast::NodeValue::Panic { message } => {
2622 2638
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
2639 +
                class: types::PointerClass::Owned,
2623 2640
                item: allocType(self, Type::U8),
2624 2641
                mutable: false
2625 2642
            });
2626 2643
            return setNodeType(self, node, Type::Never);
2627 2644
        },
2628 2645
        case ast::NodeValue::Assert { condition, message } => {
2629 2646
            try visit(self, condition, Type::Bool);
2630 2647
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
2648 +
                class: types::PointerClass::Owned,
2631 2649
                item: allocType(self, Type::U8),
2632 2650
                mutable: false
2633 2651
            });
2634 2652
            return setNodeType(self, node, Type::Void);
2635 2653
        },
2664 2682
        }
2665 2683
        case ast::NodeValue::String(text) => {
2666 2684
            setNodeConstValue(self, node, ConstValue::String(text));
2667 2685
            let byteTy = allocType(self, Type::U8);
2668 2686
            let sliceTy = allocType(self, Type::Slice {
2687 +
                class: types::PointerClass::Owned,
2669 2688
                item: byteTy,
2670 2689
                mutable: false,
2671 2690
            });
2672 2691
            return setNodeType(self, node, *sliceTy);
2673 2692
        },
3330 3349
            actual: traitType.methods.len as u32 + methods.len as u32,
3331 3350
        }));
3332 3351
    }
3333 3352
3334 3353
    for methodNode in methods {
3335 -
        let case ast::NodeValue::TraitMethodSig { name, receiver, sig } = methodNode.value
3354 +
        let case ast::NodeValue::TraitMethodSig { name, receiver, sig, .. } = methodNode.value
3336 3355
            else continue;
3337 3356
        let methodName = try nodeName(self, name);
3338 3357
3339 3358
        // Reject duplicate method names.
3340 3359
        if let _ = findTraitMethod(traitType, methodName) {
3342 3361
        }
3343 3362
        // Determine receiver mutability from the receiver type node
3344 3363
        // and validate that the receiver points to the declaring trait.
3345 3364
        let case ast::NodeValue::TypeSig(typeSig) = receiver.value
3346 3365
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
3347 -
        let case ast::TypeSig::Pointer { mutable, valueType } = typeSig
3366 +
        let case ast::TypeSig::Pointer { mutable, valueType, .. } = typeSig
3348 3367
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
3349 3368
        let case ast::NodeValue::TypeSig(innerSig) = valueType.value
3350 3369
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
3351 3370
        let case ast::TypeSig::Nominal(nameNode) = innerSig
3352 3371
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
3484 3503
3485 3504
        // Determine receiver mutability and validate receiver type.
3486 3505
        // The receiver must be `*Type` or `*mut Type`.
3487 3506
        let case ast::NodeValue::TypeSig(typeSig) = receiverType.value
3488 3507
            else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
3489 -
        let case ast::TypeSig::Pointer { mutable: receiverMut, valueType } = typeSig
3508 +
        let case ast::TypeSig::Pointer { mutable: receiverMut, valueType, .. } = typeSig
3490 3509
            else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
3491 3510
3492 3511
        // Validate that the receiver type annotation matches the
3493 3512
        // concrete type from the instance declaration.
3494 3513
        let annotatedTy = try infer(self, valueType);
3508 3527
        }
3509 3528
3510 3529
        // Build the function type for the instance method.
3511 3530
        // The receiver becomes the first parameter.
3512 3531
        let receiverPtrType = Type::Pointer {
3532 +
            class: types::PointerClass::Owned,
3513 3533
            target: allocType(self, concreteType),
3514 3534
            mutable: receiverMut,
3515 3535
        };
3516 3536
3517 3537
        // Validate that the instance method's signature matches the
3705 3725
    attrs: ?ast::Attributes,
3706 3726
) throws (ResolveError) {
3707 3727
    // Resolve the receiver type: must be `*Type` or `*mut Type` pointing to a
3708 3728
    // nominal type.
3709 3729
    let fullReceiverTy = try infer(self, receiverType);
3710 -
    let case Type::Pointer { target, mutable: receiverMut } = fullReceiverTy
3730 +
    let case Type::Pointer { target, mutable: receiverMut, .. } = fullReceiverTy
3711 3731
        else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
3712 3732
    let concreteType = *target;
3713 3733
    let case Type::Nominal(nominalTy) = concreteType
3714 3734
        else throw emitError(self, receiverType, ErrorKind::ExpectedRecord);
3715 3735
    try ensureNominalResolved(self, nominalTy, receiverType);
3727 3747
    let a = alloc::arenaAllocator(&mut self.arena);
3728 3748
    let mut paramTypes: *mut [*Type] = &mut [];
3729 3749
3730 3750
    // Receiver is the first parameter.
3731 3751
    let receiverPtrType = Type::Pointer {
3752 +
        class: types::PointerClass::Owned,
3732 3753
        target: allocType(self, concreteType),
3733 3754
        mutable: receiverMut,
3734 3755
    };
3735 3756
    paramTypes.append(allocType(self, receiverPtrType), a);
3736 3757
4754 4775
    throws (ResolveError)
4755 4776
{
4756 4777
    let mut bindTy = ty;
4757 4778
    match matchBy {
4758 4779
        case MatchBy::Value => {}
4759 -
        case MatchBy::Ref => set bindTy = Type::Pointer { target: allocType(self, ty), mutable: false },
4760 -
        case MatchBy::MutRef => set bindTy = Type::Pointer { target: allocType(self, ty), mutable: true },
4780 +
        case MatchBy::Ref => set bindTy = Type::Pointer {
4781 +
            class: types::PointerClass::Owned, target: allocType(self, ty), mutable: false,
4782 +
        },
4783 +
        case MatchBy::MutRef => set bindTy = Type::Pointer {
4784 +
            class: types::PointerClass::Owned, target: allocType(self, ty), mutable: true,
4785 +
        },
4761 4786
    }
4762 4787
    match binding.value {
4763 4788
        case ast::NodeValue::Placeholder => {
4764 4789
            // Nothing to do.
4765 4790
        }
4925 4950
                expected: 2,
4926 4951
                actual: args.len as u32,
4927 4952
            }));
4928 4953
        }
4929 4954
        let ptrType = try visit(self, args[0], Type::Unknown);
4930 -
        let case Type::Pointer { target, mutable } = ptrType else {
4955 +
        let case Type::Pointer { target, mutable, .. } = ptrType else {
4931 4956
            throw emitError(self, node, ErrorKind::ExpectedPointer);
4932 4957
        };
4933 4958
        let _ = try checkAssignable(self, args[1], Type::U32);
4934 4959
        if args.len == 3 {
4935 4960
            let _ = try checkAssignable(self, args[2], Type::U32);
4936 4961
        }
4937 -
        return setNodeType(self, node, Type::Slice { item: target, mutable });
4962 +
        return setNodeType(self, node, Type::Slice {
4963 +
            class: types::PointerClass::Owned, item: target, mutable,
4964 +
        });
4938 4965
    }
4939 4966
    if args.len <> 1 {
4940 4967
        throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch {
4941 4968
            expected: 1,
4942 4969
            actual: args.len as u32,
5003 5030
    // Intercept method calls on slices before inferring the callee.
5004 5031
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
5005 5032
        let parentTy = try infer(self, access.parent);
5006 5033
        let subjectTy = autoDeref(parentTy);
5007 5034
5008 -
        if let case Type::Slice { item, mutable } = subjectTy {
5035 +
        if let case Type::Slice { item, mutable, .. } = subjectTy {
5009 5036
            let methodName = try nodeName(self, access.child);
5010 5037
            if methodName == "append" {
5011 5038
                return try resolveSliceAppend(self, node, access.parent, parentTy, call.args, item, mutable);
5012 5039
            }
5013 5040
            if methodName == "delete" {
5046 5073
        if let t = typeFor(self, access.parent) {
5047 5074
            set parentTy = t;
5048 5075
        }
5049 5076
        let subjectTy = autoDeref(parentTy);
5050 5077
5051 -
        if let case Type::TraitObject { traitInfo, mutable: objMutable } = subjectTy {
5078 +
        if let case Type::TraitObject { traitInfo, mutable: objMutable, .. } = subjectTy {
5052 5079
            let methodName = try nodeName(self, access.child);
5053 5080
            let method = findTraitMethod(traitInfo, methodName)
5054 5081
                else throw emitError(self, access.child, ErrorKind::RecordFieldUnknown(methodName));
5055 5082
5056 5083
            // Reject mutable-receiver methods called on immutable trait objects.
5177 5204
                case Type::Array(a) => {
5178 5205
                    try validateArraySliceBounds(self, range, a.length, node);
5179 5206
                    set item = a.item;
5180 5207
                    set capacity = a.length;
5181 5208
                }
5182 -
                case Type::Slice { item: i, mutable } => {
5209 +
                case Type::Slice { item: i, mutable, .. } => {
5183 5210
                    if not mutable { throw emitError(self, container, ErrorKind::ImmutableBinding); }
5184 5211
                    set item = i;
5185 5212
                }
5186 5213
                else => throw emitError(self, container, ErrorKind::ExpectedIndexable),
5187 5214
            }
5682 5709
5683 5710
                return setNodeType(self, node, Type::U32);
5684 5711
            }
5685 5712
            throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName));
5686 5713
        }
5687 -
        case Type::Slice { item, mutable } => {
5714 +
        case Type::Slice { item, mutable, .. } => {
5688 5715
            let fieldNode = access.child;
5689 5716
            let fieldName = try nodeName(self, fieldNode);
5690 5717
5691 5718
            if mem::eq(fieldName, PTR_FIELD) {
5692 5719
                setRecordFieldIndex(self, fieldNode, 0);
5693 5720
                let ptrTy = Type::Pointer {
5721 +
                    class: types::PointerClass::Owned,
5694 5722
                    target: item,
5695 5723
                    mutable,
5696 5724
                };
5697 5725
                return setNodeType(self, node, ptrTy);
5698 5726
            }
5842 5870
                case Type::Array(arrayInfo) => {
5843 5871
                    try validateArraySliceBounds(self, range, arrayInfo.length, node);
5844 5872
                    set item = arrayInfo.item;
5845 5873
                    set capacity = arrayInfo.length;
5846 5874
                }
5847 -
                case Type::Slice { item: sliceItem, mutable } => {
5875 +
                case Type::Slice { item: sliceItem, mutable, .. } => {
5848 5876
                    if addr.mutable and not mutable {
5849 5877
                        throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
5850 5878
                    }
5851 5879
                    set item = sliceItem;
5852 5880
                }
5853 5881
                else => {
5854 5882
                    throw emitError(self, container, ErrorKind::ExpectedIndexable);
5855 5883
                }
5856 5884
            }
5857 -
            let sliceTy = Type::Slice { item, mutable: addr.mutable };
5885 +
            let sliceTy = Type::Slice {
5886 +
                class: types::PointerClass::Owned, item, mutable: addr.mutable,
5887 +
            };
5858 5888
            let alloc = allocType(self, sliceTy);
5859 5889
            setSliceRangeInfo(self, node, SliceRangeInfo {
5860 5890
                itemType: item,
5861 5891
                mutable: addr.mutable,
5862 5892
                capacity,
5889 5919
        match addr.target.value {
5890 5920
            case ast::NodeValue::ArrayLit(_),
5891 5921
                 ast::NodeValue::ArrayRepeatLit(_) =>
5892 5922
            {
5893 5923
                let sliceTy = Type::Slice {
5924 +
                    class: types::PointerClass::Owned,
5894 5925
                    item: arrayInfo.item,
5895 5926
                    mutable: addr.mutable,
5896 5927
                };
5897 5928
                return setNodeType(self, node, *allocType(self, sliceTy));
5898 5929
            }
5899 5930
            else => {}
5900 5931
        }
5901 5932
    }
5902 5933
    let pointerTy = Type::Pointer {
5934 +
        class: types::PointerClass::Owned,
5903 5935
        target: allocType(self, targetTy),
5904 5936
        mutable: addr.mutable,
5905 5937
    };
5906 5938
    return setNodeType(self, node, pointerTy);
5907 5939
}
6610 6642
            let item = try infer(self, itemType);
6611 6643
            let length = try checkSizeInt(self, length);
6612 6644
6613 6645
            return Type::Array(ArrayType { item: allocType(self, item), length });
6614 6646
        }
6615 -
        case ast::TypeSig::Slice { itemType, mutable } => {
6647 +
        case ast::TypeSig::Slice { class, itemType, mutable } => {
6616 6648
            let item = try infer(self, itemType);
6617 6649
            return Type::Slice {
6650 +
                class,
6618 6651
                item: allocType(self, item),
6619 6652
                mutable,
6620 6653
            };
6621 6654
        }
6622 -
        case ast::TypeSig::Pointer { valueType, mutable } => {
6655 +
        case ast::TypeSig::Pointer { class, valueType, mutable } => {
6623 6656
            let target = try infer(self, valueType);
6624 6657
            return Type::Pointer {
6658 +
                class,
6625 6659
                target: allocType(self, target),
6626 6660
                mutable,
6627 6661
            };
6628 6662
        }
6629 6663
        case ast::TypeSig::Optional { valueType } => {
6675 6709
                throwList: &throwList[..],
6676 6710
                localCount: 0,
6677 6711
            };
6678 6712
            return Type::Fn(allocFnType(self, fnType));
6679 6713
        }
6680 -
        case ast::TypeSig::TraitObject { traitName, mutable } => {
6714 +
        case ast::TypeSig::TraitObject { class, traitName, mutable } => {
6681 6715
            let sym = try resolveNamePath(self, traitName);
6682 6716
            let case SymbolData::Trait(traitInfo) = sym.data
6683 6717
                else throw emitError(self, traitName, ErrorKind::Internal);
6684 6718
            setNodeSymbol(self, traitName, sym);
6685 6719
6686 -
            return Type::TraitObject { traitInfo, mutable };
6720 +
            return Type::TraitObject {
6721 +
                class,
6722 +
                traitInfo,
6723 +
                mutable,
6724 +
            };
6687 6725
        }
6688 6726
    }
6689 6727
}
6690 6728
6691 6729
/// Check if a type can be used for inferrence.
lib/std/lang/resolver/printer.rad +3 -3
97 97
            io::print("i32");
98 98
        }
99 99
        case super::Type::I64 => {
100 100
            io::print("i64");
101 101
        }
102 -
        case super::Type::Pointer { target, mutable } => {
102 +
        case super::Type::Pointer { target, mutable, .. } => {
103 103
            printPtrPrefix(mutable);
104 104
            printTypeBody(*target, brief);
105 105
        }
106 -
        case super::Type::Slice { item, mutable } => {
106 +
        case super::Type::Slice { item, mutable, .. } => {
107 107
            printPtrPrefix(mutable);
108 108
            io::print("[");
109 109
            printTypeBody(*item, brief);
110 110
            io::print("]");
111 111
        }
146 146
                printNominalTypeName(info);
147 147
            } else {
148 148
                printNominalType(info);
149 149
            }
150 150
        }
151 -
        case super::Type::TraitObject { traitInfo, mutable } => {
151 +
        case super::Type::TraitObject { traitInfo, mutable, .. } => {
152 152
            printPtrPrefix(mutable);
153 153
            io::print("opaque ");
154 154
            io::print(traitInfo.name);
155 155
        }
156 156
        case super::Type::Range { start, end } => {
lib/std/lang/resolver/tests.rad +2 -2
398 398
}
399 399
400 400
fn expectSliceType(ty: super::Type, mutable: bool) -> super::Type
401 401
    throws (testing::TestError)
402 402
{
403 -
    let case super::Type::Slice { item, mutable: sliceMut } = ty
403 +
    let case super::Type::Slice { item, mutable: sliceMut, .. } = ty
404 404
        else throw testing::TestError::Failed;
405 405
    try testing::expect(sliceMut == mutable);
406 406
407 407
    return *item;
408 408
}
409 409
410 410
fn expectPointerType(ty: super::Type, mutable: bool) -> super::Type
411 411
    throws (testing::TestError)
412 412
{
413 -
    let case super::Type::Pointer { target, mutable: ptrMut } = ty
413 +
    let case super::Type::Pointer { target, mutable: ptrMut, .. } = ty
414 414
        else throw testing::TestError::Failed;
415 415
    try testing::expect(ptrMut == mutable);
416 416
417 417
    return *target;
418 418
}
lib/std/lang/scanner.rad +3 -2
103 103
    // Trait-related tokens.
104 104
    Trait, Instance,
105 105
106 106
    // Type-related tokens.
107 107
    I8, I16, I32, I64, U8, U16, U32, U64,
108 -
    Opaque, Fn, Bool, Union, Record, As
108 +
    Opaque, Fn, Bool, Union, Record, As, Unsafe
109 109
}
110 110
111 111
/// A reserved keyword.
112 112
record Keyword {
113 113
    /// Keyword string.
115 115
    /// Corresponding token.
116 116
    tok: TokenKind,
117 117
}
118 118
119 119
/// Sorted keyword table for binary search.
120 -
constant KEYWORDS: [Keyword; 51] = [
120 +
constant KEYWORDS: [Keyword; 52] = [
121 121
    { name: "align", tok: TokenKind::Align },
122 122
    { name: "and", tok: TokenKind::And },
123 123
    { name: "as", tok: TokenKind::As },
124 124
    { name: "assert", tok: TokenKind::Assert },
125 125
    { name: "bool", tok: TokenKind::Bool },
165 165
    { name: "u32", tok: TokenKind::U32 },
166 166
    { name: "u64", tok: TokenKind::U64 },
167 167
    { name: "u8", tok: TokenKind::U8 },
168 168
    { name: "undefined", tok: TokenKind::Undefined },
169 169
    { name: "union", tok: TokenKind::Union },
170 +
    { name: "unsafe", tok: TokenKind::Unsafe },
170 171
    { name: "use", tok: TokenKind::Use },
171 172
    { name: "while", tok: TokenKind::While },
172 173
];
173 174
174 175
/// Describes where source code originated from.
lib/std/lang/scanner/tests.rad +5 -1
222 222
        try testing::expect(super::next(&mut s).kind == expectedKind);
223 223
    }
224 224
}
225 225
226 226
@test fn testScanKeywords() throws (testing::TestError) {
227 -
    let mut s = testScanner("nil mod not static");
227 +
    let mut s = testScanner("nil mod not static unsafe");
228 228
    let tok1: super::Token = super::next(&mut s);
229 229
230 230
    try testing::expect(tok1.kind == super::TokenKind::Nil);
231 231
    try testing::expect(tok1.source.len == 3);
232 232
239 239
    try testing::expect(tok3.source.len == 3);
240 240
241 241
    let tok4: super::Token = super::next(&mut s);
242 242
    try testing::expect(tok4.kind == super::TokenKind::Static);
243 243
    try testing::expect(tok4.source.len == 6);
244 +
245 +
    let tok5: super::Token = super::next(&mut s);
246 +
    try testing::expect(tok5.kind == super::TokenKind::Unsafe);
247 +
    try testing::expect(tok5.source.len == 6);
244 248
}
245 249
246 250
@test fn testScanVoidAsIdent() throws (testing::TestError) {
247 251
    let mut s = testScanner("void");
248 252
    let tok: super::Token = super::next(&mut s);
lib/std/lang/types.rad added +11 -0
1 +
//! Shared Radiance language types.
2 +
3 +
/// Ownership and safety class for pointer-like types.
4 +
export union PointerClass {
5 +
    /// Owned pointer, eg. `*T`.
6 +
    Owned,
7 +
    /// Reference, borrowed pointer, eg. `&T`.
8 +
    Ref,
9 +
    /// Unsafe, raw pointer, eg. `*unsafe T`.
10 +
    Unsafe,
11 +
}
std.lib +1 -0
20 20
lib/std/arch/rv64/asm/scanner.rad
21 21
lib/std/arch/rv64/asm/parser.rad
22 22
lib/std/arch/rv64/asm/emit.rad
23 23
lib/std/lang.rad
24 24
lib/std/lang/alloc.rad
25 +
lib/std/lang/types.rad
25 26
lib/std/lang/strings.rad
26 27
lib/std/lang/sexpr.rad
27 28
lib/std/lang/ast.rad
28 29
lib/std/lang/ast/printer.rad
29 30
lib/std/lang/scanner.rad
test/tests/builtin.size.align.rad +0 -1
54 54
    assert @alignOf(*[u16]) == 8;
55 55
56 56
    assert @sizeOf(*mut [u8]) == 16;
57 57
    assert @alignOf(*mut [u8]) == 8;
58 58
59 -
60 59
    return 0;
61 60
}