Supertraits

71eb30159d5f00353ec0c5ff3b4f8f127b853450975d238c73bf571190eb16b4
Alexis Sellier committed ago 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");