compiler: Share checked method and v-table name assembly

54994768e04274fa96c84baef10b385e86205697b98dca86a8109aebeec3ecba
Alexis Sellier committed ago 1 parent 72388a52
lib/std/lang/lower.rad +8 -24
1135 1135
    }
1136 1136
}
1137 1137
1138 1138
/// Build a qualified name of the form "Type::method".
1139 1139
unsafe fn instanceMethodName 'arena 'phase (self: &mut Lowerer 'arena 'phase, modId: ?u16, typeName: *[u8], methodName: *[u8]) -> *[u8] where 'arena: 'phase {
1140 -
    let sepLen: u32 = 2; // "::"
1141 -
    let totalLen = typeName.len + sepLen + methodName.len;
1142 -
    let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8];
1143 -
    let mut pos: u32 = 0;
1144 -
1145 -
    set pos += try! mem::copy(&mut buf[pos..], typeName);
1146 -
    set pos += try! mem::copy(&mut buf[pos..], "::");
1147 -
    set pos += try! mem::copy(&mut buf[pos..], methodName);
1148 -
    assert pos == totalLen;
1149 -
1150 -
    return qualifyName(self, modId, &buf[..totalLen]);
1140 +
    // "::" separates the type and method names.
1141 +
    let path = [typeName];
1142 +
    let name = il::formatQualifiedName(self.arena, &path[..], methodName);
1143 +
    return qualifyName(self, modId, name);
1151 1144
}
1152 1145
1153 1146
/// Build a v-table data name of the form "vtable::Type::Trait".
1154 1147
unsafe fn vtableName 'arena 'phase (self: &mut Lowerer 'arena 'phase, modId: ?u16, typeName: *[u8], traitName: *[u8]) -> *[u8] where 'arena: 'phase {
1155 -
    let prefix = "vtable::";
1156 -
    let sepLen: u32 = 2; // "::"
1157 -
    let totalLen = prefix.len + typeName.len + sepLen + traitName.len;
1158 -
    let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8];
1159 -
    let mut pos: u32 = 0;
1160 -
1161 -
    set pos += try! mem::copy(&mut buf[pos..], prefix);
1162 -
    set pos += try! mem::copy(&mut buf[pos..], typeName);
1163 -
    set pos += try! mem::copy(&mut buf[pos..], "::");
1164 -
    set pos += try! mem::copy(&mut buf[pos..], traitName);
1165 -
    assert pos == totalLen;
1166 -
1167 -
    return qualifyName(self, modId, &buf[..totalLen]);
1148 +
    // "::" separates the namespace, type, and trait names.
1149 +
    let path = ["vtable", typeName];
1150 +
    let name = il::formatQualifiedName(self.arena, &path[..], traitName);
1151 +
    return qualifyName(self, modId, name);
1168 1152
}
1169 1153
1170 1154
/// Lower an instance declaration (`instance Trait for Type { ... }`).
1171 1155
///
1172 1156
/// Each method in the instance block is lowered as a standalone function
test/tests/method.with.trait.rad +18 -0
20 20
    unsafe fn (w: *unsafe Widget) code() -> i32 {
21 21
        return w.x + w.y;
22 22
    }
23 23
}
24 24
25 +
/// A second implementation with a distinct method symbol and v-table.
26 +
record Counter: Copy {
27 +
    /// Value returned through dynamic dispatch.
28 +
    value: i32,
29 +
}
30 +
31 +
/// Preserve type-qualified method names for a shared trait.
32 +
instance Printable for Counter {
33 +
    /// Read the counter through its trait receiver.
34 +
    unsafe fn (counter: *unsafe Counter) code() -> i32 {
35 +
        return counter.value;
36 +
    }
37 +
}
38 +
25 39
@default unsafe fn main() -> i32 {
26 40
    let w = Widget { x: 3, y: 5 };
27 41
28 42
    // Standalone method call.
29 43
    assert w.area() == 15;
30 44
31 45
    // Trait method call via trait object.
32 46
    let p: *unsafe opaque Printable = &w;
33 47
    assert p.code() == 8;
48 +
    let counter = Counter { value: 37 };
49 +
    let other: *unsafe opaque Printable = &counter;
50 +
    assert other.code() == 37;
51 +
    assert p.code() == 8;
34 52
35 53
    return 0;
36 54
}