Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/typecheck/step1_global_symbols.jou
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def typecheck_statement_with_symbol(stmt: AstStatement*) -> None:
stmt.symbol().signature = typecheck_signature(jou_file, &stmt.method, self_class)
case AstStatementKind.Class:
t = create_empty_class(stmt.symbol().name)
t.classdata.definition = stmt
if stmt.classdef.is_generic():
for nameptr = stmt.classdef.generic_typevar_names.ptr; nameptr < stmt.classdef.generic_typevar_names.end(); nameptr++:
t.classdata.generic_params.append(create_typevar(*nameptr))
Expand Down
59 changes: 44 additions & 15 deletions compiler/typecheck/step3_function_and_method_bodies.jou
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,49 @@ def nth(n: int) -> byte[100]:
return result


def fail_with_method_not_found(
state: State*,
location: Location,
self_class: Type*,
method_name: byte*,
) -> noreturn:
assert self_class.kind == TypeKind.Class
class_ast = self_class.classdata.definition
assert class_ast != NULL
assert class_ast.kind == AstStatementKind.Class

msg: byte[500]

# Is the method in the class definition?
for stmt = class_ast.classdef.body.ptr; stmt < class_ast.classdef.body.end(); stmt++:
if (
stmt.kind == AstStatementKind.MethodDef
and strcmp(stmt.method.ast_signature.name, method_name) == 0
and strcmp(stmt.location.path, state.jou_file.path) != 0
):
# Method exists
if stmt.symbol().public:
# TODO: generate something that can be copy/pasted to write an import statement?
snprintf(
msg, sizeof(msg),
"to use the '%s' method of class %s, you need to import the file that defines it (%s)",
method_name,
self_class.name,
stmt.location.path,
)
else:
snprintf(
msg, sizeof(msg),
"method '%s' of class %s is private (maybe add @public to it?)",
method_name,
self_class.name,
)
fail(location, msg)

snprintf(msg, sizeof(msg), "class %s has no method named '%s'", self_class.name, method_name)
fail(location, msg)


# This is for code that looks like obj.member(). It could be a method call or a
# function pointer call, because `obj` may have a field whose type is funcptr.
#
Expand Down Expand Up @@ -684,21 +727,7 @@ def typecheck_member_that_looks_like_method(state: State*, call: AstCall*) -> Ty

field = self_class.find_class_field(member_name)
if field == NULL:
# TODO: better error messages!!!!!
big_msg: byte* = NULL
asprintf(
&big_msg,
"method '%s' not found in class %s. The problem is ONE of the following: 1) you didn't import the file that defines class %.*s, 2) the '%s' method is private, 3) there really is no such method in class %.*s. I know that this is a bad compiler error message, and I will later split this into 3 different error messages.",
member_name,
self_class.name,
strcspn(self_class.name, "[") as int, # List[int] --> List
self_class.name,
member_name,
strcspn(self_class.name, "[") as int, # List[int] --> List
self_class.name,
)
assert big_msg != NULL
fail(func_location, big_msg)
fail_with_method_not_found(state, func_location, self_class, member_name)

# It is a function pointer call where the function is in a class field.
# It looks like obj.field().
Expand Down
1 change: 1 addition & 0 deletions compiler/types.jou
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class ClassField:
class ClassData:
generic_params: List[Type*] # this is the "int" part of List[int]
fields: List[ClassField]
definition: AstStatement*

@public
def is_generic(self) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion tests/404/import_private_method.jou
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ import "./imported/privates.jou"
def foo() -> None:
p = PublicClass{}
# TODO: ideally error message would say that it exists but is private
p.private_method() # Error: method 'private_method' not found in class PublicClass. The problem is ONE of the following: 1) you didn't import the file that defines class PublicClass, 2) the 'private_method' method is private, 3) there really is no such method in class PublicClass. I know that this is a bad compiler error message, and I will later split this into 3 different error messages.
p.private_method() # Error: method 'private_method' of class PublicClass is private (maybe add @public to it?)
3 changes: 1 addition & 2 deletions tests/404/indirect_import_method.jou
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ import "./imported/point_factory.jou"

def blah() -> int:
p = make_point()
# TODO: Improve this error!
return p.get_sum() # Error: method 'get_sum' not found in class Point. The problem is ONE of the following: 1) you didn't import the file that defines class Point, 2) the 'get_sum' method is private, 3) there really is no such method in class Point. I know that this is a bad compiler error message, and I will later split this into 3 different error messages.
return p.get_sum() # Error: to use the 'get_sum' method of class Point, you need to import the file that defines it (tests/404/imported/point.jou)
2 changes: 1 addition & 1 deletion tests/404/method.jou
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ class Foo:

def main() -> int:
f = Foo{x=1}
f.bar() # Error: method 'bar' not found in class Foo. The problem is ONE of the following: 1) you didn't import the file that defines class Foo, 2) the 'bar' method is private, 3) there really is no such method in class Foo. I know that this is a bad compiler error message, and I will later split this into 3 different error messages.
f.bar() # Error: class Foo has no method named 'bar'