Fix parse support for 'fn F[];' (#5135)

According to approved syntax at
https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p3848.md#syntax-defined,
`fn F[]` without explicit parameters should be valid. This makes it
work, then adds some validation to prevent `class C[]` in check.

Note that for `fn`, positional parameters are a TODO -- but this allows
me to test validation in `fn destroy[]` which is rejected, not just a
TODO.
This commit is contained in:
Jon Ross-Perkins
2025-03-18 00:31:17 +00:00
committed by GitHub
parent a584ee120e
commit 8738497301
15 changed files with 402 additions and 93 deletions
+13
View File
@@ -532,4 +532,17 @@ auto GetInstForSpecific(Context& context, SemIR::SpecificId specific_id)
}
}
auto DiagnoseIfGenericMissingExplicitParameters(
Context& context, SemIR::EntityWithParamsBase& entity_base) -> void {
if (!entity_base.implicit_param_patterns_id.has_value() ||
entity_base.param_patterns_id.has_value()) {
return;
}
CARBON_DIAGNOSTIC(GenericMissingExplicitParameters, Error,
"expected explicit parameters after implicit parameters");
context.emitter().Emit(entity_base.last_param_node_id,
GenericMissingExplicitParameters);
}
} // namespace Carbon::Check
+6
View File
@@ -6,6 +6,7 @@
#define CARBON_TOOLCHAIN_CHECK_GENERIC_H_
#include "toolchain/check/context.h"
#include "toolchain/sem_ir/entity_with_params_base.h"
#include "toolchain/sem_ir/ids.h"
namespace Carbon::Check {
@@ -87,6 +88,11 @@ auto ResolveSpecificDefinition(Context& context, SemIRLoc loc,
auto GetInstForSpecific(Context& context, SemIR::SpecificId specific_id)
-> SemIR::InstId;
// Diagnoses if an entity has implicit parameters, indicating it's generic, but
// is missing explicit parameters.
auto DiagnoseIfGenericMissingExplicitParameters(
Context& context, SemIR::EntityWithParamsBase& entity_base) -> void;
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_GENERIC_H_
+2
View File
@@ -233,6 +233,8 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
.self_type_id = SemIR::TypeId::None,
.inheritance_kind = inheritance_kind}};
DiagnoseIfGenericMissingExplicitParameters(context, class_info);
MergeOrAddName(context, node_id, name_context, class_decl_id, class_decl,
class_info, is_definition,
introducer.modifier_set.GetAccessKind());
+7 -5
View File
@@ -385,11 +385,13 @@ static auto ValidateIfDestroy(Context& context, bool is_redecl,
return;
}
CARBON_CHECK(
orig_param_patterns_id.has_value(),
"TODO: Positional parameters are currently rejected as part of requiring "
"implicit parameters, because it's an invalid parse tree; add a "
"diagnostic once this is testable");
if (!orig_param_patterns_id.has_value()) {
CARBON_DIAGNOSTIC(DestroyFunctionPositionalParams, Error,
"missing empty explicit parameter list");
context.emitter().Emit(function_info.latest_decl_id(),
DestroyFunctionPositionalParams);
return;
}
if (orig_param_patterns_id != SemIR::InstBlockId::Empty) {
CARBON_DIAGNOSTIC(DestroyFunctionNonEmptyExplicitParams, Error,
+2
View File
@@ -62,6 +62,8 @@ static auto BuildInterfaceDecl(Context& context,
name, interface_decl_id, /*is_extern=*/false,
SemIR::LibraryNameId::None)};
DiagnoseIfGenericMissingExplicitParameters(context, interface_info);
// Check whether this is a redeclaration.
SemIR::ScopeLookupResult lookup_result =
context.decl_name_stack().LookupOrAddName(
+8 -8
View File
@@ -15,20 +15,20 @@ auto PopNameComponent(Context& context, SemIR::InstId return_slot_pattern_id)
Parse::NodeId last_param_node_id = Parse::NoneNodeId();
// Explicit params.
auto [params_loc_id, param_patterns_id] =
auto [params_node_id, param_patterns_id] =
context.node_stack()
.PopWithNodeIdIf<Parse::NodeKind::ExplicitParamList>();
if (param_patterns_id) {
first_param_node_id =
context.node_stack()
.PopForSoloNodeId<Parse::NodeKind::ExplicitParamListStart>();
last_param_node_id = params_loc_id;
last_param_node_id = params_node_id;
} else {
param_patterns_id = SemIR::InstBlockId::None;
}
// Implicit params.
auto [implicit_params_loc_id, implicit_param_patterns_id] =
auto [implicit_params_node_id, implicit_param_patterns_id] =
context.node_stack()
.PopWithNodeIdIf<Parse::NodeKind::ImplicitParamList>();
if (implicit_param_patterns_id) {
@@ -37,9 +37,9 @@ auto PopNameComponent(Context& context, SemIR::InstId return_slot_pattern_id)
context.node_stack()
.PopForSoloNodeId<Parse::NodeKind::ImplicitParamListStart>();
// Only use the end of implicit params if there weren't explicit params.
CARBON_CHECK(last_param_node_id.has_value(),
"Implicit parameters currently only occur before explicit "
"parameters, update and test when this changes");
if (!last_param_node_id.has_value()) {
last_param_node_id = implicit_params_node_id;
}
} else {
implicit_param_patterns_id = SemIR::InstBlockId::None;
}
@@ -64,9 +64,9 @@ auto PopNameComponent(Context& context, SemIR::InstId return_slot_pattern_id)
.name_id = name_id,
.first_param_node_id = first_param_node_id,
.last_param_node_id = last_param_node_id,
.implicit_params_loc_id = implicit_params_loc_id,
.implicit_params_loc_id = implicit_params_node_id,
.implicit_param_patterns_id = *implicit_param_patterns_id,
.params_loc_id = params_loc_id,
.params_loc_id = params_node_id,
.param_patterns_id = *param_patterns_id,
.call_params_id = call_params_id,
.return_slot_pattern_id = return_slot_pattern_id,
+24 -7
View File
@@ -73,11 +73,7 @@ class C {
library "[[@TEST_NAME]]";
class C {
// CHECK:STDERR: fail_positional_params.carbon:[[@LINE+8]]:25: error: a `(` for parameters is required after implicit parameters [ParamsRequiredAfterImplicit]
// CHECK:STDERR: fn destroy[self: Self];
// CHECK:STDERR: ^
// CHECK:STDERR:
// CHECK:STDERR: fail_positional_params.carbon:[[@LINE+4]]:3: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
// CHECK:STDERR: fail_positional_params.carbon:[[@LINE+4]]:3: error: missing empty explicit parameter list [DestroyFunctionPositionalParams]
// CHECK:STDERR: fn destroy[self: Self];
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
@@ -435,17 +431,38 @@ fn C.destroy.Foo() {}
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %destroy.type: type = fn_type @destroy [concrete]
// CHECK:STDOUT: %destroy: %destroy.type = 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: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: complete_type_witness = invalid
// CHECK:STDOUT: %destroy.decl: %destroy.type = fn_decl @destroy [concrete = constants.%destroy] {
// CHECK:STDOUT: %self.patt: %C = binding_pattern self
// CHECK:STDOUT: %self.param_patt: %C = value_param_pattern %self.patt, call_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %C = value_param call_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%C [concrete = constants.%C]
// CHECK:STDOUT: %self: %C = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: .destroy = %destroy.decl
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @destroy[%self.param_patt: %C]();
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_explicit_params.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -54,6 +54,26 @@ fn F(T:! type) {
A(T);
}
// --- fail_implicit_params_only_empty.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_implicit_params_only_empty.carbon:[[@LINE+4]]:10: error: expected explicit parameters after implicit parameters [GenericMissingExplicitParameters]
// CHECK:STDERR: class Foo[];
// CHECK:STDERR: ^~
// CHECK:STDERR:
class Foo[];
// --- fail_implicit_params_only.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_implicit_params_only.carbon:[[@LINE+4]]:10: error: expected explicit parameters after implicit parameters [GenericMissingExplicitParameters]
// CHECK:STDERR: class Foo[T:! type];
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR:
class Foo[T:! type];
// CHECK:STDOUT: --- params.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -412,3 +432,51 @@ fn F(T:! type) {
// CHECK:STDOUT: %T.patt.loc11_6.2 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_implicit_params_only_empty.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Foo.type: type = generic_class_type @Foo [concrete]
// CHECK:STDOUT: %Foo.generic: %Foo.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .Foo = %Foo.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Foo.decl: %Foo.type = class_decl @Foo [concrete = constants.%Foo.generic] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Foo;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_implicit_params_only.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic]
// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
// CHECK:STDOUT: %Foo.type: type = generic_class_type @Foo [concrete]
// CHECK:STDOUT: %Foo.generic: %Foo.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .Foo = %Foo.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Foo.decl: %Foo.type = class_decl @Foo [concrete = constants.%Foo.generic] {
// CHECK:STDOUT: %T.patt.loc8_11.1: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc8_11.2 (constants.%T.patt)]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %T.loc8_11.1: type = bind_symbolic_name T, 0 [symbolic = %T.loc8_11.2 (constants.%T)]
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic class @Foo(%T.loc8_11.1: type) {
// CHECK:STDOUT: %T.loc8_11.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc8_11.2 (constants.%T)]
// CHECK:STDOUT: %T.patt.loc8_11.2: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc8_11.2 (constants.%T.patt)]
// CHECK:STDOUT:
// CHECK:STDOUT: class;
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Foo(constants.%T) {
// CHECK:STDOUT: %T.loc8_11.2 => constants.%T
// CHECK:STDOUT: %T.patt.loc8_11.2 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -36,6 +36,15 @@ library "[[@TEST_NAME]]";
// CHECK:STDERR:
fn A -> ();
// --- fail_todo_implicit_only.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_todo_implicit_only.carbon:[[@LINE+4]]:1: error: semantics TODO: `function with positional parameters` [SemanticsTodo]
// CHECK:STDERR: fn A[] -> ();
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
fn A[] -> ();
// --- fail_todo_arrow_body.carbon
// TODO: We don't have parsing support for this yet.
@@ -128,6 +137,31 @@ fn A {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @A() -> %empty_tuple.type;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_implicit_only.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %A.type: type = fn_type @A [concrete]
// CHECK:STDOUT: %A: %A.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .A = %A.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %A.decl: %A.type = fn_decl @A [concrete = constants.%A] {
// CHECK:STDOUT: %return.patt: %empty_tuple.type = return_slot_pattern
// CHECK:STDOUT: %return.param_patt: %empty_tuple.type = out_param_pattern %return.patt, call_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %.loc7_12.1: %empty_tuple.type = tuple_literal ()
// CHECK:STDOUT: %.loc7_12.2: type = converted %.loc7_12.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type]
// CHECK:STDOUT: %return.param: ref %empty_tuple.type = out_param call_param0
// CHECK:STDOUT: %return: ref %empty_tuple.type = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @A[]() -> %empty_tuple.type;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_arrow_body.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: file {}
@@ -46,6 +46,31 @@ fn Foo(a: C);
// CHECK:STDERR:
fn Foo(a: (C)) {}
// --- fail_only_implicit_params.carbon
library "[[@TEST_NAME]]";
class C {}
// CHECK:STDERR: fail_only_implicit_params.carbon:[[@LINE+8]]:8: error: implicit parameters of functions must be constant or `self` [ImplictParamMustBeConstant]
// CHECK:STDERR: fn Foo[a: C];
// CHECK:STDERR: ^~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_only_implicit_params.carbon:[[@LINE+4]]:1: error: semantics TODO: `function with positional parameters` [SemanticsTodo]
// CHECK:STDERR: fn Foo[a: C];
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
fn Foo[a: C];
// CHECK:STDERR: fail_only_implicit_params.carbon:[[@LINE+8]]:8: error: implicit parameters of functions must be constant or `self` [ImplictParamMustBeConstant]
// CHECK:STDERR: fn Foo[a: (C)] {}
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_only_implicit_params.carbon:[[@LINE+4]]:1: error: semantics TODO: `function with positional parameters` [SemanticsTodo]
// CHECK:STDERR: fn Foo[a: (C)] {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
// CHECK:STDERR:
fn Foo[a: (C)] {}
// --- todo_fail_raw_identifier.carbon
library "[[@TEST_NAME]]";
@@ -341,6 +366,43 @@ fn Foo(a: const (const C)) {}
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_only_implicit_params.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
// CHECK:STDOUT: %Foo.type.a02530.1: type = fn_type @Foo.1 [concrete]
// CHECK:STDOUT: %Foo.ddeb7d.1: %Foo.type.a02530.1 = struct_value () [concrete]
// CHECK:STDOUT: %Foo.type.a02530.2: type = fn_type @Foo.2 [concrete]
// CHECK:STDOUT: %Foo.ddeb7d.2: %Foo.type.a02530.2 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: .Foo = %Foo.decl.loc14
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %Foo.decl.loc14: %Foo.type.a02530.1 = fn_decl @Foo.1 [concrete = constants.%Foo.ddeb7d.1] {} {}
// CHECK:STDOUT: %Foo.decl.loc23: %Foo.type.a02530.2 = fn_decl @Foo.2 [concrete = constants.%Foo.ddeb7d.2] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Foo.1[<error>: <error>]();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Foo.2[<error>: <error>]() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- todo_fail_raw_identifier.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -48,6 +48,26 @@ library "[[@TEST_NAME]]";
// CHECK:STDERR:
interface A(T: type) {}
// --- fail_implicit_params_only_empty.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_implicit_params_only_empty.carbon:[[@LINE+4]]:14: error: expected explicit parameters after implicit parameters [GenericMissingExplicitParameters]
// CHECK:STDERR: interface Bar[] {}
// CHECK:STDERR: ^~
// CHECK:STDERR:
interface Bar[] {}
// --- fail_implicit_params_only.carbon
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_implicit_params_only.carbon:[[@LINE+4]]:14: error: expected explicit parameters after implicit parameters [GenericMissingExplicitParameters]
// CHECK:STDERR: interface Bar[T:! type] {}
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR:
interface Bar[T:! type] {}
// CHECK:STDOUT: --- params.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -371,3 +391,73 @@ interface A(T: type) {}
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_implicit_params_only_empty.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Bar.type.982: type = generic_interface_type @Bar [concrete]
// CHECK:STDOUT: %Bar.generic: %Bar.type.982 = struct_value () [concrete]
// CHECK:STDOUT: %Bar.type.ea3: type = facet_type <@Bar> [concrete]
// CHECK:STDOUT: %Self: %Bar.type.ea3 = bind_symbolic_name Self, 0 [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .Bar = %Bar.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Bar.decl: %Bar.type.982 = interface_decl @Bar [concrete = constants.%Bar.generic] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @Bar {
// CHECK:STDOUT: %Self: %Bar.type.ea3 = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_implicit_params_only.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic]
// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic]
// CHECK:STDOUT: %Bar.type.982: type = generic_interface_type @Bar [concrete]
// CHECK:STDOUT: %Bar.generic: %Bar.type.982 = struct_value () [concrete]
// CHECK:STDOUT: %Bar.type.7ed: type = facet_type <@Bar, @Bar(%T)> [symbolic]
// CHECK:STDOUT: %Self: %Bar.type.7ed = bind_symbolic_name Self, 1 [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .Bar = %Bar.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Bar.decl: %Bar.type.982 = interface_decl @Bar [concrete = constants.%Bar.generic] {
// CHECK:STDOUT: %T.patt.loc8_15.1: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc8_15.2 (constants.%T.patt)]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %T.loc8_15.1: type = bind_symbolic_name T, 0 [symbolic = %T.loc8_15.2 (constants.%T)]
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic interface @Bar(%T.loc8_15.1: type) {
// CHECK:STDOUT: %T.loc8_15.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc8_15.2 (constants.%T)]
// CHECK:STDOUT: %T.patt.loc8_15.2: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc8_15.2 (constants.%T.patt)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %Bar.type: type = facet_type <@Bar, @Bar(%T.loc8_15.2)> [symbolic = %Bar.type (constants.%Bar.type.7ed)]
// CHECK:STDOUT: %Self.2: %Bar.type.7ed = bind_symbolic_name Self, 1 [symbolic = %Self.2 (constants.%Self)]
// CHECK:STDOUT:
// CHECK:STDOUT: interface {
// CHECK:STDOUT: %Self.1: @Bar.%Bar.type (%Bar.type.7ed) = bind_symbolic_name Self, 1 [symbolic = %Self.2 (constants.%Self)]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self.1
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Bar(constants.%T) {
// CHECK:STDOUT: %T.loc8_15.2 => constants.%T
// CHECK:STDOUT: %T.patt.loc8_15.2 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Bar(%T.loc8_15.2) {}
// CHECK:STDOUT:
+4 -1
View File
@@ -138,7 +138,6 @@ CARBON_DIAGNOSTIC_KIND(ExpectedDeclName)
CARBON_DIAGNOSTIC_KIND(ExpectedDeclNameAfterPeriod)
CARBON_DIAGNOSTIC_KIND(ExpectedDeclSemi)
CARBON_DIAGNOSTIC_KIND(ExpectedDeclSemiOrDefinition)
CARBON_DIAGNOSTIC_KIND(ParamsRequiredAfterImplicit)
CARBON_DIAGNOSTIC_KIND(ExpectedAfterBase)
CARBON_DIAGNOSTIC_KIND(ExpectedBuiltinName)
CARBON_DIAGNOSTIC_KIND(ImplExpectedAfterForall)
@@ -240,6 +239,7 @@ CARBON_DIAGNOSTIC_KIND(InvalidBuiltinSignature)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionOutsideClass)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionMissingSelf)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionUnexpectedImplicitParam)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionPositionalParams)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionNonEmptyExplicitParams)
CARBON_DIAGNOSTIC_KIND(DestroyFunctionIncorrectReturnType)
@@ -465,6 +465,9 @@ CARBON_DIAGNOSTIC_KIND(RewriteForAssociatedFunction)
// Facet type combination.
CARBON_DIAGNOSTIC_KIND(FacetTypeRequiredForTypeAndOperator)
// Generics.
CARBON_DIAGNOSTIC_KIND(GenericMissingExplicitParameters)
// Pattern matching diagnostics.
CARBON_DIAGNOSTIC_KIND(TuplePatternSizeDoesntMatchLiteral)
@@ -86,17 +86,13 @@ auto HandleDeclNameAndParams(Context& context) -> void {
auto HandleDeclNameAndParamsAfterImplicit(Context& context) -> void {
auto state = context.PopState();
state.state = State::DeclNameAndParamsAfterParams;
context.PushState(state);
if (!context.PositionIs(Lex::TokenKind::OpenParen)) {
CARBON_DIAGNOSTIC(
ParamsRequiredAfterImplicit, Error,
"a `(` for parameters is required after implicit parameters");
context.emitter().Emit(*context.position(), ParamsRequiredAfterImplicit);
context.ReturnErrorOnState();
return;
}
state.state = State::DeclNameAndParamsAfterParams;
context.PushState(state);
context.PushState(State::PatternListAsExplicit);
}
@@ -1,65 +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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/generics/deduced_params/fail_no_parens.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/generics/deduced_params/fail_no_parens.carbon
// CHECK:STDERR: fail_no_parens.carbon:[[@LINE+4]]:12: error: a `(` for parameters is required after implicit parameters [ParamsRequiredAfterImplicit]
// CHECK:STDERR: class Foo[];
// CHECK:STDERR: ^
// CHECK:STDERR:
class Foo[];
// CHECK:STDERR: fail_no_parens.carbon:[[@LINE+4]]:18: error: a `(` for parameters is required after implicit parameters [ParamsRequiredAfterImplicit]
// CHECK:STDERR: class Foo[a: i32];
// CHECK:STDERR: ^
// CHECK:STDERR:
class Foo[a: i32];
// CHECK:STDERR: fail_no_parens.carbon:[[@LINE+4]]:17: error: a `(` for parameters is required after implicit parameters [ParamsRequiredAfterImplicit]
// CHECK:STDERR: interface Bar[] {}
// CHECK:STDERR: ^
// CHECK:STDERR:
interface Bar[] {}
// CHECK:STDERR: fail_no_parens.carbon:[[@LINE+4]]:23: error: a `(` for parameters is required after implicit parameters [ParamsRequiredAfterImplicit]
// CHECK:STDERR: interface Bar[a: i32] {}
// CHECK:STDERR: ^
// CHECK:STDERR:
interface Bar[a: i32] {}
// CHECK:STDOUT: - filename: fail_no_parens.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 2},
// CHECK:STDOUT: {kind: 'ClassDecl', text: ';', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'a'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ClassDecl', text: ';', has_error: yes, subtree_size: 8},
// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Bar'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InterfaceDecl', text: '}', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Bar'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'a'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5},
// CHECK:STDOUT: {kind: 'InterfaceDecl', text: '}', has_error: yes, subtree_size: 8},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
@@ -0,0 +1,79 @@
// 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/parse/testdata/generics/deduced_params/no_parens.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/generics/deduced_params/no_parens.carbon
// --- class.carbon
class Foo[];
class Foo[a: i32];
// --- interface.carbon
interface Bar[] {}
interface Bar[a: i32] {}
// --- qualified.carbon
interface Bar[].Baz[] {}
// CHECK:STDOUT: - filename: class.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 2},
// CHECK:STDOUT: {kind: 'ClassDecl', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'a'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ClassDecl', text: ';', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: interface.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Bar'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 6},
// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Bar'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'a'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5},
// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 8},
// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 9},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: qualified.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Bar'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameQualifierWithParams', text: '.', subtree_size: 4},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'Baz'},
// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['},
// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 9},
// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 10},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]