Browse Source

Import generic named constraints (#6376)

We add tests showing that `ImplStore::GetOrAddLookupBucket` is doing the
wrong thing for impls of a named constraint, as the impl-file
redeclarations of impls in the api file are not getting flagged as such.
To do the right thing requires us to be able to get the constraint from
a require declaration with the specific of the named
constraint/interface applied, which is future work as described in the
[open discussion
notes](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.1ji9ixn9bbnn#heading=h.kijomnov90rz).
Dana Jansens 5 months ago
parent
commit
eb0dcc8ce4

+ 32 - 1
toolchain/check/import_ref.cpp

@@ -852,6 +852,11 @@ static auto GetLocalGenericId(ImportContext& context,
           .Get(interface_type.interface_id)
           .generic_id;
     }
+    case CARBON_KIND(SemIR::GenericNamedConstraintType constraint_type): {
+      return context.local_named_constraints()
+          .Get(constraint_type.named_constraint_id)
+          .generic_id;
+    }
     case CARBON_KIND(SemIR::ImplDecl impl_decl): {
       return context.local_impls().Get(impl_decl.impl_id).generic_id;
     }
@@ -1070,6 +1075,11 @@ static auto GetLocalNameScopeIdImpl(ImportRefResolver& resolver,
         case CARBON_KIND(SemIR::GenericInterfaceType inst): {
           return resolver.local_interfaces().Get(inst.interface_id).scope_id;
         }
+        case CARBON_KIND(SemIR::GenericNamedConstraintType inst): {
+          return resolver.local_named_constraints()
+              .Get(inst.named_constraint_id)
+              .scope_id;
+        }
         default: {
           break;
         }
@@ -2272,6 +2282,24 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
       resolver.local_types().GetConstantId(interface_val.type_id()));
 }
 
+static auto TryResolveTypedInst(ImportRefResolver& resolver,
+                                SemIR::GenericNamedConstraintType inst)
+    -> ResolveResult {
+  CARBON_CHECK(inst.type_id == SemIR::TypeType::TypeId);
+  auto constraint_val_id =
+      GetLocalConstantInstId(resolver, resolver.import_named_constraints()
+                                           .Get(inst.named_constraint_id)
+                                           .first_owning_decl_id);
+  if (resolver.HasNewWork()) {
+    return ResolveResult::Retry();
+  }
+  auto constraint_val = resolver.local_insts().Get(constraint_val_id);
+  CARBON_CHECK(resolver.local_types().Is<SemIR::GenericNamedConstraintType>(
+      constraint_val.type_id()));
+  return ResolveResult::Done(
+      resolver.local_types().GetConstantId(constraint_val.type_id()));
+}
+
 // Make a declaration of an impl. This is done as a separate step from
 // importing the impl definition in order to resolve cycles.
 static auto MakeImplDeclaration(ImportContext& context,
@@ -2775,7 +2803,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
           resolver, import_named_constraint.require_impls_block_id,
           require_impls);
   SetGenericData(resolver, import_named_constraint.generic_id,
-                 import_named_constraint.generic_id, generic_data);
+                 new_named_constraint.generic_id, generic_data);
 
   if (import_named_constraint.is_complete()) {
     CARBON_CHECK(self_param_id);
@@ -3522,6 +3550,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver,
     case CARBON_KIND(SemIR::GenericInterfaceType inst): {
       return TryResolveTypedInst(resolver, inst);
     }
+    case CARBON_KIND(SemIR::GenericNamedConstraintType inst): {
+      return TryResolveTypedInst(resolver, inst);
+    }
     case CARBON_KIND(SemIR::LookupImplWitness inst): {
       return TryResolveTypedInst(resolver, inst);
     }

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

@@ -133,3 +133,18 @@ constraint C {
 // CHECK:STDERR: ^~~~~~~~~~~~~~
 // CHECK:STDERR:
 impl () as C {}
+
+// --- todo_fail_duplicate_through_generic_constraint.carbon
+library "[[@TEST_NAME]]";
+
+interface A(T:! type) {}
+
+constraint B(X:! type, Y:! type) {
+  extend require impls A(Y);
+}
+
+// This should impl () as A({}).
+impl () as B((), {}) {}
+
+// This should be considered a duplicate.
+impl () as A({}) {}

File diff suppressed because it is too large
+ 750 - 41
toolchain/check/testdata/impl/import_generic.carbon


+ 1 - 0
toolchain/sem_ir/type_iterator.cpp

@@ -98,6 +98,7 @@ auto TypeIterator::ProcessTypeId(TypeId type_id) -> std::optional<Step> {
     case FunctionTypeWithSelfType::Kind:
     case GenericClassType::Kind:
     case GenericInterfaceType::Kind:
+    case GenericNamedConstraintType::Kind:
     case ImplWitnessAccess::Kind:
     case IntLiteralType::Kind:
     case NamespaceType::Kind:

Some files were not shown because too many files changed in this diff