Просмотр исходного кода

Don't produce a follow-on error message if we try to perform an impl lookup during error recovery. (#4749)

Richard Smith 1 год назад
Родитель
Сommit
4bbc189d55

+ 5 - 0
toolchain/check/impl_lookup.cpp

@@ -8,6 +8,7 @@
 #include "toolchain/check/generic.h"
 #include "toolchain/check/import_ref.h"
 #include "toolchain/sem_ir/ids.h"
+#include "toolchain/sem_ir/typed_insts.h"
 
 namespace Carbon::Check {
 
@@ -113,6 +114,10 @@ auto LookupInterfaceWitness(Context& context, SemIR::LocId loc_id,
                             SemIR::ConstantId type_const_id,
                             SemIR::ConstantId interface_const_id)
     -> SemIR::InstId {
+  if (type_const_id == SemIR::ErrorInst::SingletonConstantId ||
+      interface_const_id == SemIR::ErrorInst::SingletonConstantId) {
+    return SemIR::ErrorInst::SingletonInstId;
+  }
   auto import_irs =
       FindAssociatedImportIRs(context, type_const_id, interface_const_id);
   for (auto import_ir : import_irs) {

+ 6 - 7
toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon

@@ -11,13 +11,9 @@
 fn Main() -> i32 {
   // The following line has two mismatches, but after the first, it shouldn't
   // keep erroring.
-  // CHECK:STDERR: fail_type_mismatch_once.carbon:[[@LINE+7]]:10: error: cannot access member of interface `Core.Add` in type `Core.IntLiteral` that does not implement that interface [MissingImplInMemberAccess]
+  // CHECK:STDERR: fail_type_mismatch_once.carbon:[[@LINE+3]]:10: error: cannot access member of interface `Core.Add` in type `Core.IntLiteral` that does not implement that interface [MissingImplInMemberAccess]
   // CHECK:STDERR:   return 12 + 3.4 + 12;
   // CHECK:STDERR:          ^~~~~~~~
-  // CHECK:STDERR:
-  // CHECK:STDERR: fail_type_mismatch_once.carbon:[[@LINE+3]]:10: error: cannot access member of interface `Core.Add` in type `<error>` that does not implement that interface [MissingImplInMemberAccess]
-  // CHECK:STDERR:   return 12 + 3.4 + 12;
-  // CHECK:STDERR:          ^~~~~~~~~~~~~
   return 12 + 3.4 + 12;
 }
 
@@ -30,6 +26,7 @@ fn Main() -> i32 {
 // CHECK:STDOUT:   %Main: %Main.type = struct_value () [template]
 // CHECK:STDOUT:   %int_12: Core.IntLiteral = int_value 12 [template]
 // CHECK:STDOUT:   %float: f64 = float_literal 3.4000000000000004 [template]
+// CHECK:STDOUT:   %Op.type: type = fn_type @Op [template]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -60,9 +57,11 @@ fn Main() -> i32 {
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Main() -> %i32 {
 // CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   %int_12.loc21_10: Core.IntLiteral = int_value 12 [template = constants.%int_12]
+// CHECK:STDOUT:   %int_12.loc17_10: Core.IntLiteral = int_value 12 [template = constants.%int_12]
 // CHECK:STDOUT:   %float: f64 = float_literal 3.4000000000000004 [template = constants.%float]
-// CHECK:STDOUT:   %int_12.loc21_21: Core.IntLiteral = int_value 12 [template = constants.%int_12]
+// CHECK:STDOUT:   %int_12.loc17_21: Core.IntLiteral = int_value 12 [template = constants.%int_12]
+// CHECK:STDOUT:   %impl.elem0: %Op.type = interface_witness_access <error>, element0 [template = <error>]
+// CHECK:STDOUT:   %Op.bound: <bound method> = bound_method <error>, %impl.elem0 [template = <error>]
 // CHECK:STDOUT:   return <error>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 92 - 0
toolchain/check/testdata/operators/overloaded/fail_error_recovery.carbon

@@ -0,0 +1,92 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/operators/overloaded/fail_error_recovery.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/operators/overloaded/fail_error_recovery.carbon
+
+// Each of these should only produce one error, and shouldn't complain that
+// `<error>` doesn't implement an operator.
+
+fn F() {
+  // CHECK:STDERR: fail_error_recovery.carbon:[[@LINE+4]]:3: error: name `undeclared` not found [NameNotFound]
+  // CHECK:STDERR:   undeclared + 1;
+  // CHECK:STDERR:   ^~~~~~~~~~
+  // CHECK:STDERR:
+  undeclared + 1;
+}
+
+fn G(n: i32) {
+  // CHECK:STDERR: fail_error_recovery.carbon:[[@LINE+3]]:7: error: name `undeclared` not found [NameNotFound]
+  // CHECK:STDERR:   n + undeclared;
+  // CHECK:STDERR:       ^~~~~~~~~~
+  n + undeclared;
+}
+
+// CHECK:STDOUT: --- fail_error_recovery.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %F.type: type = fn_type @F [template]
+// CHECK:STDOUT:   %F: %F.type = struct_value () [template]
+// CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [template]
+// CHECK:STDOUT:   %Op.type.1: type = fn_type @Op.1 [template]
+// CHECK:STDOUT:   %int_32: Core.IntLiteral = int_value 32 [template]
+// CHECK:STDOUT:   %i32: type = class_type @Int, @Int(%int_32) [template]
+// CHECK:STDOUT:   %G.type: type = fn_type @G [template]
+// CHECK:STDOUT:   %G: %G.type = struct_value () [template]
+// CHECK:STDOUT:   %Op.type.14: type = fn_type @Op.2, @impl.7(%int_32) [template]
+// CHECK:STDOUT:   %Op.14: %Op.type.14 = struct_value () [template]
+// CHECK:STDOUT:   %interface.19: <witness> = interface_witness (%Op.14) [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Core: <namespace> = namespace file.%Core.import, [template] {
+// CHECK:STDOUT:     .Add = %import_ref.1
+// CHECK:STDOUT:     .Int = %import_ref.6
+// CHECK:STDOUT:     import Core//prelude
+// CHECK:STDOUT:     import Core//prelude/...
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .Core = imports.%Core
+// CHECK:STDOUT:     .F = %F.decl
+// CHECK:STDOUT:     .G = %G.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %Core.import = import Core
+// CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {}
+// CHECK:STDOUT:   %G.decl: %G.type = fn_decl @G [template = constants.%G] {
+// CHECK:STDOUT:     %n.patt: %i32 = binding_pattern n
+// CHECK:STDOUT:     %n.param_patt: %i32 = value_param_pattern %n.patt, runtime_param0
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %n.param: %i32 = value_param runtime_param0
+// CHECK:STDOUT:     %.loc22: type = splice_block %i32 [template = constants.%i32] {
+// CHECK:STDOUT:       %int_32: Core.IntLiteral = int_value 32 [template = constants.%int_32]
+// CHECK:STDOUT:       %i32: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %n: %i32 = bind_name n, %n.param
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %undeclared.ref: <error> = name_ref undeclared, <error> [template = <error>]
+// CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [template = constants.%int_1]
+// CHECK:STDOUT:   %impl.elem0: %Op.type.1 = interface_witness_access <error>, element0 [template = <error>]
+// CHECK:STDOUT:   %Op.bound: <bound method> = bound_method %undeclared.ref, %impl.elem0 [template = <error>]
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @G(%n.param_patt: %i32) {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   %n.ref: %i32 = name_ref n, %n
+// CHECK:STDOUT:   %undeclared.ref: <error> = name_ref undeclared, <error> [template = <error>]
+// CHECK:STDOUT:   %impl.elem0: %Op.type.1 = interface_witness_access constants.%interface.19, element0 [template = constants.%Op.14]
+// CHECK:STDOUT:   %Op.bound: <bound method> = bound_method %n.ref, %impl.elem0
+// CHECK:STDOUT:   return
+// CHECK:STDOUT: }
+// CHECK:STDOUT: