Implement super-traits

f952258ddd11d6a3288b4bc6670babf692ade8be9f23e36d41e31a05b26bb214
Alexis Sellier committed ago 1 parent 71eb3015
lib/std/arch/rv64/tests/trait.supertrait.rad added +114 -0
1 +
//! Test supertrait bounds: a trait that requires its implementors to also
2 +
//! implement another trait.
3 +
//!
4 +
//! Exercises: trait Reader with a `read` method, trait Writer with a `write`
5 +
//! method, and trait ReadWriter: Reader + Writer that combines both.
6 +
//! A Socket type implements all three. Coercing a `*opaque ReadWriter` to
7 +
//! `*opaque Reader` or `*opaque Writer` should work, and dispatching through
8 +
//! any of the three trait objects should call the correct methods.
9 +
10 +
trait Reader {
11 +
    fn (*mut Reader) read(buf: *mut [u8]) -> i32;
12 +
}
13 +
14 +
trait Writer {
15 +
    fn (*mut Writer) write(data: *[u8]) -> i32;
16 +
}
17 +
18 +
trait ReadWriter: Reader + Writer {
19 +
    fn (*mut ReadWriter) flush() -> i32;
20 +
}
21 +
22 +
record Socket {
23 +
    rbuf: [u8; 32],
24 +
    rpos: i32,
25 +
    rlen: i32,
26 +
    wbuf: [u8; 32],
27 +
    wpos: i32,
28 +
}
29 +
30 +
instance Reader for Socket {
31 +
    fn (s: *mut Socket) read(buf: *mut [u8]) -> i32 {
32 +
        let mut i: u32 = 0;
33 +
        while i < buf.len and s.rpos < s.rlen {
34 +
            buf[i] = s.rbuf[s.rpos as u32];
35 +
            s.rpos = s.rpos + 1;
36 +
            i = i + 1;
37 +
        }
38 +
        return i as i32;
39 +
    }
40 +
}
41 +
42 +
instance Writer for Socket {
43 +
    fn (s: *mut Socket) write(data: *[u8]) -> i32 {
44 +
        let mut i: u32 = 0;
45 +
        while i < data.len {
46 +
            if s.wpos >= 32 {
47 +
                return s.wpos;
48 +
            }
49 +
            s.wbuf[s.wpos as u32] = data[i];
50 +
            s.wpos = s.wpos + 1;
51 +
            i = i + 1;
52 +
        }
53 +
        return s.wpos;
54 +
    }
55 +
}
56 +
57 +
instance ReadWriter for Socket {
58 +
    fn (s: *mut Socket) flush() -> i32 {
59 +
        let pos = s.wpos;
60 +
        s.wpos = 0;
61 +
        return pos;
62 +
    }
63 +
}
64 +
65 +
@default fn main() -> i32 {
66 +
    let mut sock = Socket {
67 +
        rbuf: undefined,
68 +
        rpos: 0,
69 +
        rlen: 5,
70 +
        wbuf: undefined,
71 +
        wpos: 0,
72 +
    };
73 +
    // Pre-fill the read buffer with "hello".
74 +
    sock.rbuf[0] = 'h' as u8;
75 +
    sock.rbuf[1] = 'e' as u8;
76 +
    sock.rbuf[2] = 'l' as u8;
77 +
    sock.rbuf[3] = 'l' as u8;
78 +
    sock.rbuf[4] = 'o' as u8;
79 +
80 +
    // Test 1: Use as ReadWriter trait object.
81 +
    let rw: *mut opaque ReadWriter = &mut sock;
82 +
83 +
    // Test 2: Write through the ReadWriter (dispatches via Writer supertrait).
84 +
    let wn = rw.write("abc");
85 +
    if wn != 3 {
86 +
        return 1;
87 +
    }
88 +
    if sock.wpos != 3 {
89 +
        return 2;
90 +
    }
91 +
92 +
    // Test 3: Read through the ReadWriter (dispatches via Reader supertrait).
93 +
    let mut rbuf: [u8; 8] = undefined;
94 +
    let rn = rw.read(&mut rbuf[0..8]);
95 +
    if rn != 5 {
96 +
        return 3;
97 +
    }
98 +
    if rbuf[0] != 'h' as u8 {
99 +
        return 4;
100 +
    }
101 +
    if rbuf[4] != 'o' as u8 {
102 +
        return 5;
103 +
    }
104 +
105 +
    // Test 4: Call ReadWriter's own method.
106 +
    let flushed = rw.flush();
107 +
    if flushed != 3 {
108 +
        return 6;
109 +
    }
110 +
    if sock.wpos != 0 {
111 +
        return 7;
112 +
    }
113 +
    return 0;
114 +
}
lib/std/lang/ast.rad +2 -0
818 818
    CatchClause(CatchClause),
819 819
    /// Trait declaration.
820 820
    TraitDecl {
821 821
        /// Trait name identifier.
822 822
        name: *Node,
823 +
        /// Supertrait name nodes.
824 +
        supertraits: NodeList,
823 825
        /// Method signature nodes ([`TraitMethodSig`]).
824 826
        methods: NodeList,
825 827
        /// Optional attributes.
826 828
        attrs: ?Attributes,
827 829
    },
lib/std/lang/resolver.rad +41 -5
48 48
49 49
/// Trait definition stored in the resolver.
50 50
pub record TraitType {
51 51
    /// Trait name.
52 52
    name: *[u8],
53 -
    /// Method signatures.
53 +
    /// Method signatures, including from supertraits.
54 54
    methods: [TraitMethod; ast::MAX_TRAIT_METHODS],
55 55
    /// Number of methods.
56 56
    methodsLen: u32,
57 57
    /// Supertraits that must also be implemented.
58 58
    supertraits: [*TraitType; ast::MAX_SUPERTRAITS],
3306 3306
    let sym = symbolFor(self, node)
3307 3307
        else return;
3308 3308
    let case SymbolData::Trait(traitType) = sym.data
3309 3309
        else return;
3310 3310
3311 -
    if methods.len > traitType.methods.len {
3311 +
    // Resolve supertrait bounds and copy their methods into this trait.
3312 +
    for i in 0..supertraits.len {
3313 +
        if traitType.supertraitsLen >= traitType.supertraits.len {
3314 +
            throw emitError(self, node, ErrorKind::Internal);
3315 +
        }
3316 +
        let superNode = supertraits.list[i];
3317 +
        let superSym = try resolveNamePath(self, superNode);
3318 +
        let case SymbolData::Trait(superTrait) = superSym.data
3319 +
            else throw emitError(self, superNode, ErrorKind::Internal);
3320 +
        try setNodeSymbol(self, superNode, superSym);
3321 +
3322 +
        if traitType.methodsLen + superTrait.methodsLen > ast::MAX_TRAIT_METHODS {
3323 +
            throw emitError(self, node, ErrorKind::TraitMethodOverflow(CountMismatch {
3324 +
                expected: ast::MAX_TRAIT_METHODS,
3325 +
                actual: traitType.methodsLen + superTrait.methodsLen,
3326 +
            }));
3327 +
        }
3328 +
        // Copy inherited methods into this trait's method table.
3329 +
        for j in 0..superTrait.methodsLen {
3330 +
            let inherited = superTrait.methods[j];
3331 +
            if let _ = findTraitMethod(traitType, inherited.name) {
3332 +
                throw emitError(self, superNode, ErrorKind::DuplicateBinding(inherited.name));
3333 +
            }
3334 +
            traitType.methods[traitType.methodsLen] = TraitMethod {
3335 +
                name: inherited.name,
3336 +
                fnType: inherited.fnType,
3337 +
                mutable: inherited.mutable,
3338 +
                index: traitType.methodsLen,
3339 +
            };
3340 +
            traitType.methodsLen += 1;
3341 +
        }
3342 +
        traitType.supertraits[traitType.supertraitsLen] = superTrait;
3343 +
        traitType.supertraitsLen += 1;
3344 +
    }
3345 +
3346 +
    if traitType.methodsLen + methods.len > ast::MAX_TRAIT_METHODS {
3312 3347
        throw emitError(self, node, ErrorKind::TraitMethodOverflow(CountMismatch {
3313 -
            expected: traitType.methods.len,
3314 -
            actual: methods.len,
3348 +
            expected: ast::MAX_TRAIT_METHODS,
3349 +
            actual: traitType.methodsLen + methods.len,
3315 3350
        }));
3316 3351
    }
3352 +
3317 3353
    for i in 0..methods.len {
3318 3354
        let methodNode = methods.list[i];
3319 3355
        let case ast::NodeValue::TraitMethodSig { name, receiver, sig } = methodNode.value
3320 3356
            else continue;
3321 3357
        let methodName = try nodeName(self, name);
3322 3358
3323 -
        // Reject duplicate method names within the same trait.
3359 +
        // Reject duplicate method names.
3324 3360
        if let _ = findTraitMethod(traitType, methodName) {
3325 3361
            throw emitError(self, name, ErrorKind::DuplicateBinding(methodName));
3326 3362
        }
3327 3363
3328 3364
        // Determine receiver mutability from the receiver type node