mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
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:
@@ -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,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_
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
+34
@@ -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 {}
|
||||
|
||||
+62
@@ -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:
|
||||
|
||||
@@ -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: ]
|
||||
Reference in New Issue
Block a user