Skip to content

Commit fd1cfe0

Browse files
committed
Work on interfaces
1 parent 0f4da76 commit fd1cfe0

4 files changed

Lines changed: 235 additions & 35 deletions

File tree

src/compiler.pr

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4909,7 +4909,9 @@ export def walk_expression(node: &parser::Node, state: &State) -> Value {
49094909
case parser::NodeKind::RANGE, parser::NodeKind::RANGE_INC
49104910
case parser::NodeKind::LAMBDA
49114911
expr = walk_Lambda(node, state)
4912-
case;
4912+
case parser::NodeKind::IMPLEMENTS
4913+
// Do nothing
4914+
case
49134915
error(node.kind, "\n")
49144916
assert(false)
49154917
}
@@ -9425,8 +9427,7 @@ export def predeclare_functions(module: &toolchain::Module) {
94259427

94269428
def generate_vtable_function(function: &Function, fdef: typechecking::FunctionDef, state: &State) {
94279429
let ftpe = fdef.to_type().resolve()
9428-
let first_param = (ftpe.parameter_t(0)).tpe
9429-
let intf = typechecking::get_interface(first_param)
9430+
let first_param = ftpe.parameter_t(0).tpe
94309431

94319432
function.block = make_block()
94329433
function.forward_declare = false
@@ -9461,7 +9462,7 @@ def generate_vtable_function(function: &Function, fdef: typechecking::FunctionDe
94619462
let keys = map::keys(typechecking::type_registry)
94629463
for var i in 0..keys.size {
94639464
let type_entry = typechecking::type_registry(keys(i))
9464-
if is_ref(type_entry.tpe) and typechecking::implements(type_entry, intf, state.scope) {
9465+
if is_ref(type_entry.tpe) and typechecking::implements(type_entry, first_param, state.scope) {
94659466
// FIXME This whole branch isn't working yet because interfaces don't work right now
94669467
let hash = type_entry.id
94679468
if hashes.contains(hash) { continue }

src/consteval.pr

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,21 @@ def walk_Assert(node: &parser::Node, state: &typechecking::State) {
10951095
walk(node, msg, state)
10961096
}
10971097

1098+
def walk_Implements(node: &parser::Node, state: &typechecking::State) {
1099+
walk(node, node.value.impl.left, state)
1100+
walk(node, node.value.impl.right, state)
1101+
1102+
let scpe = scope::enter_scope(state.scope)
1103+
let prev_scope = state.scope
1104+
1105+
state.scope = scpe
1106+
let left = typechecking::type_lookup(node.value.impl.left, state)
1107+
let right = typechecking::type_lookup(node.value.impl.right, state)
1108+
state.scope = prev_scope
1109+
1110+
scope::create_impl(state.scope, node.value.impl.share, left, right, node)
1111+
}
1112+
10981113
def walk_top(parent: &parser::Node, node: &parser::Node, state: &typechecking::State) {
10991114
node.parent = parent
11001115
node.module = state.module
@@ -1181,6 +1196,8 @@ def do_walk(node: &parser::Node, state: &typechecking::State) {
11811196
walk_From(node, state)
11821197
case parser::NodeKind::LAMBDA
11831198
walk_Lambda(node, state)
1199+
case parser::NodeKind::IMPLEMENTS
1200+
walk_Implements(node, state)
11841201
}
11851202
}
11861203

src/scope.pr

Lines changed: 160 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ export def find_references_to(value: &Value) -> &Vector(parser::SourceLoc) {
219219
return res
220220
}
221221

222+
export type Impl = struct {
223+
share: parser::ShareMarker
224+
module: weak &toolchain::Module
225+
left: &typechecking::TypeRef
226+
right: &typechecking::TypeRef
227+
node: weak &parser::Node
228+
}
229+
222230
export type ReExport = struct {
223231
module: weak &toolchain::Module
224232
pattern: &parser::Node
@@ -244,6 +252,7 @@ export type Scope = struct {
244252
re_exports: &Vector(ReExport)
245253
// Polymorphic instances
246254
polymorphics: &SMap(&Scope)
255+
impls: &Vector(&Impl)
247256
}
248257

249258
export def print_scope(scope: &Scope) {
@@ -398,7 +407,8 @@ export def enter_scope(parents: &Vector(weak &Scope), module: &toolchain::Module
398407
fields = map::make(type &Value),
399408
implicits = vector::make(type &Value),
400409
underscore_count = 0,
401-
is_global = is_global
410+
is_global = is_global,
411+
impls = vector::make(type &Impl)
402412
] !&Scope
403413
let function_parent = get_function_parent(s)
404414
if function_parent {
@@ -424,7 +434,8 @@ export def enter_function_scope(scope: &Scope, module: &toolchain::Module, is_gl
424434
implicits = vector::make(type &Value),
425435
is_function = true,
426436
is_global = is_global,
427-
scope_count = 0
437+
scope_count = 0,
438+
impls = vector::make(type &Impl)
428439
] !&Scope
429440
}
430441

@@ -1941,6 +1952,153 @@ export def create_type(
19411952
return create_type(scope, name_node, share, tpe, Phase::COMPILED, null)
19421953
}
19431954

1955+
export def create_impl(
1956+
scope: &Scope, share: parser::ShareMarker, left: &typechecking::TypeRef, right: &typechecking::TypeRef, node: &parser::Node) {
1957+
1958+
let impl = [
1959+
share = share,
1960+
module = scope.module,
1961+
left = left,
1962+
right = right,
1963+
node = node
1964+
] !&Impl
1965+
1966+
// We resolve all types conditionally here to make sure
1967+
// that the equality check doesn't fail. If one of the types
1968+
// is a forward declared type, it will be resolved later
1969+
// and the equality check looks at the patterns
1970+
1971+
if left.resolve(scope, error_on_fail = false) {
1972+
right.resolve(scope, error_on_fail = false)
1973+
}
1974+
1975+
for var impl in scope.impls {
1976+
if impl.left.resolve(scope, error_on_fail = false) {
1977+
impl.right.resolve(scope, error_on_fail = false)
1978+
}
1979+
if impl.left == left and impl.right == right {
1980+
errors::errorn(node, "Duplicate impl for `", typechecking::generic_to_string(left), "`")
1981+
return
1982+
}
1983+
}
1984+
1985+
scope.impls.push(impl)
1986+
}
1987+
1988+
def all_impl(scope: &Scope) -> &Vector(&Impl) {
1989+
let vec = vector::make(&Impl)
1990+
all_impl(scope, scope.module, vec)
1991+
return vec
1992+
}
1993+
1994+
def all_impl(scope: &Scope, module: &toolchain::Module, all: &Vector(&Impl)) {
1995+
if not scope { return}
1996+
if scope.imports {
1997+
for var imp in scope.imports {
1998+
all_impl(imp.module.scope, module, all)
1999+
}
2000+
}
2001+
for var parent in scope.parents {
2002+
all_impl(parent, module, all)
2003+
}
2004+
for var impl in scope.impls {
2005+
// Don't include impls from other modules, unless they are exported
2006+
if module != scope.module and not (impl.share !int & parser::ShareMarker::EXPORT !int) {
2007+
continue
2008+
}
2009+
all.push(impl)
2010+
}
2011+
}
2012+
2013+
2014+
// This gets called whenever we create new types to
2015+
// generate concrete implementations for polymorphic functions so that
2016+
// the interface call is able to find them.
2017+
export def trigger_impl(scope: &Scope, tpe: &typechecking::Type) {
2018+
let impls = all_impl(scope)
2019+
for var impl in impls {
2020+
let temp_scope = enter_scope(scope)
2021+
// TODO score of 1 is hardcoded, we need to check if the resulting type is actually the same
2022+
if typechecking::convert_type_score(impl.left, tpe, temp_scope) <= 1 {
2023+
// The type matches, now get the right hand side
2024+
let right = impl.right.copy().resolve(temp_scope).resolve()
2025+
// We don't give errors in static context
2026+
if not right {
2027+
if not consteval::is_static {
2028+
errors::errorn(impl.node, "Couldn't resolve implemented type `", typechecking::generic_to_string(impl.right), "`")
2029+
}
2030+
continue
2031+
}
2032+
if right.implementors and right.implementors.contains(tpe.id) {
2033+
continue
2034+
}
2035+
// Check if we have an interface on the right hand side
2036+
if not (right.kind == typechecking::TypeKind::INTERFACE or
2037+
(right.kind == typechecking::TypeKind::REFERENCE and
2038+
right.tpe and right.tpe.resolve().kind == typechecking::TypeKind::INTERFACE)) {
2039+
2040+
errors::errorn(impl.node, "Right hand side of impl must be an interface, got `", debug::type_to_str(right), "`")
2041+
continue
2042+
}
2043+
2044+
// Lookup all functions in interface
2045+
var intf = right
2046+
if right.kind == typechecking::TypeKind::REFERENCE {
2047+
intf = right.tpe.resolve()
2048+
}
2049+
2050+
var cnt = true
2051+
for var member in intf.members {
2052+
let parameter_t = vector::make(typechecking::NamedParameter)
2053+
parameter_t.push([tpe = tpe.id] !typechecking::NamedParameter)
2054+
for var param in member.parameter_t {
2055+
parameter_t.push(param)
2056+
}
2057+
let name_node = parser::make_identifier(member.name)
2058+
let fun = get_function(impl.module.scope, name_node, parameter_t, dry_run = true)
2059+
var res = fun != null
2060+
2061+
if res {
2062+
if fun.fdef.return_t.length != member.return_t.length {
2063+
res = false
2064+
} else {
2065+
let ftpe = fun.fdef.to_type().resolve()
2066+
for var i in 0..fun.fdef.return_t.length {
2067+
if not typechecking::equals(ftpe.return_t(i), member.return_t(i)){
2068+
res = false
2069+
break
2070+
}
2071+
}
2072+
}
2073+
}
2074+
2075+
if not res {
2076+
if not consteval::is_static {
2077+
errors::errorn(impl.node, "Type `", typechecking::type_to_str(tpe), "` doesn't implement member `", member.name, "` of interface `", debug::type_to_str(right), "`")
2078+
}
2079+
cnt = false
2080+
break
2081+
}
2082+
}
2083+
2084+
if not cnt {
2085+
continue
2086+
}
2087+
2088+
if not right.implementors {
2089+
right.implementors = set::make(typechecking::TypeId)
2090+
}
2091+
right.implementors.add(tpe.id)
2092+
2093+
if not tpe.implements {
2094+
tpe.implements = set::make(typechecking::TypeId)
2095+
}
2096+
tpe.implements.add(right.id)
2097+
}
2098+
}
2099+
}
2100+
2101+
19442102
export def enter_namespace(scope: &Scope, scope2: &Scope, node: &parser::Node) -> &Value {
19452103

19462104
scope = create_path(scope, node)

0 commit comments

Comments
 (0)