Explorar el Código

When re-declaring, find the original decl of an associated function in an interface (#6688)

Functions in an interface definition are wrapped in an AssociatedEntity
instruction, which the logic for finding a previous declaration must
unwrap to find the FunctionDecl.

This is controlled by the NameScope::is_interface_definition() flag,
which is true for interfaces, and causes this extra wrapping to occur
when adding the function to the scope.
Dana Jansens hace 2 meses
padre
commit
f63d0a6266

+ 9 - 0
toolchain/check/handle_function.cpp

@@ -195,6 +195,15 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
   auto prev_type_id = SemIR::TypeId::None;
   auto prev_import_ir_id = SemIR::ImportIRId::None;
   CARBON_KIND_SWITCH(context.insts().Get(prev_id)) {
+    case CARBON_KIND(SemIR::AssociatedEntity assoc_entity): {
+      // This is a function in an interface definition scope (see
+      // NameScope::is_interface_definition()).
+      auto function_decl =
+          context.insts().GetAs<SemIR::FunctionDecl>(assoc_entity.decl_id);
+      prev_function_id = function_decl.function_id;
+      prev_type_id = function_decl.type_id;
+      break;
+    }
     case CARBON_KIND(SemIR::FunctionDecl function_decl): {
       prev_function_id = function_decl.function_id;
       prev_type_id = function_decl.type_id;

+ 9 - 17
toolchain/check/testdata/interface/fail_redeclare_member.carbon

@@ -14,10 +14,10 @@
 
 interface Interface {
   fn F();
-  // CHECK:STDERR: fail_redeclare_member.carbon:[[@LINE+7]]:6: error: duplicate name `F` being declared in the same scope [NameDeclDuplicate]
+  // CHECK:STDERR: fail_redeclare_member.carbon:[[@LINE+7]]:3: error: redeclaration of `fn F` is redundant [RedeclRedundant]
   // CHECK:STDERR:   fn F();
-  // CHECK:STDERR:      ^
-  // CHECK:STDERR: fail_redeclare_member.carbon:[[@LINE-4]]:3: note: name is previously declared here [NameDeclPrevious]
+  // CHECK:STDERR:   ^~~~~~~
+  // CHECK:STDERR: fail_redeclare_member.carbon:[[@LINE-4]]:3: note: previously declared here [RedeclPrevDecl]
   // CHECK:STDERR:   fn F();
   // CHECK:STDERR:   ^~~~~~~
   // CHECK:STDERR:
@@ -29,12 +29,10 @@ interface Interface {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %Interface.type: type = facet_type <@Interface> [concrete]
 // CHECK:STDOUT:   %Self: %Interface.type = symbolic_binding Self, 0 [symbolic]
-// CHECK:STDOUT:   %Interface.F.type.3f3064.1: type = fn_type @Interface.F.loc16 [concrete]
-// CHECK:STDOUT:   %Interface.F.77c12a.1: %Interface.F.type.3f3064.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %Interface.F.type: type = fn_type @Interface.F [concrete]
+// CHECK:STDOUT:   %Interface.F: %Interface.F.type = struct_value () [concrete]
 // CHECK:STDOUT:   %Interface.assoc_type: type = assoc_entity_type @Interface [concrete]
 // CHECK:STDOUT:   %assoc0: %Interface.assoc_type = assoc_entity element0, @Interface.%Interface.F.decl.loc16 [concrete]
-// CHECK:STDOUT:   %Interface.F.type.3f3064.2: type = fn_type @Interface.F.loc24 [concrete]
-// CHECK:STDOUT:   %Interface.F.77c12a.2: %Interface.F.type.3f3064.2 = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
@@ -46,9 +44,9 @@ interface Interface {
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Interface {
 // CHECK:STDOUT:   %Self: %Interface.type = symbolic_binding Self, 0 [symbolic = constants.%Self]
-// CHECK:STDOUT:   %Interface.F.decl.loc16: %Interface.F.type.3f3064.1 = fn_decl @Interface.F.loc16 [concrete = constants.%Interface.F.77c12a.1] {} {}
+// CHECK:STDOUT:   %Interface.F.decl.loc16: %Interface.F.type = fn_decl @Interface.F [concrete = constants.%Interface.F] {} {}
 // CHECK:STDOUT:   %assoc0: %Interface.assoc_type = assoc_entity element0, %Interface.F.decl.loc16 [concrete = constants.%assoc0]
-// CHECK:STDOUT:   %Interface.F.decl.loc24: %Interface.F.type.3f3064.2 = fn_decl @Interface.F.loc24 [concrete = constants.%Interface.F.77c12a.2] {} {}
+// CHECK:STDOUT:   %Interface.F.decl.loc24: %Interface.F.type = fn_decl @Interface.F [concrete = constants.%Interface.F] {} {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = %Self
@@ -58,15 +56,9 @@ interface Interface {
 // CHECK:STDOUT: !requires:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Interface.F.loc16(@Interface.%Self: %Interface.type) {
+// CHECK:STDOUT: generic fn @Interface.F(@Interface.%Self: %Interface.type) {
 // CHECK:STDOUT:   fn();
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Interface.F.loc24(@Interface.%Self: %Interface.type) {
-// CHECK:STDOUT:   fn();
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @Interface.F.loc16(constants.%Self) {}
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @Interface.F.loc24(constants.%Self) {}
+// CHECK:STDOUT: specific @Interface.F(constants.%Self) {}
 // CHECK:STDOUT:

+ 34 - 64
toolchain/check/testdata/interface/fail_todo_define_default_fn_out_of_line.carbon

@@ -28,22 +28,8 @@ interface Interface {
   default fn G(a: i32, b: i32) -> i32;
 }
 
-// CHECK:STDERR: fail_todo_define_default_fn_out_of_line.carbon:[[@LINE+7]]:14: error: duplicate name `F` being declared in the same scope [NameDeclDuplicate]
-// CHECK:STDERR: fn Interface.F() {}
-// CHECK:STDERR:              ^
-// CHECK:STDERR: fail_todo_define_default_fn_out_of_line.carbon:[[@LINE-12]]:3: note: name is previously declared here [NameDeclPrevious]
-// CHECK:STDERR:   default fn F();
-// CHECK:STDERR:   ^~~~~~~~~~~~~~~
-// CHECK:STDERR:
 fn Interface.F() {}
 
-// CHECK:STDERR: fail_todo_define_default_fn_out_of_line.carbon:[[@LINE+7]]:14: error: duplicate name `G` being declared in the same scope [NameDeclDuplicate]
-// CHECK:STDERR: fn Interface.G(a: i32, b: i32) -> i32 = "int.sadd";
-// CHECK:STDERR:              ^
-// CHECK:STDERR: fail_todo_define_default_fn_out_of_line.carbon:[[@LINE-15]]:3: note: name is previously declared here [NameDeclPrevious]
-// CHECK:STDERR:   default fn G(a: i32, b: i32) -> i32;
-// CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// CHECK:STDERR:
 fn Interface.G(a: i32, b: i32) -> i32 = "int.sadd";
 
 // --- dependent_return_type.carbon
@@ -73,8 +59,8 @@ fn Interface.C.F[self: Self](U:! type, u: U*) -> U* { return u; }
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %Interface.type: type = facet_type <@Interface> [concrete]
 // CHECK:STDOUT:   %Self: %Interface.type = symbolic_binding Self, 0 [symbolic]
-// CHECK:STDOUT:   %Interface.F.type.3f3064.1: type = fn_type @Interface.F.loc7 [concrete]
-// CHECK:STDOUT:   %Interface.F.77c12a.1: %Interface.F.type.3f3064.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %Interface.F.type: type = fn_type @Interface.F [concrete]
+// CHECK:STDOUT:   %Interface.F: %Interface.F.type = struct_value () [concrete]
 // CHECK:STDOUT:   %Interface.assoc_type: type = assoc_entity_type @Interface [concrete]
 // CHECK:STDOUT:   %assoc0: %Interface.assoc_type = assoc_entity element0, @Interface.%Interface.F.decl [concrete]
 // CHECK:STDOUT:   %int_32: Core.IntLiteral = int_value 32 [concrete]
@@ -83,13 +69,9 @@ fn Interface.C.F[self: Self](U:! type, u: U*) -> U* { return u; }
 // CHECK:STDOUT:   %i32: type = class_type @Int, @Int(%int_32) [concrete]
 // CHECK:STDOUT:   %pattern_type.7ce: type = pattern_type %i32 [concrete]
 // CHECK:STDOUT:   %.88a: form = init_form %i32, call_param2 [concrete]
-// CHECK:STDOUT:   %Interface.G.type.cde93b.1: type = fn_type @Interface.G.loc13 [concrete]
-// CHECK:STDOUT:   %Interface.G.433e0c.1: %Interface.G.type.cde93b.1 = struct_value () [concrete]
+// CHECK:STDOUT:   %Interface.G.type: type = fn_type @Interface.G [concrete]
+// CHECK:STDOUT:   %Interface.G: %Interface.G.type = struct_value () [concrete]
 // CHECK:STDOUT:   %assoc1: %Interface.assoc_type = assoc_entity element1, @Interface.%Interface.G.decl [concrete]
-// CHECK:STDOUT:   %Interface.F.type.3f3064.2: type = fn_type @Interface.F.loc23 [concrete]
-// CHECK:STDOUT:   %Interface.F.77c12a.2: %Interface.F.type.3f3064.2 = struct_value () [concrete]
-// CHECK:STDOUT:   %Interface.G.type.cde93b.2: type = fn_type @Interface.G.loc32 [concrete]
-// CHECK:STDOUT:   %Interface.G.433e0c.2: %Interface.G.type.cde93b.2 = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -108,8 +90,8 @@ fn Interface.C.F[self: Self](U:! type, u: U*) -> U* { return u; }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %Core.import = import Core
 // CHECK:STDOUT:   %Interface.decl: type = interface_decl @Interface [concrete = constants.%Interface.type] {} {}
-// CHECK:STDOUT:   %Interface.F.decl: %Interface.F.type.3f3064.2 = fn_decl @Interface.F.loc23 [concrete = constants.%Interface.F.77c12a.2] {} {}
-// CHECK:STDOUT:   %Interface.G.decl: %Interface.G.type.cde93b.2 = fn_decl @Interface.G.loc32 [concrete = constants.%Interface.G.433e0c.2] {
+// CHECK:STDOUT:   %Interface.F.decl: %Interface.F.type = fn_decl @Interface.F [concrete = constants.%Interface.F] {} {}
+// CHECK:STDOUT:   %Interface.G.decl: %Interface.G.type = fn_decl @Interface.G [concrete = constants.%Interface.G] {
 // CHECK:STDOUT:     %a.patt: %pattern_type.7ce = value_binding_pattern a [concrete]
 // CHECK:STDOUT:     %a.param_patt: %pattern_type.7ce = value_param_pattern %a.patt, call_param0 [concrete]
 // CHECK:STDOUT:     %b.patt: %pattern_type.7ce = value_binding_pattern b [concrete]
@@ -117,31 +99,31 @@ fn Interface.C.F[self: Self](U:! type, u: U*) -> U* { return u; }
 // CHECK:STDOUT:     %return.patt: %pattern_type.7ce = return_slot_pattern [concrete]
 // CHECK:STDOUT:     %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param2 [concrete]
 // CHECK:STDOUT:   } {
-// CHECK:STDOUT:     %int_32.loc32_35: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:     %i32.loc32_35: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
-// CHECK:STDOUT:     %.loc32_35: form = init_form %i32.loc32_35, call_param2 [concrete = constants.%.88a]
-// CHECK:STDOUT:     %a.param: %i32 = value_param call_param0
-// CHECK:STDOUT:     %.loc32_19: type = splice_block %i32.loc32_19 [concrete = constants.%i32] {
-// CHECK:STDOUT:       %int_32.loc32_19: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:       %i32.loc32_19: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:     %int_32.loc18_35: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
+// CHECK:STDOUT:     %i32.loc18_35: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:     %.loc18_35: form = init_form %i32.loc18_35, call_param2 [concrete = constants.%.88a]
+// CHECK:STDOUT:     %a.param.loc18: %i32 = value_param call_param0
+// CHECK:STDOUT:     %.loc18_19: type = splice_block %i32.loc18_19 [concrete = constants.%i32] {
+// CHECK:STDOUT:       %int_32.loc18_19: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
+// CHECK:STDOUT:       %i32.loc18_19: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:     }
-// CHECK:STDOUT:     %a: %i32 = value_binding a, %a.param
-// CHECK:STDOUT:     %b.param: %i32 = value_param call_param1
-// CHECK:STDOUT:     %.loc32_27: type = splice_block %i32.loc32_27 [concrete = constants.%i32] {
-// CHECK:STDOUT:       %int_32.loc32_27: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
-// CHECK:STDOUT:       %i32.loc32_27: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
+// CHECK:STDOUT:     %a.loc18: %i32 = value_binding a, %a.param.loc18
+// CHECK:STDOUT:     %b.param.loc18: %i32 = value_param call_param1
+// CHECK:STDOUT:     %.loc18_27: type = splice_block %i32.loc18_27 [concrete = constants.%i32] {
+// CHECK:STDOUT:       %int_32.loc18_27: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
+// CHECK:STDOUT:       %i32.loc18_27: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:     }
-// CHECK:STDOUT:     %b: %i32 = value_binding b, %b.param
-// CHECK:STDOUT:     %return.param: ref %i32 = out_param call_param2
-// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:     %b.loc18: %i32 = value_binding b, %b.param.loc18
+// CHECK:STDOUT:     %return.param.loc18: ref %i32 = out_param call_param2
+// CHECK:STDOUT:     %return.loc18: ref %i32 = return_slot %return.param.loc18
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: interface @Interface {
 // CHECK:STDOUT:   %Self: %Interface.type = symbolic_binding Self, 0 [symbolic = constants.%Self]
-// CHECK:STDOUT:   %Interface.F.decl: %Interface.F.type.3f3064.1 = fn_decl @Interface.F.loc7 [concrete = constants.%Interface.F.77c12a.1] {} {}
+// CHECK:STDOUT:   %Interface.F.decl: %Interface.F.type = fn_decl @Interface.F [concrete = constants.%Interface.F] {} {}
 // CHECK:STDOUT:   %assoc0: %Interface.assoc_type = assoc_entity element0, %Interface.F.decl [concrete = constants.%assoc0]
-// CHECK:STDOUT:   %Interface.G.decl: %Interface.G.type.cde93b.1 = fn_decl @Interface.G.loc13 [concrete = constants.%Interface.G.433e0c.1] {
+// CHECK:STDOUT:   %Interface.G.decl: %Interface.G.type = fn_decl @Interface.G [concrete = constants.%Interface.G] {
 // CHECK:STDOUT:     %a.patt: %pattern_type.7ce = value_binding_pattern a [concrete]
 // CHECK:STDOUT:     %a.param_patt: %pattern_type.7ce = value_param_pattern %a.patt, call_param0 [concrete]
 // CHECK:STDOUT:     %b.patt: %pattern_type.7ce = value_binding_pattern b [concrete]
@@ -152,20 +134,20 @@ fn Interface.C.F[self: Self](U:! type, u: U*) -> U* { return u; }
 // CHECK:STDOUT:     %int_32.loc13_35: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:     %i32.loc13_35: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:     %.loc13_35: form = init_form %i32.loc13_35, call_param2 [concrete = constants.%.88a]
-// CHECK:STDOUT:     %a.param: %i32 = value_param call_param0
+// CHECK:STDOUT:     %a.param.loc13: %i32 = value_param call_param0
 // CHECK:STDOUT:     %.loc13_19: type = splice_block %i32.loc13_19 [concrete = constants.%i32] {
 // CHECK:STDOUT:       %int_32.loc13_19: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:       %i32.loc13_19: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:     }
-// CHECK:STDOUT:     %a: %i32 = value_binding a, %a.param
-// CHECK:STDOUT:     %b.param: %i32 = value_param call_param1
+// CHECK:STDOUT:     %a.loc13: %i32 = value_binding a, %a.param.loc13
+// CHECK:STDOUT:     %b.param.loc13: %i32 = value_param call_param1
 // CHECK:STDOUT:     %.loc13_27: type = splice_block %i32.loc13_27 [concrete = constants.%i32] {
 // CHECK:STDOUT:       %int_32.loc13_27: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
 // CHECK:STDOUT:       %i32.loc13_27: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
 // CHECK:STDOUT:     }
-// CHECK:STDOUT:     %b: %i32 = value_binding b, %b.param
-// CHECK:STDOUT:     %return.param: ref %i32 = out_param call_param2
-// CHECK:STDOUT:     %return: ref %i32 = return_slot %return.param
+// CHECK:STDOUT:     %b.loc13: %i32 = value_binding b, %b.param.loc13
+// CHECK:STDOUT:     %return.param.loc13: ref %i32 = out_param call_param2
+// CHECK:STDOUT:     %return.loc13: ref %i32 = return_slot %return.param.loc13
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %assoc1: %Interface.assoc_type = assoc_entity element1, %Interface.G.decl [concrete = constants.%assoc1]
 // CHECK:STDOUT:
@@ -178,15 +160,7 @@ fn Interface.C.F[self: Self](U:! type, u: U*) -> U* { return u; }
 // CHECK:STDOUT: !requires:
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Interface.F.loc7(@Interface.%Self: %Interface.type) {
-// CHECK:STDOUT:   fn();
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Interface.G.loc13(@Interface.%Self: %Interface.type) {
-// CHECK:STDOUT:   fn(%a.param: %i32, %b.param: %i32) -> out %return.param: %i32;
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Interface.F.loc23(@Interface.%Self: %Interface.type) {
+// CHECK:STDOUT: generic fn @Interface.F(@Interface.%Self: %Interface.type) {
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:
 // CHECK:STDOUT:   fn() {
@@ -195,19 +169,15 @@ fn Interface.C.F[self: Self](U:! type, u: U*) -> U* { return u; }
 // CHECK:STDOUT:   }
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: generic fn @Interface.G.loc32(@Interface.%Self: %Interface.type) {
+// CHECK:STDOUT: generic fn @Interface.G(@Interface.%Self: %Interface.type) {
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT:
-// CHECK:STDOUT:   fn(%a.param: %i32, %b.param: %i32) -> out %return.param: %i32 = "int.sadd";
+// CHECK:STDOUT:   fn(%a.param.loc18: %i32, %b.param.loc18: %i32) -> out %return.param.loc18: %i32 = "int.sadd";
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @Interface.F.loc7(constants.%Self) {}
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @Interface.G.loc13(constants.%Self) {}
-// CHECK:STDOUT:
-// CHECK:STDOUT: specific @Interface.F.loc23(constants.%Self) {}
+// CHECK:STDOUT: specific @Interface.F(constants.%Self) {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: specific @Interface.G.loc32(constants.%Self) {}
+// CHECK:STDOUT: specific @Interface.G(constants.%Self) {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: --- dependent_return_type.carbon
 // CHECK:STDOUT:

+ 0 - 25
toolchain/check/testdata/interface/fail_todo_generic_default_fn.carbon

@@ -1,25 +0,0 @@
-// 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
-//
-// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
-//
-// AUTOUPDATE
-// TIP: To test this file alone, run:
-// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/fail_todo_generic_default_fn.carbon
-// TIP: To dump output, run:
-// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/fail_todo_generic_default_fn.carbon
-
-interface I(T:! type) {
-  // TODO: Use `default` here.
-  fn F[ref self: Self]() -> Self*;
-}
-
-// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+7]]:16: error: duplicate name `F` being declared in the same scope [NameDeclDuplicate]
-// CHECK:STDERR: fn I(T:! type).F[ref self: Self]() -> Self* { return &self; }
-// CHECK:STDERR:                ^
-// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE-6]]:3: note: name is previously declared here [NameDeclPrevious]
-// CHECK:STDERR:   fn F[ref self: Self]() -> Self*;
-// CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// CHECK:STDERR:
-fn I(T:! type).F[ref self: Self]() -> Self* { return &self; }

+ 18 - 0
toolchain/check/testdata/interface/generic_default_fn.carbon

@@ -0,0 +1,18 @@
+// 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
+//
+// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/generic_default_fn.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/generic_default_fn.carbon
+
+interface I(T:! type) {
+  // TODO: Use `default` here.
+  fn F[ref self: Self]() -> Self*;
+}
+
+fn I(T:! type).F[ref self: Self]() -> Self* { return &self; }