Implement unused pattern bindings, continued (#6518)

Implementation of unused pattern bindings #2022, continued.

Whereas previous PR #6460 took care of parsing, and PR #6479 prepared
the stage by using _ in some test cases, this PR has the the actual
implementation, using a simple dataflow analysis.

---------

Co-authored-by: Burak Emir <bqe@google.com>
Co-authored-by: jonmeow <jperkins@google.com>
This commit is contained in:
Burak Emir
2026-02-19 23:33:36 +00:00
committed by GitHub
co-authored by Burak Emir jonmeow
parent bea24a8bee
commit fdb188ccfd
366 changed files with 8453 additions and 7996 deletions
@@ -16,7 +16,7 @@
library "[[@TEST_NAME]]";
fn F(T:! type) {
fn F(unused T:! type) {
}
fn G(T:! type) {
@@ -43,14 +43,15 @@ fn H() {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %type: type = facet_type <type> [concrete]
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self]
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic]
// CHECK:STDOUT: %T.67db0b.1: type = symbolic_binding T, 0 [symbolic]
// CHECK:STDOUT: %pattern_type: type = pattern_type type [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: %T.67db0b.2: type = symbolic_binding T, 0 [symbolic]
// CHECK:STDOUT: %G.type: type = fn_type @G [concrete]
// CHECK:STDOUT: %G: %G.type = struct_value () [concrete]
// CHECK:STDOUT: %F.specific_fn: <specific function> = specific_function %F, @F(%T) [symbolic]
// CHECK:STDOUT: %F.specific_fn: <specific function> = specific_function %F, @F(%T.67db0b.2) [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -62,18 +63,18 @@ fn H() {
// CHECK:STDOUT: %T.patt: %pattern_type = symbolic_binding_pattern T, 0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
// CHECK:STDOUT: %T.loc4_6.2: type = symbolic_binding T, 0 [symbolic = %T.loc4_6.1 (constants.%T)]
// CHECK:STDOUT: %T.loc4_13.2: type = symbolic_binding T, 0 [symbolic = %T.loc4_13.1 (constants.%T.67db0b.1)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [concrete = constants.%G] {
// CHECK:STDOUT: %T.patt: %pattern_type = symbolic_binding_pattern T, 0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
// CHECK:STDOUT: %T.loc7_6.2: type = symbolic_binding T, 0 [symbolic = %T.loc7_6.1 (constants.%T)]
// CHECK:STDOUT: %T.loc7_6.2: type = symbolic_binding T, 0 [symbolic = %T.loc7_6.1 (constants.%T.67db0b.2)]
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @F(%T.loc4_6.2: type) {
// CHECK:STDOUT: %T.loc4_6.1: type = symbolic_binding T, 0 [symbolic = %T.loc4_6.1 (constants.%T)]
// CHECK:STDOUT: generic fn @F(%T.loc4_13.2: type) {
// CHECK:STDOUT: %T.loc4_13.1: type = symbolic_binding T, 0 [symbolic = %T.loc4_13.1 (constants.%T.67db0b.1)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT:
@@ -84,7 +85,7 @@ fn H() {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @G(%T.loc7_6.2: type) {
// CHECK:STDOUT: %T.loc7_6.1: type = symbolic_binding T, 0 [symbolic = %T.loc7_6.1 (constants.%T)]
// CHECK:STDOUT: %T.loc7_6.1: type = symbolic_binding T, 0 [symbolic = %T.loc7_6.1 (constants.%T.67db0b.2)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %F.specific_fn.loc8_3.2: <specific function> = specific_function constants.%F, @F(%T.loc7_6.1) [symbolic = %F.specific_fn.loc8_3.2 (constants.%F.specific_fn)]
@@ -92,21 +93,25 @@ fn H() {
// CHECK:STDOUT: fn() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F]
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc7_6.2 [symbolic = %T.loc7_6.1 (constants.%T)]
// CHECK:STDOUT: %F.specific_fn.loc8_3.1: <specific function> = specific_function %F.ref, @F(constants.%T) [symbolic = %F.specific_fn.loc8_3.2 (constants.%F.specific_fn)]
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc7_6.2 [symbolic = %T.loc7_6.1 (constants.%T.67db0b.2)]
// CHECK:STDOUT: %F.specific_fn.loc8_3.1: <specific function> = specific_function %F.ref, @F(constants.%T.67db0b.2) [symbolic = %F.specific_fn.loc8_3.2 (constants.%F.specific_fn)]
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.specific_fn.loc8_3.1()
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F(constants.%T) {
// CHECK:STDOUT: %T.loc4_6.1 => constants.%T
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: specific @F(constants.%T.67db0b.1) {
// CHECK:STDOUT: %T.loc4_13.1 => constants.%T.67db0b.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @G(constants.%T) {
// CHECK:STDOUT: %T.loc7_6.1 => constants.%T
// CHECK:STDOUT: specific @G(constants.%T.67db0b.2) {
// CHECK:STDOUT: %T.loc7_6.1 => constants.%T.67db0b.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F(constants.%T.67db0b.2) {
// CHECK:STDOUT: %T.loc4_13.1 => constants.%T.67db0b.2
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- user.carbon
@@ -120,19 +125,20 @@ fn H() {
// CHECK:STDOUT: %H: %H.type = struct_value () [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic]
// CHECK:STDOUT: %T.67db0b.1: type = symbolic_binding T, 0 [symbolic]
// CHECK:STDOUT: %F.specific_fn.540: <specific function> = specific_function %F, @F(%C) [concrete]
// CHECK:STDOUT: %G.type: type = fn_type @G [concrete]
// CHECK:STDOUT: %G: %G.type = struct_value () [concrete]
// CHECK:STDOUT: %F.specific_fn.643: <specific function> = specific_function %F, @F(%T) [symbolic]
// CHECK:STDOUT: %T.67db0b.2: type = symbolic_binding T, 0 [symbolic]
// CHECK:STDOUT: %F.specific_fn.643: <specific function> = specific_function %F, @F(%T.67db0b.2) [symbolic]
// CHECK:STDOUT: %G.specific_fn: <specific function> = specific_function %G, @G(%C) [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Main.F: %F.type = import_ref Main//library, F, loaded [concrete = constants.%F]
// CHECK:STDOUT: %Main.G: %G.type = import_ref Main//library, G, loaded [concrete = constants.%G]
// CHECK:STDOUT: %Main.import_ref.b3bc94.1: type = import_ref Main//library, loc4_6, loaded [symbolic = @F.%T (constants.%T)]
// CHECK:STDOUT: %Main.import_ref.b3bc94.2: type = import_ref Main//library, loc7_6, loaded [symbolic = @G.%T (constants.%T)]
// CHECK:STDOUT: %Main.import_ref.b3bc94.1: type = import_ref Main//library, loc4_13, loaded [symbolic = @F.%T (constants.%T.67db0b.1)]
// CHECK:STDOUT: %Main.import_ref.b3bc94.2: type = import_ref Main//library, loc7_6, loaded [symbolic = @G.%T (constants.%T.67db0b.2)]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -169,7 +175,7 @@ fn H() {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @F(imports.%Main.import_ref.b3bc94.1: type) [from "library.carbon"] {
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T.67db0b.1)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT:
@@ -177,7 +183,7 @@ fn H() {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @G(imports.%Main.import_ref.b3bc94.2: type) [from "library.carbon"] {
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T.67db0b.2)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %F.specific_fn: <specific function> = specific_function constants.%F, @F(%T) [symbolic = %F.specific_fn (constants.%F.specific_fn.643)]
@@ -185,10 +191,8 @@ fn H() {
// CHECK:STDOUT: fn;
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F(constants.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: specific @F(constants.%T.67db0b.1) {
// CHECK:STDOUT: %T => constants.%T.67db0b.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F(constants.%C) {
@@ -197,8 +201,14 @@ fn H() {
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @G(constants.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: specific @F(constants.%T.67db0b.2) {
// CHECK:STDOUT: %T => constants.%T.67db0b.2
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @G(constants.%T.67db0b.2) {
// CHECK:STDOUT: %T => constants.%T.67db0b.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @G(constants.%C) {