mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 07:24:42 +01:00
Don't require a thunk for parameter name differences. (#5404)
When checking whether we can use the function in an impl directly to satisfy a signature in an interface, allow the parameter names to differ between the two declarations.
This commit is contained in:
@@ -206,7 +206,7 @@ static auto CheckRedeclParam(Context& context, bool is_implicit_param,
|
||||
SemIR::InstId new_param_pattern_id,
|
||||
SemIR::InstId prev_param_pattern_id,
|
||||
SemIR::SpecificId prev_specific_id, bool diagnose,
|
||||
bool check_self) -> bool {
|
||||
bool check_syntax, bool check_self) -> bool {
|
||||
auto orig_new_param_pattern_id = new_param_pattern_id;
|
||||
auto orig_prev_param_pattern_id = prev_param_pattern_id;
|
||||
|
||||
@@ -300,7 +300,7 @@ static auto CheckRedeclParam(Context& context, bool is_implicit_param,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (new_name_id != prev_name_id) {
|
||||
if (check_syntax && new_name_id != prev_name_id) {
|
||||
emit_diagnostic();
|
||||
return false;
|
||||
}
|
||||
@@ -315,7 +315,7 @@ static auto CheckRedeclParams(Context& context, SemIR::LocId new_decl_loc_id,
|
||||
SemIR::InstBlockId prev_param_patterns_id,
|
||||
bool is_implicit_param,
|
||||
SemIR::SpecificId prev_specific_id, bool diagnose,
|
||||
bool check_self) -> bool {
|
||||
bool check_syntax, bool check_self) -> bool {
|
||||
// This will often occur for empty params.
|
||||
if (new_param_patterns_id == prev_param_patterns_id) {
|
||||
return true;
|
||||
@@ -373,7 +373,8 @@ static auto CheckRedeclParams(Context& context, SemIR::LocId new_decl_loc_id,
|
||||
llvm::enumerate(new_param_pattern_ids, prev_param_pattern_ids)) {
|
||||
if (!CheckRedeclParam(context, is_implicit_param, index,
|
||||
new_param_pattern_id, prev_param_pattern_id,
|
||||
prev_specific_id, diagnose, check_self)) {
|
||||
prev_specific_id, diagnose, check_syntax,
|
||||
check_self)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -493,7 +494,8 @@ auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
|
||||
if (!CheckRedeclParams(
|
||||
context, new_entity.loc_id, new_entity.implicit_param_patterns_id,
|
||||
prev_entity.loc_id, prev_entity.implicit_param_patterns_id,
|
||||
/*is_implicit_param=*/true, prev_specific_id, diagnose, check_self)) {
|
||||
/*is_implicit_param=*/true, prev_specific_id, diagnose, check_syntax,
|
||||
check_self)) {
|
||||
return false;
|
||||
}
|
||||
// Don't forward `check_self` here because it's extra cost, and `self` is only
|
||||
@@ -502,7 +504,7 @@ auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity,
|
||||
new_entity.param_patterns_id, prev_entity.loc_id,
|
||||
prev_entity.param_patterns_id,
|
||||
/*is_implicit_param=*/false, prev_specific_id,
|
||||
diagnose, /*check_self=*/true)) {
|
||||
diagnose, check_syntax, /*check_self=*/true)) {
|
||||
return false;
|
||||
}
|
||||
if (check_syntax &&
|
||||
|
||||
+18
-59
@@ -8,39 +8,15 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/no_prelude/impl_thunk.carbon
|
||||
|
||||
// --- fail_todo_param_name_differs.carbon
|
||||
// --- no_thunk_param_name_differs.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE+3]]:20: error: parameter has incomplete type `C` in function definition [IncompleteTypeInFunctionParam]
|
||||
// CHECK:STDERR: interface I { fn F(x: Self); }
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
interface I { fn F(x: Self); }
|
||||
|
||||
// TODO: This currently uses a thunk due to the parameter name mismatch, but shouldn't!
|
||||
// TODO: This then fails because we attempt to build the thunk before `C` is complete.
|
||||
// CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE+3]]:1: note: class is incomplete within its definition [ClassIncompleteWithinDefinition]
|
||||
// CHECK:STDERR: class C {
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// This is OK, and does not require a thunk despite the parameter name differing.
|
||||
class C {
|
||||
impl as I {
|
||||
// CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE+17]]:5: note: while building thunk calling this function [ThunkCallee]
|
||||
// CHECK:STDERR: fn F(not_x: C);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE-13]]:20: error: forming value of incomplete type `C` [IncompleteTypeInValueConversion]
|
||||
// CHECK:STDERR: interface I { fn F(x: Self); }
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE-9]]:1: note: class is incomplete within its definition [ClassIncompleteWithinDefinition]
|
||||
// CHECK:STDERR: class C {
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE+7]]:10: note: initializing function parameter [InCallToFunctionParam]
|
||||
// CHECK:STDERR: fn F(not_x: C);
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_param_name_differs.carbon:[[@LINE-22]]:15: note: while building thunk to match the signature of this function [ThunkSignature]
|
||||
// CHECK:STDERR: interface I { fn F(x: Self); }
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn F(not_x: C);
|
||||
}
|
||||
}
|
||||
@@ -227,7 +203,7 @@ impl C as I {
|
||||
fn NoReturn() -> C;
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: --- fail_todo_param_name_differs.carbon
|
||||
// CHECK:STDOUT: --- no_thunk_param_name_differs.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %I.type: type = facet_type <@I> [concrete]
|
||||
@@ -235,18 +211,15 @@ impl C as I {
|
||||
// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self [symbolic]
|
||||
// CHECK:STDOUT: %pattern_type.6de: type = pattern_type %Self.as_type [symbolic]
|
||||
// CHECK:STDOUT: %F.type.cf0: type = fn_type @F.1 [concrete]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %F.bc6: %F.type.cf0 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type @I [concrete]
|
||||
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, @I.%F.decl [concrete]
|
||||
// CHECK:STDOUT: %C: type = class_type @C [concrete]
|
||||
// CHECK:STDOUT: %I.impl_witness: <witness> = impl_witness @C.%I.impl_witness_table [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.c48: type = pattern_type %C [concrete]
|
||||
// CHECK:STDOUT: %F.type.f3605c.1: type = fn_type @F.2 [concrete]
|
||||
// CHECK:STDOUT: %F.4c32b3.1: %F.type.f3605c.1 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %F.type.f36: type = fn_type @F.2 [concrete]
|
||||
// CHECK:STDOUT: %F.4c3: %F.type.f36 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %I.facet: %I.type = facet_value %C, (%I.impl_witness) [concrete]
|
||||
// CHECK:STDOUT: %F.type.f3605c.2: type = fn_type @F.3 [concrete]
|
||||
// CHECK:STDOUT: %F.4c32b3.2: %F.type.f3605c.2 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
@@ -266,13 +239,13 @@ impl C as I {
|
||||
// CHECK:STDOUT: %x.patt: @F.1.%pattern_type (%pattern_type.6de) = binding_pattern x [concrete]
|
||||
// CHECK:STDOUT: %x.param_patt: @F.1.%pattern_type (%pattern_type.6de) = value_param_pattern %x.patt, call_param0 [concrete]
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: %x.param: @F.1.%Self.as_type.loc7_23.1 (%Self.as_type) = value_param call_param0
|
||||
// CHECK:STDOUT: %.loc7_23.1: type = splice_block %.loc7_23.2 [symbolic = %Self.as_type.loc7_23.1 (constants.%Self.as_type)] {
|
||||
// CHECK:STDOUT: %x.param: @F.1.%Self.as_type.loc4_23.1 (%Self.as_type) = value_param call_param0
|
||||
// CHECK:STDOUT: %.loc4_23.1: type = splice_block %.loc4_23.2 [symbolic = %Self.as_type.loc4_23.1 (constants.%Self.as_type)] {
|
||||
// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)]
|
||||
// CHECK:STDOUT: %Self.as_type.loc7_23.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc7_23.1 (constants.%Self.as_type)]
|
||||
// CHECK:STDOUT: %.loc7_23.2: type = converted %Self.ref, %Self.as_type.loc7_23.2 [symbolic = %Self.as_type.loc7_23.1 (constants.%Self.as_type)]
|
||||
// CHECK:STDOUT: %Self.as_type.loc4_23.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc4_23.1 (constants.%Self.as_type)]
|
||||
// CHECK:STDOUT: %.loc4_23.2: type = converted %Self.ref, %Self.as_type.loc4_23.2 [symbolic = %Self.as_type.loc4_23.1 (constants.%Self.as_type)]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %x: @F.1.%Self.as_type.loc7_23.1 (%Self.as_type) = bind_name x, %x.param
|
||||
// CHECK:STDOUT: %x: @F.1.%Self.as_type.loc4_23.1 (%Self.as_type) = bind_name x, %x.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [concrete = constants.%assoc0]
|
||||
// CHECK:STDOUT:
|
||||
@@ -283,7 +256,7 @@ impl C as I {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: impl @impl: %Self.ref as %I.ref {
|
||||
// CHECK:STDOUT: %F.decl.loc33_19.1: %F.type.f3605c.1 = fn_decl @F.2 [concrete = constants.%F.4c32b3.1] {
|
||||
// CHECK:STDOUT: %F.decl: %F.type.f36 = fn_decl @F.2 [concrete = constants.%F.4c3] {
|
||||
// CHECK:STDOUT: %not_x.patt: %pattern_type.c48 = binding_pattern not_x [concrete]
|
||||
// CHECK:STDOUT: %not_x.param_patt: %pattern_type.c48 = value_param_pattern %not_x.patt, call_param0 [concrete]
|
||||
// CHECK:STDOUT: } {
|
||||
@@ -291,17 +264,10 @@ impl C as I {
|
||||
// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C]
|
||||
// CHECK:STDOUT: %not_x: %C = bind_name not_x, %not_x.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %F.decl.loc33_19.2: %F.type.f3605c.2 = fn_decl @F.3 [concrete = constants.%F.4c32b3.2] {
|
||||
// CHECK:STDOUT: %x.patt: %pattern_type.c48 = binding_pattern x [concrete]
|
||||
// CHECK:STDOUT: %x.param_patt: %pattern_type.c48 = value_param_pattern %x.patt, call_param0 [concrete]
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: %x.param: %C = value_param call_param0
|
||||
// CHECK:STDOUT: %x: %C = bind_name x, %x.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .C = <poisoned>
|
||||
// CHECK:STDOUT: .F = %F.decl.loc33_19.1
|
||||
// CHECK:STDOUT: .F = %F.decl
|
||||
// CHECK:STDOUT: witness = @C.%I.impl_witness
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -310,7 +276,7 @@ impl C as I {
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%C [concrete = constants.%C]
|
||||
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %I.impl_witness_table = impl_witness_table (@impl.%F.decl.loc33_19.2), @impl [concrete]
|
||||
// CHECK:STDOUT: %I.impl_witness_table = impl_witness_table (@impl.%F.decl), @impl [concrete]
|
||||
// CHECK:STDOUT: %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type]
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
|
||||
@@ -324,30 +290,23 @@ impl C as I {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic fn @F.1(@I.%Self: %I.type) {
|
||||
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
|
||||
// CHECK:STDOUT: %Self.as_type.loc7_23.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc7_23.1 (constants.%Self.as_type)]
|
||||
// CHECK:STDOUT: %pattern_type: type = pattern_type %Self.as_type.loc7_23.1 [symbolic = %pattern_type (constants.%pattern_type.6de)]
|
||||
// CHECK:STDOUT: %Self.as_type.loc4_23.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc4_23.1 (constants.%Self.as_type)]
|
||||
// CHECK:STDOUT: %pattern_type: type = pattern_type %Self.as_type.loc4_23.1 [symbolic = %pattern_type (constants.%pattern_type.6de)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn(%x.param: @F.1.%Self.as_type.loc7_23.1 (%Self.as_type));
|
||||
// CHECK:STDOUT: fn(%x.param: @F.1.%Self.as_type.loc4_23.1 (%Self.as_type));
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.2(%not_x.param: %C);
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.3(%x.param: %C) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %x.ref: %C = name_ref x, %x.param
|
||||
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call @impl.%F.decl.loc33_19.1(<error>)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @F.1(constants.%Self) {
|
||||
// CHECK:STDOUT: %Self => constants.%Self
|
||||
// CHECK:STDOUT: %Self.as_type.loc7_23.1 => constants.%Self.as_type
|
||||
// CHECK:STDOUT: %Self.as_type.loc4_23.1 => constants.%Self.as_type
|
||||
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.6de
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @F.1(constants.%I.facet) {
|
||||
// CHECK:STDOUT: %Self => constants.%I.facet
|
||||
// CHECK:STDOUT: %Self.as_type.loc7_23.1 => constants.%C
|
||||
// CHECK:STDOUT: %Self.as_type.loc4_23.1 => constants.%C
|
||||
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.c48
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
Reference in New Issue
Block a user