From d6d70bf80df7c071d233b3cc031590f97c4b3f8c Mon Sep 17 00:00:00 2001 From: josh11b <15258583+josh11b@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:24:28 -0700 Subject: [PATCH] Handle runtime implicit parameters, and `self` outside of methods (#4361) Closes #4356, #4359 --------- Co-authored-by: Josh L --- toolchain/check/generic.cpp | 61 +++++++++--- toolchain/check/generic.h | 18 +++- toolchain/check/handle_class.cpp | 4 +- toolchain/check/handle_function.cpp | 2 + toolchain/check/handle_impl.cpp | 2 +- toolchain/check/handle_interface.cpp | 4 +- .../testdata/class/fail_addr_not_self.carbon | 21 ++-- .../testdata/class/fail_self_param.carbon | 95 +++++++++++++++++++ .../fail_explicit_self_param.carbon | 58 +++++++++++ .../fail_runtime_implicit_param.carbon | 54 +++++++++++ .../no_prelude/syntactic_merge.carbon | 55 +++++++---- toolchain/diagnostics/diagnostic_kind.def | 4 +- 12 files changed, 331 insertions(+), 47 deletions(-) create mode 100644 toolchain/check/testdata/class/fail_self_param.carbon create mode 100644 toolchain/check/testdata/function/call/no_prelude/fail_explicit_self_param.carbon create mode 100644 toolchain/check/testdata/function/call/no_prelude/fail_runtime_implicit_param.carbon diff --git a/toolchain/check/generic.cpp b/toolchain/check/generic.cpp index b7bb57afc51c..184179cdbe53 100644 --- a/toolchain/check/generic.cpp +++ b/toolchain/check/generic.cpp @@ -421,27 +421,64 @@ auto ResolveSpecificDefinition(Context& context, SemIR::SpecificId specific_id) return true; } -auto RequireGenericParams(Context& context, SemIR::InstBlockId block_id) +// Replace the parameter with an invalid instruction so that we don't try +// constructing a generic based on it. Note this is updating the param +// refs block, not the actual params block, so will not be directly +// reflected in SemIR output. +static auto ReplaceInstructionWithError(Context& context, + SemIR::InstId& inst_id) -> void { + inst_id = context.AddInstInNoBlock( + context.insts().GetLocId(inst_id), + {.type_id = SemIR::TypeId::Error, + .name_id = SemIR::NameId::Base, + .runtime_index = SemIR::RuntimeParamIndex::Invalid}); +} + +auto RequireGenericParamsOnType(Context& context, SemIR::InstBlockId block_id) -> void { if (!block_id.is_valid() || block_id == SemIR::InstBlockId::Empty) { return; } - for (auto& inst_id : context.inst_blocks().Get(block_id)) { - if (!context.constant_values().Get(inst_id).is_constant()) { + // TODO: Change GetParamFromParamRefId to return the name instead of + // inspecting param.name_id. + auto [param_id, param] = + SemIR::Function::GetParamFromParamRefId(context.sem_ir(), inst_id); + if (param.name_id == SemIR::NameId::SelfValue) { + CARBON_DIAGNOSTIC(SelfParameterNotAllowed, Error, + "`self` parameter only allowed on functions"); + context.emitter().Emit(inst_id, SelfParameterNotAllowed); + + ReplaceInstructionWithError(context, inst_id); + } else if (!context.constant_values().Get(inst_id).is_constant()) { CARBON_DIAGNOSTIC(GenericParamMustBeConstant, Error, "parameters of generic types must be constant"); context.emitter().Emit(inst_id, GenericParamMustBeConstant); - // Replace the parameter with an invalid instruction so that we don't try - // constructing a generic based on it. Note this is updating the param - // refs block, not the actual params block, so will not be directly - // reflected in SemIR output. - inst_id = context.AddInstInNoBlock( - context.insts().GetLocId(inst_id), - {.type_id = SemIR::TypeId::Error, - .name_id = SemIR::NameId::Base, - .runtime_index = SemIR::RuntimeParamIndex::Invalid}); + ReplaceInstructionWithError(context, inst_id); + } + } +} + +auto RequireGenericOrSelfImplicitFunctionParams(Context& context, + SemIR::InstBlockId block_id) + -> void { + if (!block_id.is_valid() || block_id == SemIR::InstBlockId::Empty) { + return; + } + for (auto& inst_id : context.inst_blocks().Get(block_id)) { + // TODO: Change GetParamFromParamRefId to return the name instead of + // inspecting param.name_id. + auto [param_id, param] = + SemIR::Function::GetParamFromParamRefId(context.sem_ir(), inst_id); + if (param.name_id != SemIR::NameId::SelfValue && + !context.constant_values().Get(inst_id).is_constant()) { + CARBON_DIAGNOSTIC( + ImplictParamMustBeConstant, Error, + "implicit parameters of functions must be constant or `self`"); + context.emitter().Emit(inst_id, ImplictParamMustBeConstant); + + ReplaceInstructionWithError(context, inst_id); } } } diff --git a/toolchain/check/generic.h b/toolchain/check/generic.h index 85d5f9f12343..faceadad91d1 100644 --- a/toolchain/check/generic.h +++ b/toolchain/check/generic.h @@ -73,11 +73,19 @@ auto MakeSelfSpecific(Context& context, SemIR::GenericId generic_id) auto ResolveSpecificDefinition(Context& context, SemIR::SpecificId specific_id) -> bool; -// Requires that a param block only contains generics. Diagnoses and updates the -// block otherwise. This will typically be called once for each of implicit and -// explicit parameters, and must occur before constant evaluation of the -// parameterized instruction. -auto RequireGenericParams(Context& context, SemIR::InstBlockId block_id) +// Requires that a param block only contains generics, and no parameters +// named `self`. Diagnoses and updates the block otherwise. This will typically +// be called once for each of implicit and explicit parameters, and must occur +// before constant evaluation of the parameterized instruction. +auto RequireGenericParamsOnType(Context& context, SemIR::InstBlockId block_id) + -> void; + +// Requires that a param block only contains generics or parameters +// named `self`. Diagnoses and updates the block otherwise. This is used for +// the implicit parameters of a function declaration, and must occur +// before constant evaluation of the parameterized instruction. +auto RequireGenericOrSelfImplicitFunctionParams(Context& context, + SemIR::InstBlockId block_id) -> void; } // namespace Carbon::Check diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index b89865e5fd1b..c500a7dbf4a8 100644 --- a/toolchain/check/handle_class.cpp +++ b/toolchain/check/handle_class.cpp @@ -227,8 +227,8 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id, .self_type_id = SemIR::TypeId::Invalid, .inheritance_kind = inheritance_kind}}; - RequireGenericParams(context, class_info.implicit_param_refs_id); - RequireGenericParams(context, class_info.param_refs_id); + RequireGenericParamsOnType(context, class_info.implicit_param_refs_id); + RequireGenericParamsOnType(context, class_info.param_refs_id); MergeOrAddName(context, node_id, name_context, class_decl_id, class_decl, class_info, is_definition, diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index 67f7ea677221..88a1b2ae7630 100644 --- a/toolchain/check/handle_function.cpp +++ b/toolchain/check/handle_function.cpp @@ -72,6 +72,8 @@ static auto DiagnoseModifiers(Context& context, DeclIntroducerState& introducer, static auto CheckFunctionSignature(Context& context, const NameComponent& name_and_params) -> void { + RequireGenericOrSelfImplicitFunctionParams( + context, name_and_params.implicit_params_id); SemIR::RuntimeParamIndex next_index(0); for (auto param_id : llvm::concat( context.inst_blocks().GetOrEmpty(name_and_params.implicit_params_id), diff --git a/toolchain/check/handle_impl.cpp b/toolchain/check/handle_impl.cpp index ecf1dc5b8f79..b18f31e7fe13 100644 --- a/toolchain/check/handle_impl.cpp +++ b/toolchain/check/handle_impl.cpp @@ -48,7 +48,7 @@ auto HandleParseNode(Context& context, Parse::ImplForallId node_id) -> bool { context.node_stack().Pop(); context.node_stack() .PopAndDiscardSoloNodeId(); - RequireGenericParams(context, params_id); + RequireGenericParamsOnType(context, params_id); context.node_stack().Push(node_id, params_id); return true; } diff --git a/toolchain/check/handle_interface.cpp b/toolchain/check/handle_interface.cpp index 502b9a06613d..c6260ced0823 100644 --- a/toolchain/check/handle_interface.cpp +++ b/toolchain/check/handle_interface.cpp @@ -60,8 +60,8 @@ static auto BuildInterfaceDecl(Context& context, SemIR::Interface interface_info = {name_context.MakeEntityWithParamsBase( name, interface_decl_id, /*is_extern=*/false, SemIR::LibraryNameId::Invalid)}; - RequireGenericParams(context, interface_info.implicit_param_refs_id); - RequireGenericParams(context, interface_info.param_refs_id); + RequireGenericParamsOnType(context, interface_info.implicit_param_refs_id); + RequireGenericParamsOnType(context, interface_info.param_refs_id); // Check whether this is a redeclaration. auto existing_id = context.decl_name_stack().LookupOrAddName( diff --git a/toolchain/check/testdata/class/fail_addr_not_self.carbon b/toolchain/check/testdata/class/fail_addr_not_self.carbon index 59c502c6df84..6280ed865470 100644 --- a/toolchain/check/testdata/class/fail_addr_not_self.carbon +++ b/toolchain/check/testdata/class/fail_addr_not_self.carbon @@ -10,10 +10,10 @@ class Class { // CHECK:STDERR: fail_addr_not_self.carbon:[[@LINE+4]]:8: error: `addr` can only be applied to a `self` parameter - // CHECK:STDERR: fn F[addr a: Class*](); + // CHECK:STDERR: fn F[addr a:! Class*](); // CHECK:STDERR: ^~~~ // CHECK:STDERR: - fn F[addr a: Class*](); + fn F[addr a:! Class*](); // CHECK:STDERR: fail_addr_not_self.carbon:[[@LINE+3]]:8: error: `addr` can only be applied to a `self` parameter // CHECK:STDERR: fn G(addr b: Class*); @@ -26,6 +26,7 @@ class Class { // CHECK:STDOUT: constants { // CHECK:STDOUT: %Class: type = class_type @Class [template] // CHECK:STDOUT: %.1: type = ptr_type %Class [template] +// CHECK:STDOUT: %a: %.1 = bind_symbolic_name a, 0 [symbolic] // CHECK:STDOUT: %F.type: type = fn_type @F [template] // CHECK:STDOUT: %.2: type = tuple_type () [template] // CHECK:STDOUT: %F: %F.type = struct_value () [template] @@ -59,12 +60,12 @@ class Class { // CHECK:STDOUT: // CHECK:STDOUT: class @Class { // CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { -// CHECK:STDOUT: %a.patt: %.1 = binding_pattern a +// CHECK:STDOUT: %a.patt: %.1 = symbolic_binding_pattern a, 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %Class.ref: type = name_ref Class, file.%Class.decl [template = constants.%Class] // CHECK:STDOUT: %.loc16: type = ptr_type %Class [template = constants.%.1] -// CHECK:STDOUT: %a.param: %.1 = param a, runtime_param0 -// CHECK:STDOUT: %a: %.1 = bind_name a, %a.param +// CHECK:STDOUT: %a.param: %.1 = param a, runtime_param +// CHECK:STDOUT: %a.loc16: %.1 = bind_symbolic_name a, 0, %a.param [symbolic = %a.1 (constants.%a)] // CHECK:STDOUT: } // CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { // CHECK:STDOUT: %b.patt: %.1 = binding_pattern b @@ -82,7 +83,15 @@ class Class { // CHECK:STDOUT: .G = %G.decl // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F[%a: %.1](); +// CHECK:STDOUT: generic fn @F(%a.loc16: %.1) { +// CHECK:STDOUT: %a.1: %.1 = bind_symbolic_name a, 0 [symbolic = %a.1 (constants.%a)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%a.loc16: %.1](); +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @G(%b: %.1); // CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%a) { +// CHECK:STDOUT: %a.1 => constants.%a +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/fail_self_param.carbon b/toolchain/check/testdata/class/fail_self_param.carbon new file mode 100644 index 000000000000..cb511c34eb9d --- /dev/null +++ b/toolchain/check/testdata/class/fail_self_param.carbon @@ -0,0 +1,95 @@ +// 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 +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/fail_self_param.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_self_param.carbon + +// CHECK:STDERR: fail_self_param.carbon:[[@LINE+3]]:9: error: `self` parameter only allowed on functions +// CHECK:STDERR: class C[self:! type](x:! self) {} +// CHECK:STDERR: ^~~~ +class C[self:! type](x:! self) {} +var v: C(0); + +// CHECK:STDOUT: --- fail_self_param.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %self: type = bind_symbolic_name self, 0 [symbolic] +// CHECK:STDOUT: %x: %self = bind_symbolic_name x, 1 [symbolic] +// CHECK:STDOUT: %C.type: type = generic_class_type @C [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %C.1: %C.type = struct_value () [template] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%self, %x) [symbolic] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %.3: = complete_type_witness %.2 [template] +// CHECK:STDOUT: %.4: i32 = int_literal 0 [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(i32, %.4) [template] +// CHECK:STDOUT: %.5: type = ptr_type %.2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .v = %v +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %C.decl: %C.type = class_decl @C [template = constants.%C.1] { +// CHECK:STDOUT: %self.patt: type = symbolic_binding_pattern self, 0 +// CHECK:STDOUT: %x.patt: @C.%self.1 (%self) = symbolic_binding_pattern x, 1 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: type = param self, runtime_param +// CHECK:STDOUT: %self.loc14: type = bind_symbolic_name self, 0, %self.param [symbolic = %self.1 (constants.%self)] +// CHECK:STDOUT: %self.ref: type = name_ref self, %self.loc14 [symbolic = %self.1 (constants.%self)] +// CHECK:STDOUT: %x.param: @C.%self.1 (%self) = param x, runtime_param +// CHECK:STDOUT: %x.loc14: @C.%self.1 (%self) = bind_symbolic_name x, 1, %x.param [symbolic = %x.1 (constants.%x)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.ref: %C.type = name_ref C, %C.decl [template = constants.%C.1] +// CHECK:STDOUT: %.loc15: i32 = int_literal 0 [template = constants.%.4] +// CHECK:STDOUT: %C: type = class_type @C, @C(i32, constants.%.4) [template = constants.%C.3] +// CHECK:STDOUT: %v.var: ref %C.3 = var v +// CHECK:STDOUT: %v: ref %C.3 = bind_name v, %v.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @C(%self.loc14: type, %x.loc14: @C.%self.1 (%self)) { +// CHECK:STDOUT: %self.1: type = bind_symbolic_name self, 0 [symbolic = %self.1 (constants.%self)] +// CHECK:STDOUT: %x.1: %self = bind_symbolic_name x, 1 [symbolic = %x.1 (constants.%x)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %.loc14: = complete_type_witness %.2 [template = constants.%.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(constants.%self, constants.%x) { +// CHECK:STDOUT: %self.1 => constants.%self +// CHECK:STDOUT: %x.1 => constants.%x +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(i32, constants.%.4) { +// CHECK:STDOUT: %self.1 => i32 +// CHECK:STDOUT: %x.1 => constants.%.4 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/call/no_prelude/fail_explicit_self_param.carbon b/toolchain/check/testdata/function/call/no_prelude/fail_explicit_self_param.carbon new file mode 100644 index 000000000000..9b454798653e --- /dev/null +++ b/toolchain/check/testdata/function/call/no_prelude/fail_explicit_self_param.carbon @@ -0,0 +1,58 @@ +// 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 +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/function/call/no_prelude/fail_explicit_self_param.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/call/no_prelude/fail_explicit_self_param.carbon + +// CHECK:STDERR: fail_explicit_self_param.carbon:[[@LINE+3]]:6: error: `self` can only be declared in an implicit parameter list +// CHECK:STDERR: fn F(self: ()); +// CHECK:STDERR: ^~~~~~~~ +fn F(self: ()); + +fn Run() { + F(()); +} + +// CHECK:STDOUT: --- fail_explicit_self_param.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %Run.type: type = fn_type @Run [template] +// CHECK:STDOUT: %Run: %Run.type = struct_value () [template] +// CHECK:STDOUT: %tuple: %.1 = tuple_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .Run = %Run.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %self.patt: %.1 = binding_pattern self +// CHECK:STDOUT: } { +// CHECK:STDOUT: %.loc14_13.1: %.1 = tuple_literal () +// CHECK:STDOUT: %.loc14_13.2: type = converted %.loc14_13.1, constants.%.1 [template = constants.%.1] +// CHECK:STDOUT: %self.param: %.1 = param self, runtime_param0 +// CHECK:STDOUT: %self: %.1 = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %Run.decl: %Run.type = fn_decl @Run [template = constants.%Run] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%self: %.1); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Run() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %.loc17_6: %.1 = tuple_literal () +// CHECK:STDOUT: %tuple: %.1 = tuple_value () [template = constants.%tuple] +// CHECK:STDOUT: %.loc17_4: %.1 = converted %.loc17_6, %tuple [template = constants.%tuple] +// CHECK:STDOUT: %F.call: init %.1 = call %F.ref(%.loc17_4) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/call/no_prelude/fail_runtime_implicit_param.carbon b/toolchain/check/testdata/function/call/no_prelude/fail_runtime_implicit_param.carbon new file mode 100644 index 000000000000..d81ac9db4e45 --- /dev/null +++ b/toolchain/check/testdata/function/call/no_prelude/fail_runtime_implicit_param.carbon @@ -0,0 +1,54 @@ +// 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 +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/function/call/no_prelude/fail_runtime_implicit_param.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/function/call/no_prelude/fail_runtime_implicit_param.carbon + +// CHECK:STDERR: fail_runtime_implicit_param.carbon:[[@LINE+3]]:6: error: implicit parameters of functions must be constant or `self` +// CHECK:STDERR: fn F[s: ()](); +// CHECK:STDERR: ^ +fn F[s: ()](); + +fn Run() { + F(); +} + +// CHECK:STDOUT: --- fail_runtime_implicit_param.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %Run.type: type = fn_type @Run [template] +// CHECK:STDOUT: %Run: %Run.type = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .Run = %Run.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %s.patt: %.1 = binding_pattern s +// CHECK:STDOUT: } { +// CHECK:STDOUT: %.loc14_10.1: %.1 = tuple_literal () +// CHECK:STDOUT: %.loc14_10.2: type = converted %.loc14_10.1, constants.%.1 [template = constants.%.1] +// CHECK:STDOUT: %s.param: %.1 = param s, runtime_param +// CHECK:STDOUT: %s: %.1 = bind_name s, %s.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %Run.decl: %Run.type = fn_decl @Run [template = constants.%Run] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F[%base.param: ](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Run() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [template = constants.%F] +// CHECK:STDOUT: %F.call: init %.1 = call %F.ref() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/definition/no_prelude/syntactic_merge.carbon b/toolchain/check/testdata/function/definition/no_prelude/syntactic_merge.carbon index 62f372899a5a..4e5dbd129772 100644 --- a/toolchain/check/testdata/function/definition/no_prelude/syntactic_merge.carbon +++ b/toolchain/check/testdata/function/definition/no_prelude/syntactic_merge.carbon @@ -113,15 +113,15 @@ library "[[@TEST_NAME]]"; class C {} alias D = C; -fn Foo[a: C](); -// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE+7]]:11: error: redeclaration syntax differs here -// CHECK:STDERR: fn Foo[a: D]() {} -// CHECK:STDERR: ^ -// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE-4]]:11: note: comparing with previous declaration here -// CHECK:STDERR: fn Foo[a: C](); -// CHECK:STDERR: ^ +fn Foo[a:! C](); +// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE+7]]:12: error: redeclaration syntax differs here +// CHECK:STDERR: fn Foo[a:! D]() {} +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_deduced_alias.carbon:[[@LINE-4]]:12: note: comparing with previous declaration here +// CHECK:STDERR: fn Foo[a:! C](); +// CHECK:STDERR: ^ // CHECK:STDERR: -fn Foo[a: D]() {} +fn Foo[a:! D]() {} // --- todo_fail_alias_in_return.carbon @@ -605,6 +605,7 @@ fn Foo(a: const (const C)) {} // CHECK:STDOUT: %C: type = class_type @C [template] // CHECK:STDOUT: %.1: type = struct_type {} [template] // CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %a: %C = bind_symbolic_name a, 0 [symbolic] // CHECK:STDOUT: %Foo.type: type = fn_type @Foo [template] // CHECK:STDOUT: %.3: type = tuple_type () [template] // CHECK:STDOUT: %Foo: %Foo.type = struct_value () [template] @@ -623,18 +624,18 @@ fn Foo(a: const (const C)) {} // CHECK:STDOUT: %C.ref: type = name_ref C, %C.decl [template = constants.%C] // CHECK:STDOUT: %D: type = bind_alias D, %C.decl [template = constants.%C] // CHECK:STDOUT: %Foo.decl: %Foo.type = fn_decl @Foo [template = constants.%Foo] { -// CHECK:STDOUT: %a.patt: %C = binding_pattern a +// CHECK:STDOUT: %a.patt: %C = symbolic_binding_pattern a, 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C] -// CHECK:STDOUT: %a.param: %C = param a, runtime_param0 -// CHECK:STDOUT: %a: %C = bind_name a, %a.param +// CHECK:STDOUT: %a.param: %C = param a, runtime_param +// CHECK:STDOUT: %a.loc7: %C = bind_symbolic_name a, 0, %a.param [symbolic = %a.1 (constants.%a)] // CHECK:STDOUT: } // CHECK:STDOUT: %.decl: %.type = fn_decl @.1 [template = constants.%.4] { -// CHECK:STDOUT: %a.patt: %C = binding_pattern a +// CHECK:STDOUT: %a.patt: %C = symbolic_binding_pattern a, 0 // CHECK:STDOUT: } { // CHECK:STDOUT: %D.ref: type = name_ref D, file.%D [template = constants.%C] -// CHECK:STDOUT: %a.param: %C = param a, runtime_param0 -// CHECK:STDOUT: %a: %C = bind_name a, %a.param +// CHECK:STDOUT: %a.param: %C = param a, runtime_param +// CHECK:STDOUT: %a.loc15: %C = bind_symbolic_name a, 0, %a.param [symbolic = %a.1 (constants.%a)] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -645,11 +646,29 @@ fn Foo(a: const (const C)) {} // CHECK:STDOUT: .Self = constants.%C // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Foo[%a: %C](); +// CHECK:STDOUT: generic fn @Foo(%a.loc7: %C) { +// CHECK:STDOUT: %a.1: %C = bind_symbolic_name a, 0 [symbolic = %a.1 (constants.%a)] // CHECK:STDOUT: -// CHECK:STDOUT: fn @.1[%a: %C]() { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: return +// CHECK:STDOUT: fn[%a.loc7: %C](); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @.1(%a.loc15: %C) { +// CHECK:STDOUT: %a.1: %C = bind_symbolic_name a, 0 [symbolic = %a.1 (constants.%a)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%a.loc15: %C]() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Foo(constants.%a) { +// CHECK:STDOUT: %a.1 => constants.%a +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @.1(constants.%a) { +// CHECK:STDOUT: %a.1 => constants.%a // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- todo_fail_alias_in_return.carbon diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index db2bc5957b8a..4c1218e61ce2 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -183,13 +183,15 @@ CARBON_DIAGNOSTIC_KIND(ExternRequiresDeclInApiFile) CARBON_DIAGNOSTIC_KIND(AddrSelfIsNonRef) CARBON_DIAGNOSTIC_KIND(CallArgCountMismatch) CARBON_DIAGNOSTIC_KIND(CallToNonCallable) +CARBON_DIAGNOSTIC_KIND(GenericParamMustBeConstant) +CARBON_DIAGNOSTIC_KIND(ImplictParamMustBeConstant) CARBON_DIAGNOSTIC_KIND(IncompleteReturnTypeHere) CARBON_DIAGNOSTIC_KIND(InCallToEntity) CARBON_DIAGNOSTIC_KIND(InCallToFunction) CARBON_DIAGNOSTIC_KIND(InCallToFunctionParam) CARBON_DIAGNOSTIC_KIND(InCallToFunctionSelf) CARBON_DIAGNOSTIC_KIND(MissingObjectInMethodCall) -CARBON_DIAGNOSTIC_KIND(GenericParamMustBeConstant) +CARBON_DIAGNOSTIC_KIND(SelfParameterNotAllowed) // Function declaration checking. CARBON_DIAGNOSTIC_KIND(FunctionRedeclReturnTypeDiffers)