mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
Reject abstract types in var function parameters (#6499)
### Description Fixes an issue where the toolchain accepted abstract types in function parameters declared with `var`. ### Changes - Implemented a check for abstract types for function parameters with `var` binding pattern in `HandleAnyBindingPattern`. - Added a test case to `toolchain/check/testdata/class/fail_abstract.carbon`. **Note:** I did not use `AsConcreteType` like used in `case FullPatternStack::Kind::NameBindingDecl`. Using it enforces type completion, thus causing valid signatures such as `fn F[var self: Self]` to fail. Also the pre-commit checks fail due to a diagnostic name collision with `toolchain/check/type_completion.cpp`. Should I add a function that just checks if the type is abstract to share the diagnostic? Fixes #6402
This commit is contained in:
@@ -158,6 +158,15 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
return binding.pattern_id;
|
||||
};
|
||||
|
||||
auto abstract_diagnoser = [&] {
|
||||
CARBON_DIAGNOSTIC(AbstractTypeInVarPattern, Error,
|
||||
"binding pattern has abstract type {0} in `var` "
|
||||
"pattern",
|
||||
SemIR::TypeId);
|
||||
return context.emitter().Build(type_node, AbstractTypeInVarPattern,
|
||||
cast_type_id);
|
||||
};
|
||||
|
||||
// A `self` binding can only appear in an implicit parameter list.
|
||||
if (name_id == SemIR::NameId::SelfValue &&
|
||||
!context.node_stack().PeekIs(Parse::NodeKind::ImplicitParamListStart)) {
|
||||
@@ -192,6 +201,29 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
break;
|
||||
}
|
||||
|
||||
// Using `AsConcreteType` here causes `fn F[var self: Self]();`
|
||||
// to fail since `Self` is an incomplete type.
|
||||
if (node_kind == Parse::NodeKind::VarBindingPattern) {
|
||||
auto [unqualified_type_id, qualifiers] =
|
||||
context.types().GetUnqualifiedTypeAndQualifiers(cast_type_id);
|
||||
if ((qualifiers & SemIR::TypeQualifiers::Partial) !=
|
||||
SemIR::TypeQualifiers::Partial &&
|
||||
context.types().Is<SemIR::ClassType>(unqualified_type_id)) {
|
||||
auto class_type =
|
||||
context.types().GetAs<SemIR::ClassType>(unqualified_type_id);
|
||||
auto& class_info = context.classes().Get(class_type.class_id);
|
||||
if (class_info.inheritance_kind ==
|
||||
SemIR::Class::InheritanceKind::Abstract) {
|
||||
auto builder = abstract_diagnoser();
|
||||
auto direct_use = true;
|
||||
NoteAbstractClass(context, class_type.class_id, direct_use,
|
||||
builder);
|
||||
builder.Emit();
|
||||
cast_type_id = SemIR::ErrorInst::TypeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto result_inst_id = make_binding_pattern();
|
||||
|
||||
// A binding pattern in a function signature is a `Call` parameter
|
||||
@@ -228,16 +260,8 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
cast_type_inst_id);
|
||||
};
|
||||
if (node_kind == Parse::NodeKind::VarBindingPattern) {
|
||||
cast_type_id = AsConcreteType(
|
||||
context, cast_type_id, type_node, incomplete_diagnoser, [&] {
|
||||
CARBON_DIAGNOSTIC(
|
||||
AbstractTypeInVarPattern, Error,
|
||||
"binding pattern has abstract type {0} in `var` "
|
||||
"pattern",
|
||||
SemIR::TypeId);
|
||||
return context.emitter().Build(
|
||||
type_node, AbstractTypeInVarPattern, cast_type_id);
|
||||
});
|
||||
cast_type_id = AsConcreteType(context, cast_type_id, type_node,
|
||||
incomplete_diagnoser, abstract_diagnoser);
|
||||
} else {
|
||||
cast_type_id = AsCompleteType(context, cast_type_id, type_node,
|
||||
incomplete_diagnoser);
|
||||
|
||||
Reference in New Issue
Block a user