瀏覽代碼

Avoid a crash when the type of Self in an interface or constraint is an error (#6443)

The RequireImpls handler needs to deal with this gracefully.
Dana Jansens 5 月之前
父節點
當前提交
25536cab67
共有 2 個文件被更改,包括 62 次插入1 次删除
  1. 5 1
      toolchain/check/handle_require.cpp
  2. 57 0
      toolchain/check/testdata/impl/impl_as_named_constraint.carbon

+ 5 - 1
toolchain/check/handle_require.cpp

@@ -69,8 +69,12 @@ auto HandleParseNode(Context& context, Parse::RequireDefaultSelfImplsId node_id)
 
   auto self_inst_id = lookup_result.target_inst_id();
   auto self_type_id = context.insts().Get(self_inst_id).type_id();
-  CARBON_CHECK(context.types().Is<SemIR::FacetType>(self_type_id));
+  if (self_type_id == SemIR::ErrorInst::TypeId) {
+    context.node_stack().Push(node_id, SemIR::ErrorInst::TypeInstId);
+    return true;
+  }
 
+  CARBON_CHECK(context.types().Is<SemIR::FacetType>(self_type_id));
   auto self_facet_as_type = AddTypeInst<SemIR::FacetAccessType>(
       context, node_id,
       {.type_id = SemIR::TypeType::TypeId,

+ 57 - 0
toolchain/check/testdata/impl/impl_as_named_constraint.carbon

@@ -148,3 +148,60 @@ impl () as B((), {}) {}
 // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~
 // CHECK:STDERR:
 impl () as A({}) {}
+
+// --- fail_error_self_in_require.carbon
+library "[[@TEST_NAME]]";
+
+interface A(T:! type) {}
+
+// This makes the type of `Self` into an ErrorInst. No `require` is added to
+// the constraint.
+//@dump-sem-ir-begin
+//
+// CHECK:STDERR: fail_error_self_in_require.carbon:[[@LINE+4]]:18: error: name `Undefined` not found [NameNotFound]
+// CHECK:STDERR: constraint B(X:! Undefined) {
+// CHECK:STDERR:                  ^~~~~~~~~
+// CHECK:STDERR:
+constraint B(X:! Undefined) {
+  extend require impls A(X);
+}
+//@dump-sem-ir-end
+
+impl () as B(1) {}
+
+// CHECK:STDOUT: --- fail_error_self_in_require.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %B.type: type = generic_named_constaint_type @B [concrete]
+// CHECK:STDOUT:   %empty_struct: %B.type = struct_value () [concrete]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: imports {
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   %B.decl: %B.type = constraint_decl @B [concrete = constants.%empty_struct] {
+// CHECK:STDOUT:     %X.patt: <error> = symbolic_binding_pattern X, 0 [concrete]
+// CHECK:STDOUT:   } {
+// CHECK:STDOUT:     <elided>
+// CHECK:STDOUT:     %X: <error> = symbolic_binding X, 0 [concrete = <error>]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic constraint @B(%X: <error>) {
+// CHECK:STDOUT: !definition:
+// CHECK:STDOUT:
+// CHECK:STDOUT:   constraint {
+// CHECK:STDOUT:     %Self: <error> = symbolic_binding Self, 1 [concrete = <error>]
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !members:
+// CHECK:STDOUT:     .Self = %Self
+// CHECK:STDOUT:     .A = <poisoned>
+// CHECK:STDOUT:     .X = <poisoned>
+// CHECK:STDOUT:
+// CHECK:STDOUT:   !requires:
+// CHECK:STDOUT:   }
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: specific @B(<error>) {}
+// CHECK:STDOUT: