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

Stop assigning a symbolic generic parameter index to associated constants. (#3923)

While these use the `T:! type` notation, they don't actually introduce
new generic parameters into scope.
Richard Smith 2 лет назад
Родитель
Сommit
8676ef6f36

+ 12 - 1
toolchain/check/handle_binding_pattern.cpp

@@ -19,6 +19,17 @@ auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
   // Every other kind of pattern binding has a name.
   auto [name_node, name_id] = context.node_stack().PopNameWithNodeId();
 
+  // Determine whether we're handling an associated constant. These share the
+  // syntax for a compile-time binding, but don't behave like other compile-time
+  // bindings.
+  // TODO: Consider using a different parse node kind to make this easier.
+  bool is_associated_constant = false;
+  if (is_generic) {
+    auto inst_id = context.scope_stack().PeekInstId();
+    is_associated_constant =
+        inst_id.is_valid() && context.insts().Is<SemIR::InterfaceDecl>(inst_id);
+  }
+
   // Create the appropriate kind of binding for this pattern.
   auto make_bind_name = [&](SemIR::TypeId type_id,
                             SemIR::InstId value_id) -> SemIR::LocIdAndInst {
@@ -29,7 +40,7 @@ auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
          .enclosing_scope_id = context.scope_stack().PeekNameScopeId(),
          // TODO: Don't allocate a compile-time binding index for an associated
          // constant declaration.
-         .bind_index = is_generic
+         .bind_index = is_generic && !is_associated_constant
                            ? context.scope_stack().AddCompileTimeBinding()
                            : SemIR::CompileTimeBindIndex::Invalid});
     if (is_generic) {

+ 2 - 2
toolchain/check/testdata/interface/no_prelude/fail_assoc_const_not_binding.carbon

@@ -16,8 +16,8 @@ interface I {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %.1: type = interface_type @I [template]
 // CHECK:STDOUT:   %Self: I = bind_symbolic_name Self 0 [symbolic]
-// CHECK:STDOUT:   %T: type = bind_symbolic_name T 1 [symbolic]
-// CHECK:STDOUT:   %U: type = bind_symbolic_name U 2 [symbolic]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T [symbolic]
+// CHECK:STDOUT:   %U: type = bind_symbolic_name U [symbolic]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {}

+ 61 - 0
toolchain/check/testdata/interface/no_prelude/generic_binding_after_assoc_const.carbon

@@ -0,0 +1,61 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// AUTOUPDATE
+
+interface I {
+  fn F(T:! type);
+  let U:! type;
+  // This `T` should have index 1, just like the `T` above.
+  // The intervening `U:! type` should not cause this to have index 2.
+  fn G(T:! type);
+}
+
+// CHECK:STDOUT: --- generic_binding_after_assoc_const.carbon
+// CHECK:STDOUT:
+// CHECK:STDOUT: constants {
+// CHECK:STDOUT:   %.1: type = interface_type @I [template]
+// CHECK:STDOUT:   %Self: I = bind_symbolic_name Self 0 [symbolic]
+// CHECK:STDOUT:   %T: type = bind_symbolic_name T 1 [symbolic]
+// CHECK:STDOUT:   %.2: type = assoc_entity_type @I, <function> [template]
+// CHECK:STDOUT:   %.3: <associated <function> in I> = assoc_entity element0, @I.%F [template]
+// CHECK:STDOUT:   %.4: type = assoc_entity_type @I, type [template]
+// CHECK:STDOUT:   %.5: <associated type in I> = assoc_entity element1, @I.%U [template]
+// CHECK:STDOUT:   %.6: <associated <function> in I> = assoc_entity element2, @I.%G [template]
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: file {
+// CHECK:STDOUT:   package: <namespace> = namespace [template] {
+// CHECK:STDOUT:     .I = %I.decl
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %I.decl: type = interface_decl @I [template = constants.%.1] {}
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: interface @I {
+// CHECK:STDOUT:   %Self: I = bind_symbolic_name Self 0 [symbolic = constants.%Self]
+// CHECK:STDOUT:   %F: <function> = fn_decl @F [template] {
+// CHECK:STDOUT:     %T.loc8_8.1: type = param T
+// CHECK:STDOUT:     %T.loc8_8.2: type = bind_symbolic_name T 1, %T.loc8_8.1 [symbolic = constants.%T]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc8: <associated <function> in I> = assoc_entity element0, %F [template = constants.%.3]
+// CHECK:STDOUT:   %U: type = assoc_const_decl U [template]
+// CHECK:STDOUT:   %.loc9: <associated type in I> = assoc_entity element1, %U [template = constants.%.5]
+// CHECK:STDOUT:   %G: <function> = fn_decl @G [template] {
+// CHECK:STDOUT:     %T.loc12_8.1: type = param T
+// CHECK:STDOUT:     %T.loc12_8.2: type = bind_symbolic_name T 1, %T.loc12_8.1 [symbolic = constants.%T]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc12: <associated <function> in I> = assoc_entity element2, %G [template = constants.%.6]
+// CHECK:STDOUT:
+// CHECK:STDOUT: !members:
+// CHECK:STDOUT:   .Self = %Self
+// CHECK:STDOUT:   .F = %.loc8
+// CHECK:STDOUT:   .U = %.loc9
+// CHECK:STDOUT:   .G = %.loc12
+// CHECK:STDOUT:   witness = (%F, %U, %G)
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @F(@I.%T.loc8_8.2: type);
+// CHECK:STDOUT:
+// CHECK:STDOUT: fn @G(@I.%T.loc12_8.2: type);
+// CHECK:STDOUT: