Implement super-traits
f952258ddd11d6a3288b4bc6670babf692ade8be9f23e36d41e31a05b26bb214
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 |