Semantic analysis for if expressions (#2893)

Add semantic analysis and semantics IR building for `if` expressions, and add the first parts of control flow handling to semantics IR. After discussion with @chandlerc, use [block arguments](https://en.wikipedia.org/wiki/Static_single-assignment_form#Block_arguments) to convey values from the two arms of the `if` to the result. For now, only a single block argument is supported, but we should revisit this as we explore more of the requirements of the Semantics IR form.

Functions can now contain multiple code blocks, so grab the entry block up-front instead of assuming the entry block will be at the top of the block stack when we reach the end of function emission.

Add trivial support for `bool` type literal, because without it we can't write testcases.
This commit is contained in:
Richard Smith
2023-06-13 14:38:27 -07:00
committed by GitHub
parent 9606ce2127
commit 202d3f5993
43 changed files with 646 additions and 161 deletions
@@ -5,10 +5,10 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block3, body: block0},
// CHECK:STDOUT: {name: str4, param_refs: block5, body: block0},
// CHECK:STDOUT: {name: str5, param_refs: block0, body: block6},
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block2},
// CHECK:STDOUT: {name: str2, param_refs: block4, body: block5},
// CHECK:STDOUT: {name: str4, param_refs: block7, body: block8},
// CHECK:STDOUT: {name: str5, param_refs: block0, body: block9},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -66,6 +66,8 @@
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
@@ -73,6 +75,8 @@
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+6,
@@ -83,6 +87,8 @@
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+10,
// CHECK:STDOUT: node+11,
// CHECK:STDOUT: node+12,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -46,6 +46,8 @@
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str3, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str4, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str3, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str4, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -50,7 +50,7 @@
// CHECK:STDOUT: {kind: StubReference, arg0: node+16, type: type0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int5, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+18, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -73,6 +73,8 @@
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+8,
// CHECK:STDOUT: node+9,
// CHECK:STDOUT: node+10,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -29,7 +29,7 @@
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+4, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -46,6 +46,8 @@
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+6,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -30,10 +30,10 @@
// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function1},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+4, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+7, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block7, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -50,6 +50,8 @@
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: node+6,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -35,7 +35,7 @@
// CHECK:STDOUT: {kind: StubReference, arg0: node+6, type: type0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -55,6 +55,8 @@
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str3, param_refs: block0, body: block5},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: 1,
@@ -37,12 +37,12 @@
// CHECK:STDOUT: {kind: StubReference, arg0: node+6, type: type0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int2, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+11, type: type0},
// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int3, type: type0},
// CHECK:STDOUT: {kind: StubReference, arg0: node+13, type: type0},
// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: function0},
// CHECK:STDOUT: {kind: Call, arg0: block7, arg1: function0},
// CHECK:STDOUT: ]
// CHECK:STDOUT: node_blocks: [
// CHECK:STDOUT: [
@@ -62,6 +62,8 @@
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+6,
// CHECK:STDOUT: node+7,
// CHECK:STDOUT: node+8,
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block0, body: block2},
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block2},
// CHECK:STDOUT: {name: str1, param_refs: block0, body: block3},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -32,6 +32,8 @@
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -42,6 +42,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
// CHECK:STDERR: fail_param_name_conflict.carbon:[[@LINE+2]]:16: Redefining a in the same scope.
@@ -5,9 +5,9 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block2},
// CHECK:STDOUT: {name: str1, param_refs: block0, body: block3},
// CHECK:STDOUT: {name: str2, param_refs: block0, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -34,6 +34,12 @@
// CHECK:STDOUT: node+1,
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo() {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -37,6 +37,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32) {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -37,6 +37,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+2,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32,) {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -43,6 +43,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32, b: i32) {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block2, body: block4},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -43,6 +43,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32, b: i32,) {}
@@ -5,7 +5,7 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block0},
// CHECK:STDOUT: {name: str0, param_refs: block0, body: block2},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -26,6 +26,8 @@
// CHECK:STDOUT: [
// CHECK:STDOUT: node+0,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo() {}
@@ -5,8 +5,8 @@
// AUTOUPDATE
// CHECK:STDOUT: cross_reference_irs_size: 1
// CHECK:STDOUT: functions: [
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block0},
// CHECK:STDOUT: {name: str2, param_refs: block5, body: block0},
// CHECK:STDOUT: {name: str1, param_refs: block2, body: block4},
// CHECK:STDOUT: {name: str2, param_refs: block6, body: block7},
// CHECK:STDOUT: ]
// CHECK:STDOUT: integer_literals: [
// CHECK:STDOUT: ]
@@ -44,12 +44,16 @@
// CHECK:STDOUT: node+5,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+3,
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: node+4,
// CHECK:STDOUT: ],
// CHECK:STDOUT: [
// CHECK:STDOUT: ],
// CHECK:STDOUT: ]
fn Foo(a: i32) {}