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

Import the full NamedConstraint from its decl (#6311)

This imports the entire `NamedConstraint` structure when importing
`NamedConstraintDecl`. This will be required to identify a facet type
that contains a named constraint, as we will need to pull the `require`
decls out of the `NamedConstraint` structure to do so.

I tried making the `InterfaceDecl` code path
[templated](https://github.com/carbon-language/carbon-lang/pull/6308#discussion_r2482655927)
to reuse it, but it was a lot of template parameters including field
pointers into `InterfaceDecl`, `GenericInterfaceType`,
`SpecificInterface`, and it was very hard to read so I gave up on that
approach here.
Dana Jansens 6 месяцев назад
Родитель
Сommit
30c3a35776

+ 166 - 3
toolchain/check/import_ref.cpp

@@ -264,6 +264,9 @@ class ImportContext {
   auto import_interfaces() -> const SemIR::InterfaceStore& {
     return import_ir().interfaces();
   }
+  auto import_named_constraints() -> const SemIR::NamedConstraintStore& {
+    return import_ir().named_constraints();
+  }
   auto import_ints() -> const SharedValueStores::IntStore& {
     return import_ir().ints();
   }
@@ -337,6 +340,9 @@ class ImportContext {
   auto local_interfaces() -> SemIR::InterfaceStore& {
     return local_ir().interfaces();
   }
+  auto local_named_constraints() -> SemIR::NamedConstraintStore& {
+    return local_ir().named_constraints();
+  }
   auto local_ints() -> SharedValueStores::IntStore& {
     return local_ir().ints();
   }
@@ -2521,7 +2527,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
   const auto& import_interface =
       resolver.import_interfaces().Get(inst.interface_id);
 
-  SemIR::InterfaceId interface_id = SemIR::InterfaceId::None;
+  auto interface_id = SemIR::InterfaceId::None;
   if (!interface_const_id.has_value()) {
     auto import_specific_id = SemIR::SpecificId::None;
     if (auto import_generic_interface_type =
@@ -2598,6 +2604,162 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
   return ResolveResult::Done(interface_const_id, new_interface.first_decl_id());
 }
 
+// Make a declaration of a named constraint. This is done as a separate step
+// from importing the constraint definition in order to resolve cycles.
+static auto MakeNamedConstraintDecl(
+    ImportContext& context,
+    const SemIR::NamedConstraint& import_named_constraint,
+    SemIR::SpecificId enclosing_specific_id)
+    -> std::pair<SemIR::NamedConstraintId, SemIR::ConstantId> {
+  SemIR::NamedConstraintDecl named_constraint_decl = {
+      .type_id = SemIR::TypeType::TypeId,
+      .named_constraint_id = SemIR::NamedConstraintId::None,
+      .decl_block_id = SemIR::InstBlockId::Empty};
+  auto named_constraint_decl_id = AddPlaceholderImportedInst(
+      context, import_named_constraint.first_owning_decl_id,
+      named_constraint_decl);
+
+  // Start with an incomplete interface.
+  named_constraint_decl.named_constraint_id =
+      context.local_named_constraints().Add(
+          {GetIncompleteLocalEntityBase(context, named_constraint_decl_id,
+                                        import_named_constraint),
+           {.scope_id = import_named_constraint.is_complete()
+                            ? AddPlaceholderNameScope(context)
+                            : SemIR::NameScopeId::None}});
+
+  if (import_named_constraint.has_parameters()) {
+    named_constraint_decl.type_id = GetGenericNamedConstraintType(
+        context.local_context(), named_constraint_decl.named_constraint_id,
+        enclosing_specific_id);
+  }
+
+  // Write the interface ID into the InterfaceDecl.
+  auto interface_const_id = ReplacePlaceholderImportedInst(
+      context, named_constraint_decl_id, named_constraint_decl);
+  return {named_constraint_decl.named_constraint_id, interface_const_id};
+}
+
+// Imports the definition for a named constraint that has been imported as a
+// forward declaration.
+static auto AddNamedConstraintDefinition(
+    ImportContext& context,
+    const SemIR::NamedConstraint& import_named_constraint,
+    SemIR::NamedConstraint& new_named_constraint, SemIR::InstId self_param_id)
+    -> void {
+  auto& new_scope =
+      context.local_name_scopes().Get(new_named_constraint.scope_id);
+  const auto& import_scope =
+      context.import_name_scopes().Get(import_named_constraint.scope_id);
+
+  // Push a block so that we can add scoped instructions to it.
+  context.local_context().inst_block_stack().Push();
+  InitializeNameScopeAndImportRefs(context, import_scope, new_scope,
+                                   new_named_constraint.first_owning_decl_id,
+                                   SemIR::NameId::None,
+                                   new_named_constraint.parent_scope_id);
+  new_scope.set_is_interface_definition();
+  new_named_constraint.body_block_id =
+      context.local_context().inst_block_stack().Pop();
+  new_named_constraint.self_param_id = self_param_id;
+
+  CARBON_CHECK(import_scope.extended_scopes().empty(),
+               "Interfaces don't currently have extended scopes to support.");
+}
+
+static auto TryResolveTypedInst(ImportRefResolver& resolver,
+                                SemIR::NamedConstraintDecl inst,
+                                SemIR::ConstantId named_constraint_const_id)
+    -> ResolveResult {
+  const auto& import_named_constraint =
+      resolver.import_named_constraints().Get(inst.named_constraint_id);
+
+  auto named_constraint_id = SemIR::NamedConstraintId::None;
+  if (!named_constraint_const_id.has_value()) {
+    auto import_specific_id = SemIR::SpecificId::None;
+    if (auto import_generic_named_constraint_type =
+            resolver.import_types().TryGetAs<SemIR::GenericNamedConstraintType>(
+                inst.type_id)) {
+      import_specific_id =
+          import_generic_named_constraint_type->enclosing_specific_id;
+    }
+    auto specific_data = GetLocalSpecificData(resolver, import_specific_id);
+    if (resolver.HasNewWork()) {
+      // This is the end of the first phase. Don't make a new interface yet if
+      // we already have new work.
+      return ResolveResult::Retry();
+    }
+
+    // On the second phase, create a forward declaration of the interface.
+    auto enclosing_specific_id =
+        GetOrAddLocalSpecific(resolver, import_specific_id, specific_data);
+    std::tie(named_constraint_id, named_constraint_const_id) =
+        MakeNamedConstraintDecl(resolver, import_named_constraint,
+                                enclosing_specific_id);
+  } else {
+    // On the third phase, compute the interface ID from the constant value of
+    // the declaration.
+    auto named_constraint_const_inst = resolver.local_insts().Get(
+        resolver.local_constant_values().GetInstId(named_constraint_const_id));
+    if (auto facet_type =
+            named_constraint_const_inst.TryAs<SemIR::FacetType>()) {
+      const SemIR::FacetTypeInfo& facet_type_info =
+          resolver.local_facet_types().Get(facet_type->facet_type_id);
+      CARBON_CHECK(facet_type_info.extend_named_constraints.size() == 1);
+      CARBON_CHECK(facet_type_info.extend_constraints.empty());
+      CARBON_CHECK(facet_type_info.self_impls_constraints.empty());
+      CARBON_CHECK(facet_type_info.self_impls_named_constraints.empty());
+      named_constraint_id =
+          facet_type_info.extend_named_constraints.front().named_constraint_id;
+    } else {
+      auto generic_named_constraint_type =
+          resolver.local_types().GetAs<SemIR::GenericNamedConstraintType>(
+              named_constraint_const_inst.type_id());
+      named_constraint_id = generic_named_constraint_type.named_constraint_id;
+    }
+  }
+
+  auto parent_scope_id =
+      GetLocalNameScopeId(resolver, import_named_constraint.parent_scope_id);
+  auto implicit_param_patterns = GetLocalInstBlockContents(
+      resolver, import_named_constraint.implicit_param_patterns_id);
+  auto param_patterns = GetLocalInstBlockContents(
+      resolver, import_named_constraint.param_patterns_id);
+  auto generic_data =
+      GetLocalGenericData(resolver, import_named_constraint.generic_id);
+
+  std::optional<SemIR::InstId> self_param_id;
+  if (import_named_constraint.is_complete()) {
+    self_param_id =
+        GetLocalConstantInstId(resolver, import_named_constraint.self_param_id);
+  }
+  auto& new_named_constraint =
+      resolver.local_named_constraints().Get(named_constraint_id);
+
+  if (resolver.HasNewWork()) {
+    return ResolveResult::Retry(named_constraint_const_id,
+                                new_named_constraint.first_decl_id());
+  }
+
+  new_named_constraint.parent_scope_id = parent_scope_id;
+  new_named_constraint.implicit_param_patterns_id =
+      GetLocalCanonicalInstBlockId(
+          resolver, import_named_constraint.implicit_param_patterns_id,
+          implicit_param_patterns);
+  new_named_constraint.param_patterns_id = GetLocalCanonicalInstBlockId(
+      resolver, import_named_constraint.param_patterns_id, param_patterns);
+  SetGenericData(resolver, import_named_constraint.generic_id,
+                 import_named_constraint.generic_id, generic_data);
+
+  if (import_named_constraint.is_complete()) {
+    CARBON_CHECK(self_param_id);
+    AddNamedConstraintDefinition(resolver, import_named_constraint,
+                                 new_named_constraint, *self_param_id);
+  }
+  return ResolveResult::Done(named_constraint_const_id,
+                             new_named_constraint.first_decl_id());
+}
+
 static auto TryResolveTypedInst(ImportRefResolver& resolver,
                                 SemIR::FacetAccessType inst) -> ResolveResult {
   auto facet_value_inst_id =
@@ -3187,8 +3349,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver,
     case CARBON_KIND(SemIR::InterfaceDecl inst): {
       return TryResolveTypedInst(resolver, inst, const_id);
     }
-    // TODO: Import NamedConstraintDecl once its FacetType constant value
-    // contains the NamedConstraintId.
+    case CARBON_KIND(SemIR::NamedConstraintDecl inst): {
+      return TryResolveTypedInst(resolver, inst, const_id);
+    }
     default:
       break;
   }

+ 15 - 8
toolchain/check/testdata/named_constraint/import_constraint_decl.carbon

@@ -49,14 +49,16 @@ fn F(T:! B) {}
 // 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:   %pattern_type: type = pattern_type %type [concrete]
+// CHECK:STDOUT:   %B.type: type = facet_type <@B> [concrete]
+// CHECK:STDOUT:   %T: %B.type = symbolic_binding T, 0 [symbolic]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %B.type [concrete]
 // CHECK:STDOUT:   %F.type: type = fn_type @F [concrete]
 // CHECK:STDOUT:   %F: %F.type = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Main.B: type = import_ref Main//b, B, loaded [concrete = constants.%type]
+// CHECK:STDOUT:   %Main.B: type = import_ref Main//b, B, loaded [concrete = constants.%B.type]
+// CHECK:STDOUT:   %Main.import_ref = import_ref Main//b, loc3_14, unloaded
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -69,16 +71,21 @@ fn F(T:! B) {}
 // CHECK:STDOUT:   %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
 // CHECK:STDOUT:     %T.patt: %pattern_type = symbolic_binding_pattern T, 0 [concrete]
 // CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %.loc4: type = splice_block %B.ref [concrete = constants.%type] {
+// CHECK:STDOUT:     %.loc4: type = splice_block %B.ref [concrete = constants.%B.type] {
 // CHECK:STDOUT:       %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
-// CHECK:STDOUT:       %B.ref: type = name_ref B, imports.%Main.B [concrete = constants.%type]
+// CHECK:STDOUT:       %B.ref: type = name_ref B, imports.%Main.B [concrete = constants.%B.type]
 // CHECK:STDOUT:     }
-// CHECK:STDOUT:     %T.loc4_6.2: %type = symbolic_binding T, 0 [symbolic = %T.loc4_6.1 (constants.%T)]
+// CHECK:STDOUT:     %T.loc4_6.2: %B.type = symbolic_binding T, 0 [symbolic = %T.loc4_6.1 (constants.%T)]
 // 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: constraint @B [from "b.carbon"] {
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = imports.%Main.import_ref
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: generic fn @F(%T.loc4_6.2: %B.type) {
+// CHECK:STDOUT:   %T.loc4_6.1: %B.type = symbolic_binding T, 0 [symbolic = %T.loc4_6.1 (constants.%T)]
 // CHECK:STDOUT:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT: