Skip to content

Commit

Permalink
Improve error messages related to . and -> (#626)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli authored Jan 15, 2025
1 parent 0f631b2 commit 5f42184
Show file tree
Hide file tree
Showing 21 changed files with 82 additions and 51 deletions.
44 changes: 28 additions & 16 deletions compiler/typecheck/step3_function_and_method_bodies.jou
Original file line number Diff line number Diff line change
Expand Up @@ -569,22 +569,12 @@ def typecheck_function_or_method_call(ft: FileTypes*, call: AstCall*, self_type:
if sig == NULL:
if self_type == NULL:
snprintf(msg, sizeof(msg), "function '%s' not found", call->name)
elif self_type->kind == TypeKind.Class:
else:
assert self_type->kind == TypeKind.Class
snprintf(
msg, sizeof(msg),
"class %s does not have a method named '%s'",
self_type->name, call->name)
elif self_type->kind == TypeKind.Pointer and self_type->value_type->find_method(call->name) != NULL:
snprintf(
msg, sizeof(msg),
"the method '%s' is defined on class %s, not on the pointer type %s, so you need to dereference the pointer first (e.g. by using '->' instead of '.')",
call->name, self_type->value_type->name, self_type->name)
else:
snprintf(
msg, sizeof(msg),
"type %s does not have any methods because it is %s, not a class",
self_type->name, self_type->short_description())

fail(location, msg)

if self_type == NULL:
Expand Down Expand Up @@ -884,17 +874,25 @@ def typecheck_expression(ft: FileTypes*, expr: AstExpression*) -> None:
if temptype->kind != TypeKind.Pointer or temptype->value_type->kind != TypeKind.Class:
snprintf(
msg, sizeof(msg),
"left side of the '->' operator must be a pointer to a class, not %s",
"left side of '->' operator must be a pointer to an instance of a class, not %s",
temptype->name)
if temptype->kind == TypeKind.Class and strlen(msg) + 50 < sizeof(msg):
strcat(msg, " (try . instead of ->)")
fail(expr->location, msg)
result = typecheck_class_field(temptype->value_type, expr->class_field.field_name, expr->location)->type
else:
temptype = typecheck_expression_not_void(ft, expr->class_field.instance)
if temptype->kind != TypeKind.Class:
snprintf(
msg, sizeof(msg),
"left side of the '.' operator must be an instance of a class, not %s",
"left side of '.' operator must be an instance of a class, not %s",
temptype->name)
if (
temptype->kind == TypeKind.Pointer
and temptype->value_type->kind == TypeKind.Class
and strlen(msg) + 50 < sizeof(msg)
):
strcat(msg, " (try -> instead of .)")
fail(expr->location, msg)
result = typecheck_class_field(temptype, expr->class_field.field_name, expr->location)->type

Expand All @@ -903,14 +901,28 @@ def typecheck_expression(ft: FileTypes*, expr: AstExpression*) -> None:
result = typecheck_function_or_method_call(ft, &expr->call, NULL, expr->location)
elif expr->call.uses_arrow_operator:
temptype = typecheck_expression_not_void(ft, expr->call.method_call_self)
if temptype->kind != TypeKind.Pointer:
if temptype->kind != TypeKind.Pointer or temptype->value_type->kind != TypeKind.Class:
snprintf(msg, sizeof(msg),
"left side of the '->' operator must be a pointer, not %s",
"left side of '->' operator must be a pointer to an instance of a class, not %s",
temptype->name)
if temptype->kind == TypeKind.Class and strlen(msg) + 50 < sizeof(msg):
strcat(msg, " (try . instead of ->)")
fail(expr->location, msg)
result = typecheck_function_or_method_call(ft, &expr->call, temptype->value_type, expr->location)
else:
temptype = typecheck_expression_not_void(ft, expr->call.method_call_self)
if temptype->kind != TypeKind.Class:
snprintf(msg, sizeof(msg),
"left side of '.' operator must be an instance of a class, not %s",
temptype->name)
if (
temptype->kind == TypeKind.Pointer
and temptype->value_type->kind == TypeKind.Class
and strlen(msg) + 50 < sizeof(msg)
):
strcat(msg, " (try -> instead of .)")
fail(expr->location, msg)

result = typecheck_function_or_method_call(ft, &expr->call, temptype, expr->location)

# If self argument is passed by pointer, make sure we can create that pointer
Expand Down
7 changes: 0 additions & 7 deletions tests/404/method_on_class_ptr.jou

This file was deleted.

2 changes: 0 additions & 2 deletions tests/404/method_on_int.jou

This file was deleted.

2 changes: 0 additions & 2 deletions tests/already_exists_error/bool.jou

This file was deleted.

11 changes: 0 additions & 11 deletions tests/other_errors/method_on_ptr_called_on_class.jou

This file was deleted.

7 changes: 7 additions & 0 deletions tests/wrong_type/arrow_instead_of_dot.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Foo:
n: int


def blah() -> None:
f = Foo{}
f->n++ # Error: left side of '->' operator must be a pointer to an instance of a class, not Foo (try . instead of ->)
7 changes: 7 additions & 0 deletions tests/wrong_type/arrow_instead_of_dot_call.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Foo:
n: int


def blah() -> None:
f = Foo{}
f->do_stuff() # Error: left side of '->' operator must be a pointer to an instance of a class, not Foo (try . instead of ->)
3 changes: 3 additions & 0 deletions tests/wrong_type/arrow_operator_int.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def foo() -> None:
num = 1
x = num->lol # Error: left side of '->' operator must be a pointer to an instance of a class, not int
3 changes: 3 additions & 0 deletions tests/wrong_type/arrow_operator_int_call.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def foo() -> None:
num = 1
x = num->lol() # Error: left side of '->' operator must be a pointer to an instance of a class, not int
4 changes: 4 additions & 0 deletions tests/wrong_type/arrow_operator_intptr.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def foo() -> None:
num = 1
pointer = &num
x = pointer->lol # Error: left side of '->' operator must be a pointer to an instance of a class, not int*
4 changes: 4 additions & 0 deletions tests/wrong_type/arrow_operator_intptr_call.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def foo() -> None:
num = 1
pointer = &num
x = pointer->lol() # Error: left side of '->' operator must be a pointer to an instance of a class, not int*
4 changes: 0 additions & 4 deletions tests/wrong_type/arrow_operator_not_class.jou

This file was deleted.

3 changes: 0 additions & 3 deletions tests/wrong_type/arrow_operator_not_pointer.jou

This file was deleted.

3 changes: 0 additions & 3 deletions tests/wrong_type/arrow_operator_not_pointer_method.jou

This file was deleted.

6 changes: 6 additions & 0 deletions tests/wrong_type/dot_instead_of_arrow.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Foo:
n: int


def blah(ptr: Foo*) -> None:
ptr.n++ # Error: left side of '.' operator must be an instance of a class, not Foo* (try -> instead of .)
6 changes: 6 additions & 0 deletions tests/wrong_type/dot_instead_of_arrow_call.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Foo:
n: int


def blah(ptr: Foo*) -> None:
ptr.foo() # Error: left side of '.' operator must be an instance of a class, not Foo* (try -> instead of .)
3 changes: 0 additions & 3 deletions tests/wrong_type/dot_operator.jou

This file was deleted.

3 changes: 3 additions & 0 deletions tests/wrong_type/dot_operator_int.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def foo() -> None:
x = 123
y = x.lolwat # Error: left side of '.' operator must be an instance of a class, not int
3 changes: 3 additions & 0 deletions tests/wrong_type/dot_operator_int_call.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def foo() -> None:
x = 123
y = x.lolwat() # Error: left side of '.' operator must be an instance of a class, not int
4 changes: 4 additions & 0 deletions tests/wrong_type/dot_operator_intptr.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def foo() -> None:
x = 123
y = &x
z = y.lolwat # Error: left side of '.' operator must be an instance of a class, not int*
4 changes: 4 additions & 0 deletions tests/wrong_type/dot_operator_intptr_call.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def foo() -> None:
x = 123
y = &x
z = y.lolwat() # Error: left side of '.' operator must be an instance of a class, not int*

0 comments on commit 5f42184

Please sign in to comment.