Support for type-checking and lowering method calls. (#3343)

Adds a `BoundMethod` SemIR node to represent an `x.F` bound method, with
a new builtin type `BoundMethodType`. Reorganized conversion of call
expression arguments to also check and convert a `self` parameter in the
implicit parameters list.

In passing, improved diagnostics and error recovery for bad call
expressions. We now build a `call` node with the appropriate type and
value category, but with invalid arguments, if the argument conversion
failed, and diagnose calls to non-callable expressions.

`addr self` methods don't work properly yet; the `addr` is ignored for
now.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2023-10-27 20:41:13 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent c3e5721886
commit 57f3c553b8
29 changed files with 493 additions and 165 deletions
@@ -5,9 +5,9 @@
// AUTOUPDATE
fn Run() {
// CHECK:STDERR: fail_not_callable.carbon:[[@LINE+3]]:24: ERROR: Semantics TODO: `Not a callable name`.
// CHECK:STDERR: fail_not_callable.carbon:[[@LINE+3]]:23: ERROR: Value of type `String` is not callable.
// CHECK:STDERR: var x: i32 = "hello"();
// CHECK:STDERR: ^
// CHECK:STDERR: ^
var x: i32 = "hello"();
}
@@ -81,16 +81,22 @@ fn Main() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Run0.ref.loc18: <function> = name_reference "Run0", file.%Run0
// CHECK:STDOUT: %.loc18_8: i32 = int_literal 1
// CHECK:STDOUT: %.loc18_7: type = tuple_type ()
// CHECK:STDOUT: %.loc18_7.1: type = tuple_type ()
// CHECK:STDOUT: %.loc18_7.2: init () = call %Run0.ref.loc18(<invalid>)
// CHECK:STDOUT: %Run0.ref.loc25: <function> = name_reference "Run0", file.%Run0
// CHECK:STDOUT: %.loc25_8: i32 = int_literal 0
// CHECK:STDOUT: %.loc25_11: i32 = int_literal 1
// CHECK:STDOUT: %.loc25_7: init () = call %Run0.ref.loc25(<invalid>)
// CHECK:STDOUT: %Run1.ref.loc33: <function> = name_reference "Run1", file.%Run1
// CHECK:STDOUT: %.loc33: init () = call %Run1.ref.loc33(<invalid>)
// CHECK:STDOUT: %Run1.ref.loc40: <function> = name_reference "Run1", file.%Run1
// CHECK:STDOUT: %.loc40_8: i32 = int_literal 0
// CHECK:STDOUT: %.loc40_11: i32 = int_literal 1
// CHECK:STDOUT: %.loc40_7: init () = call %Run1.ref.loc40(<invalid>)
// CHECK:STDOUT: %Run2.ref.loc48: <function> = name_reference "Run2", file.%Run2
// CHECK:STDOUT: %.loc48: init () = call %Run2.ref.loc48(<invalid>)
// CHECK:STDOUT: %Run2.ref.loc55: <function> = name_reference "Run2", file.%Run2
// CHECK:STDOUT: %.loc55: i32 = int_literal 0
// CHECK:STDOUT: %.loc55_8: i32 = int_literal 0
// CHECK:STDOUT: %.loc55_7: init () = call %Run2.ref.loc55(<invalid>)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -30,6 +30,7 @@ fn F() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %G.ref: <function> = name_reference "G", file.%G
// CHECK:STDOUT: %.loc16_5: f64 = real_literal 10e-1
// CHECK:STDOUT: %.loc16_4: type = tuple_type ()
// CHECK:STDOUT: %.loc16_4.1: type = tuple_type ()
// CHECK:STDOUT: %.loc16_4.2: init () = call %G.ref(<invalid>)
// CHECK:STDOUT: return
// CHECK:STDOUT: }