Supertraits
71eb30159d5f00353ec0c5ff3b4f8f127b853450975d238c73bf571190eb16b4
1 parent
4fd4c947
lib/std/lang/ast.rad
+3 -0
| 6 | 6 | use std::lang::alloc; |
|
| 7 | 7 | ||
| 8 | 8 | /// Maximum number of trait methods. |
|
| 9 | 9 | pub const MAX_TRAIT_METHODS: u32 = 8; |
|
| 10 | 10 | ||
| 11 | + | /// Maximum number of supertraits. |
|
| 12 | + | pub const MAX_SUPERTRAITS: u32 = 4; |
|
| 13 | + | ||
| 11 | 14 | /// Arena for all parser allocations. |
|
| 12 | 15 | /// |
|
| 13 | 16 | /// Uses a bump allocator for both AST nodes and node pointer arrays. |
|
| 14 | 17 | pub record NodeArena { |
|
| 15 | 18 | /// Bump allocator for all allocations. |
lib/std/lang/ast/printer.rad
+3 -2
| 436 | 436 | } |
|
| 437 | 437 | case super::NodeValue::UnionDeclVariant(v) => { |
|
| 438 | 438 | return variantToExpr(a, v.name, v.type); |
|
| 439 | 439 | } |
|
| 440 | 440 | case super::NodeValue::ExprStmt(e) => return toExpr(a, e), |
|
| 441 | - | case super::NodeValue::TraitDecl { name, methods, .. } => { |
|
| 441 | + | case super::NodeValue::TraitDecl { name, supertraits, methods, .. } => { |
|
| 442 | 442 | let children = nodeListToExprs(a, &methods); |
|
| 443 | - | return sexpr::block(a, "trait", &[toExpr(a, name)], children); |
|
| 443 | + | let supers = sexpr::list(a, "supertraits", nodeListToExprs(a, &supertraits)); |
|
| 444 | + | return sexpr::block(a, "trait", &[toExpr(a, name), supers], children); |
|
| 444 | 445 | } |
|
| 445 | 446 | case super::NodeValue::TraitMethodSig { name, receiver, sig } => { |
|
| 446 | 447 | let params = sexpr::list(a, "params", nodeListToExprs(a, &sig.params)); |
|
| 447 | 448 | let ret = toExprOrNull(a, sig.returnType); |
|
| 448 | 449 | return sexpr::list(a, "methodSig", &[toExpr(a, receiver), toExpr(a, name), params, ret]); |
lib/std/lang/lower.rad
+14 -1
| 1108 | 1108 | ||
| 1109 | 1109 | let tName = traitSym.name; |
|
| 1110 | 1110 | let typeName = typeSym.name; |
|
| 1111 | 1111 | ||
| 1112 | 1112 | // Lower each instance method as a regular function. |
|
| 1113 | - | // Collect qualified names for the v-table. |
|
| 1113 | + | // Collect qualified names for the v-table. Empty entries are filled |
|
| 1114 | + | // later from inherited supertrait methods. |
|
| 1114 | 1115 | let mut methodNames: [*[u8]; ast::MAX_TRAIT_METHODS] = undefined; |
|
| 1116 | + | let mut methodNameSet: [bool; ast::MAX_TRAIT_METHODS] = [false; ast::MAX_TRAIT_METHODS]; |
|
| 1115 | 1117 | ||
| 1116 | 1118 | for i in 0..methods.len { |
|
| 1117 | 1119 | let methodNode = methods.list[i]; |
|
| 1118 | 1120 | let case ast::NodeValue::InstanceMethodDecl { |
|
| 1119 | 1121 | name, receiverName, receiverType, sig, body |
| 1158 | 1160 | ||
| 1159 | 1161 | let method = resolver::findTraitMethod(traitInfo, mName) |
|
| 1160 | 1162 | else panic "lowerInstanceDecl: method not found in trait"; |
|
| 1161 | 1163 | ||
| 1162 | 1164 | methodNames[method.index] = qualName; |
|
| 1165 | + | methodNameSet[method.index] = true; |
|
| 1166 | + | } |
|
| 1167 | + | ||
| 1168 | + | // Fill inherited method slots from supertraits. |
|
| 1169 | + | // These methods were already lowered as part of the supertrait instance |
|
| 1170 | + | // declarations and use the same `Type::method` qualified name. |
|
| 1171 | + | for i in 0..traitInfo.methodsLen { |
|
| 1172 | + | if not methodNameSet[i] { |
|
| 1173 | + | let mName = traitInfo.methods[i].name; |
|
| 1174 | + | methodNames[i] = instanceMethodName(self, nil, typeName, mName); |
|
| 1175 | + | } |
|
| 1163 | 1176 | } |
|
| 1164 | 1177 | ||
| 1165 | 1178 | // Create v-table in data section, used for dynamic dispatch. |
|
| 1166 | 1179 | let vName = vtableName(self, nil, typeName, tName); |
|
| 1167 | 1180 | let values = try! alloc::allocSlice( |
lib/std/lang/parser.rad
+2 -1
| 2311 | 2311 | fn parseTraitDecl(p: *mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2312 | 2312 | throws (ParseError) |
|
| 2313 | 2313 | { |
|
| 2314 | 2314 | try expect(p, scanner::TokenKind::Trait, "expected `trait`"); |
|
| 2315 | 2315 | let name = try parseIdent(p, "expected trait name"); |
|
| 2316 | + | let supertraits = try parseDerives(p); |
|
| 2316 | 2317 | try expect(p, scanner::TokenKind::LBrace, "expected `{` after trait name"); |
|
| 2317 | 2318 | ||
| 2318 | 2319 | let mut methods = ast::nodeList(p.arena, ast::MAX_TRAIT_METHODS); |
|
| 2319 | 2320 | while not check(p, scanner::TokenKind::RBrace) and |
|
| 2320 | 2321 | not check(p, scanner::TokenKind::Eof) |
| 2322 | 2323 | let method = try parseTraitMethodSig(p); |
|
| 2323 | 2324 | ast::nodeListPush(&mut methods, method); |
|
| 2324 | 2325 | } |
|
| 2325 | 2326 | try expect(p, scanner::TokenKind::RBrace, "expected `}` after trait methods"); |
|
| 2326 | 2327 | ||
| 2327 | - | return node(p, ast::NodeValue::TraitDecl { name, methods, attrs }); |
|
| 2328 | + | return node(p, ast::NodeValue::TraitDecl { name, supertraits, methods, attrs }); |
|
| 2328 | 2329 | } |
|
| 2329 | 2330 | ||
| 2330 | 2331 | /// Parse a trait method signature. |
|
| 2331 | 2332 | /// Syntax: `fn (*Trait) fnord(<params>) -> ReturnType;` |
|
| 2332 | 2333 | fn parseTraitMethodSig(p: *mut Parser) -> *ast::Node |
lib/std/lang/resolver.rad
+27 -5
| 52 | 52 | name: *[u8], |
|
| 53 | 53 | /// Method signatures. |
|
| 54 | 54 | methods: [TraitMethod; ast::MAX_TRAIT_METHODS], |
|
| 55 | 55 | /// Number of methods. |
|
| 56 | 56 | methodsLen: u32, |
|
| 57 | + | /// Supertraits that must also be implemented. |
|
| 58 | + | supertraits: [*TraitType; ast::MAX_SUPERTRAITS], |
|
| 59 | + | /// Number of supertraits. |
|
| 60 | + | supertraitsLen: u32, |
|
| 57 | 61 | } |
|
| 58 | 62 | ||
| 59 | 63 | /// A single method signature within a trait. |
|
| 60 | 64 | pub record TraitMethod { |
|
| 61 | 65 | /// Method name. |
| 565 | 569 | FnParamOverflow(CountMismatch), |
|
| 566 | 570 | /// Function declaration has too many throws. |
|
| 567 | 571 | FnThrowOverflow(CountMismatch), |
|
| 568 | 572 | /// Trait declaration has too many methods. |
|
| 569 | 573 | TraitMethodOverflow(CountMismatch), |
|
| 574 | + | /// Instance declaration is missing a required supertrait instance. |
|
| 575 | + | MissingSupertraitInstance(*[u8]), |
|
| 570 | 576 | /// Internal error. |
|
| 571 | 577 | Internal, |
|
| 572 | 578 | } |
|
| 573 | 579 | ||
| 574 | 580 | /// Fixed-capacity diagnostic sink. |
| 3258 | 3264 | ||
| 3259 | 3265 | /// Allocate a trait type descriptor and return a pointer to it. |
|
| 3260 | 3266 | fn allocTraitType(self: *mut Resolver, name: *[u8]) -> *mut TraitType { |
|
| 3261 | 3267 | let p = try! alloc::alloc(&mut self.arena, @sizeOf(TraitType), @alignOf(TraitType)); |
|
| 3262 | 3268 | let entry = p as *mut TraitType; |
|
| 3263 | - | *entry = TraitType { name, methods: undefined, methodsLen: 0 }; |
|
| 3269 | + | *entry = TraitType { name, methods: undefined, methodsLen: 0, supertraits: undefined, supertraitsLen: 0 }; |
|
| 3264 | 3270 | ||
| 3265 | 3271 | return entry; |
|
| 3266 | 3272 | } |
|
| 3267 | 3273 | ||
| 3268 | 3274 | /// Bind a trait name in the current scope. |
| 3291 | 3297 | } |
|
| 3292 | 3298 | } |
|
| 3293 | 3299 | return nil; |
|
| 3294 | 3300 | } |
|
| 3295 | 3301 | ||
| 3296 | - | /// Resolve a trait declaration body, ie. the method signatures. |
|
| 3297 | - | fn resolveTraitBody(self: *mut Resolver, node: *ast::Node, methods: *ast::NodeList) |
|
| 3302 | + | /// Resolve a trait declaration body: supertrait methods, then own methods. |
|
| 3303 | + | fn resolveTraitBody(self: *mut Resolver, node: *ast::Node, supertraits: *ast::NodeList, methods: *ast::NodeList) |
|
| 3298 | 3304 | throws (ResolveError) |
|
| 3299 | 3305 | { |
|
| 3300 | 3306 | let sym = symbolFor(self, node) |
|
| 3301 | 3307 | else return; |
|
| 3302 | 3308 | let case SymbolData::Trait(traitType) = sym.data |
| 3559 | 3565 | entry.methodsLen += 1; |
|
| 3560 | 3566 | ||
| 3561 | 3567 | covered[tm.index] = true; |
|
| 3562 | 3568 | } |
|
| 3563 | 3569 | ||
| 3570 | + | // Fill inherited method slots from supertrait instances. |
|
| 3571 | + | for si in 0..traitInfo.supertraitsLen { |
|
| 3572 | + | let superTrait = traitInfo.supertraits[si]; |
|
| 3573 | + | let superInst = findInstance(self, superTrait, concreteType) |
|
| 3574 | + | else throw emitError(self, node, ErrorKind::MissingSupertraitInstance(superTrait.name)); |
|
| 3575 | + | for mi in 0..superTrait.methodsLen { |
|
| 3576 | + | let merged = findTraitMethod(traitInfo, superTrait.methods[mi].name) |
|
| 3577 | + | else panic "resolveInstanceDecl: inherited method not found"; |
|
| 3578 | + | if not covered[merged.index] { |
|
| 3579 | + | entry.methods[merged.index] = superInst.methods[mi]; |
|
| 3580 | + | entry.methodsLen += 1; |
|
| 3581 | + | covered[merged.index] = true; |
|
| 3582 | + | } |
|
| 3583 | + | } |
|
| 3584 | + | } |
|
| 3585 | + | ||
| 3564 | 3586 | // Check that all trait methods are implemented. |
|
| 3565 | 3587 | for i in 0..traitInfo.methodsLen { |
|
| 3566 | 3588 | if not covered[i] { |
|
| 3567 | 3589 | throw emitError(self, node, ErrorKind::MissingTraitMethod(traitInfo.methods[i].name)); |
|
| 3568 | 3590 | } |
| 6051 | 6073 | case ast::NodeValue::UnionDecl(decl) => { |
|
| 6052 | 6074 | try resolveUnionBody(self, node, decl) catch { |
|
| 6053 | 6075 | // Continue resolving other types even if one fails. |
|
| 6054 | 6076 | }; |
|
| 6055 | 6077 | } |
|
| 6056 | - | case ast::NodeValue::TraitDecl { methods, .. } => { |
|
| 6057 | - | try resolveTraitBody(self, node, &methods) catch { |
|
| 6078 | + | case ast::NodeValue::TraitDecl { supertraits, methods, .. } => { |
|
| 6079 | + | try resolveTraitBody(self, node, &supertraits, &methods) catch { |
|
| 6058 | 6080 | // Continue resolving other types even if one fails. |
|
| 6059 | 6081 | }; |
|
| 6060 | 6082 | } |
|
| 6061 | 6083 | else => { |
|
| 6062 | 6084 | // Ignore other declarations. |
lib/std/lang/resolver/printer.rad
+5 -0
| 585 | 585 | io::print("too many trait methods: maximum "); |
|
| 586 | 586 | io::printU32(mismatch.expected); |
|
| 587 | 587 | io::print(", got "); |
|
| 588 | 588 | io::printU32(mismatch.actual); |
|
| 589 | 589 | } |
|
| 590 | + | case super::ErrorKind::MissingSupertraitInstance(name) => { |
|
| 591 | + | io::print("missing instance for supertrait '"); |
|
| 592 | + | io::print(name); |
|
| 593 | + | io::print("'"); |
|
| 594 | + | } |
|
| 590 | 595 | case super::ErrorKind::Internal => { |
|
| 591 | 596 | io::print("internal compiler error"); |
|
| 592 | 597 | } |
|
| 593 | 598 | case super::ErrorKind::RecordFieldOutOfOrder { .. } => { |
|
| 594 | 599 | io::print("record field out of order"); |