Pārlūkot izejas kodu

Find the builtin TypeCanAggregateDestroy in the FacetType for facet values (#6119)

When doing impl lookup with a constraint facet type including the
builtin `TypeCanAggregateDestroy`, we look at the type to see if it
satisfies it. However if the type is a facet value, we need to look at
the FacetType to see if the eventual concrete type is going to satisfy
it.

Note that we can do this check up front in the `LookupImplWitness()`
function without creating a symbolic instruction to be modified by
future specifics with a more precise type for the facet value, because
the result of `TypeCanAggregateDestroy` does not actually provide a
witness, so we don't need the final specific type.

This was noticed by removing the "shortcut" in convert for converting a
`FacetAccessType(<symbolic binding>)` to `typeof(<symbolic binding>)`.
By removing the shortcut, we go into impl lookup when checking `impl`
decls containing `TypeCanAggregateDestroy` via deduce.
Dana Jansens 7 mēneši atpakaļ
vecāks
revīzija
0c761a9a78

+ 0 - 3
toolchain/check/convert.cpp

@@ -1225,9 +1225,6 @@ static auto PerformBuiltinConversion(
       // form. We can skip past the whole impl lookup step then and do that
       // here.
       //
-      // See also test:
-      // facet_access_type_converts_back_to_original_facet_value.carbon
-      //
       // TODO: This instruction is going to become a `SymbolicBindingType`, so
       // we'll need to handle that instead.
       auto const_type_inst_id =

+ 6 - 8
toolchain/check/eval_inst.cpp

@@ -210,14 +210,12 @@ auto EvalConstantInst(Context& context, SemIR::FacetValue inst)
   if (auto access =
           context.insts().TryGetAs<SemIR::FacetAccessType>(inst.type_inst_id)) {
     auto bind_id = access->facet_value_inst_id;
-    auto bind = context.insts().Get(bind_id);
-    if (bind.Is<SemIR::BindSymbolicName>()) {
-      // If the FacetTypes are the same, then the FacetValue didn't add/remove
-      // any witnesses.
-      if (bind.type_id() == inst.type_id) {
-        return ConstantEvalResult::Existing(
-            context.constant_values().Get(bind_id));
-      }
+    auto bind = context.insts().TryGetAs<SemIR::BindSymbolicName>(bind_id);
+    // If the FacetTypes are the same, then the FacetValue didn't add/remove
+    // any witnesses.
+    if (bind.has_value() && bind->type_id == inst.type_id) {
+      return ConstantEvalResult::Existing(
+          context.constant_values().Get(bind_id));
     }
   }
 

+ 13 - 2
toolchain/check/impl_lookup.cpp

@@ -545,8 +545,19 @@ static auto GetOrAddLookupImplWitness(Context& context, SemIR::LocId loc_id,
 // Returns true if the `Self` should impl `Destroy`.
 static auto TypeCanDestroy(Context& context,
                            SemIR::ConstantId query_self_const_id) -> bool {
-  auto inst = context.insts().Get(
-      context.constant_values().GetInstId(query_self_const_id));
+  auto inst = context.insts().Get(context.constant_values().GetInstId(
+      GetCanonicalizedFacetOrTypeValue(context, query_self_const_id)));
+
+  // For facet values, look if the FacetType provides the same.
+  if (auto facet_type =
+          context.types().TryGetAs<SemIR::FacetType>(inst.type_id())) {
+    const auto& info = context.facet_types().Get(facet_type->facet_type_id);
+    if (info.builtin_constraint_mask.HasAnyOf(
+            SemIR::BuiltinConstraintMask::TypeCanDestroy)) {
+      return true;
+    }
+  }
+
   CARBON_KIND_SWITCH(inst) {
     case CARBON_KIND(SemIR::ClassType class_type): {
       auto class_info = context.classes().Get(class_type.class_id);

+ 15 - 0
toolchain/check/testdata/builtins/type/can_destroy.carbon

@@ -38,6 +38,21 @@ fn G() {
   //@dump-sem-ir-end
 }
 
+// --- symbolic.carbon
+library "[[@TEST_NAME]]";
+
+interface Z {}
+
+fn CanDestroy() -> type = "type.can_destroy";
+
+fn G(U:! CanDestroy()) {}
+
+fn F(T:! Z & CanDestroy()) {
+  // Requires a conversion (and thus impl lookup into `T`) since `T` and `U`
+  // have different (but compatible) facet types.
+  G(T);
+}
+
 // --- fail_incomplete.carbon
 library "[[@TEST_NAME]]";