ソースを参照

Propagate errors in import (#5728)

`AddImportedInstruction` was turning errors in an instruction into a
Runtime constant value instead of an Error, which led to crashes when
importing an instruction that had an error inside it somewhere.

Fixes #5726
Dana Jansens 10 ヶ月 前
コミット
fa6322dd8f

+ 3 - 3
toolchain/check/eval.cpp

@@ -891,9 +891,9 @@ auto AddImportedConstant(Context& context, SemIR::Inst inst)
                inst.kind());
   Phase phase = GetPhase(context.constant_values(),
                          context.types().GetConstantId(inst.type_id()));
-  if (!ReplaceAllFieldsWithConstantValues(eval_context, &inst, &phase)) {
-    return SemIR::ConstantId::NotConstant;
-  }
+  // We ignore the return value of ReplaceAllFieldsWithConstantValues and just
+  // propagate runtime and error constant values into the resulting ConstantId.
+  ReplaceAllFieldsWithConstantValues(eval_context, &inst, &phase);
   return MakeConstantResult(context, inst, phase);
 }
 

+ 85 - 0
toolchain/check/testdata/where_expr/constraints.carbon

@@ -127,6 +127,30 @@ fn NotEmptyStruct() {
   EmptyStruct(C);
 }
 
+// --- fail_error_in_constraint.carbon
+
+library "[[@TEST_NAME]]";
+
+//@dump-sem-ir-begin
+// CHECK:STDERR: fail_error_in_constraint.carbon:[[@LINE+4]]:41: error: name `I` not found [NameNotFound]
+// CHECK:STDERR: fn WithError(U:! type where .Self impls I);
+// CHECK:STDERR:                                         ^
+// CHECK:STDERR:
+fn WithError(U:! type where .Self impls I);
+//@dump-sem-ir-end
+
+// --- import_error_in_constraint.carbon
+
+library "[[@TEST_NAME]]";
+
+import library "error_in_constraint";
+
+fn F() {
+//@dump-sem-ir-begin
+  let x: () = WithError(());
+//@dump-sem-ir-end
+}
+
 // CHECK:STDOUT: --- state_constraints.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -303,3 +327,64 @@ fn NotEmptyStruct() {
 // CHECK:STDOUT:   %W.loc12_24.2 => constants.%W
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
+// CHECK:STDOUT: --- fail_error_in_constraint.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %.Self: type = bind_symbolic_name .Self [symbolic_self]
+// CHECK:STDOUT:   %WithError.type: type = fn_type @WithError [concrete]
+// CHECK:STDOUT:   %WithError: %WithError.type = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   %WithError.decl: %WithError.type = fn_decl @WithError [concrete = constants.%WithError] {
+// CHECK:STDOUT:     %U.patt: <error> = symbolic_binding_pattern U, 0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     %.loc9_23.1: type = splice_block %.loc9_23.2 [concrete = <error>] {
+// CHECK:STDOUT:       <elided>
+// CHECK:STDOUT:       %.Self.ref: type = name_ref .Self, %.Self [symbolic_self = constants.%.Self]
+// CHECK:STDOUT:       %I.ref: <error> = name_ref I, <error> [concrete = <error>]
+// CHECK:STDOUT:       %.loc9_23.2: type = where_expr %.Self [concrete = <error>] {
+// CHECK:STDOUT:         requirement_impls %.Self.ref, <error>
+// CHECK:STDOUT:       }
+// CHECK:STDOUT:     }
+// CHECK:STDOUT:     %U: <error> = bind_symbolic_name U, 0 [concrete = <error>]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @WithError(%U: <error>) {
+// CHECK:STDOUT:   fn();
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @WithError(<error>) {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: --- import_error_in_constraint.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %empty_tuple.type [concrete]
+// CHECK:STDOUT:   %WithError.type: type = fn_type @WithError [concrete]
+// CHECK:STDOUT:   %WithError: %WithError.type = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT:   %Main.WithError: %WithError.type = import_ref Main//error_in_constraint, WithError, loaded [concrete = constants.%WithError]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F() {
+// CHECK:STDOUT: !entry:
+// CHECK:STDOUT:   name_binding_decl {
+// CHECK:STDOUT:     %x.patt: %pattern_type = binding_pattern x [concrete]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %WithError.ref: %WithError.type = name_ref WithError, imports.%Main.WithError [concrete = constants.%WithError]
+// CHECK:STDOUT:   %.loc8_26: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:   %.loc8_11.1: type = splice_block %.loc8_11.3 [concrete = constants.%empty_tuple.type] {
+// CHECK:STDOUT:     %.loc8_11.2: %empty_tuple.type = tuple_literal ()
+// CHECK:STDOUT:     %.loc8_11.3: type = converted %.loc8_11.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %x: %empty_tuple.type = bind_name x, <error> [concrete = <error>]
+// CHECK:STDOUT:   <elided>
+// CHECK:STDOUT: }
+// CHECK:STDOUT: