mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 08:54:47 +01:00
Add support for field initializers (#7238)
In handle_let_and_var.cpp, field initializers are now handled like regular `var` initializers, by calling `LocalPatternMatch`. In pattern_match.cpp, `FieldDecl`s with initializers are handled by storing a value in `SemIR::File::field_initializers()`. This is a new map where the keys are `FieldDecl` `InstId`s and the map values are `InstId`s representing the initializer value. In convert.cpp, `ConvertStructToStructOrClass` now has a `get_default` function parameter that callers can use to provide a field default. `ConvertStructToClass` uses this to provide a default from field initializers.
This commit is contained in:
@@ -353,6 +353,9 @@ class Context {
|
||||
auto facet_types() -> SemIR::FacetTypeInfoStore& {
|
||||
return sem_ir().facet_types();
|
||||
}
|
||||
auto field_initializers() -> SemIR::File::FieldInitializerMap& {
|
||||
return sem_ir().field_initializers();
|
||||
}
|
||||
auto identified_facet_types() -> SemIR::IdentifiedFacetTypeStore& {
|
||||
return sem_ir().identified_facet_types();
|
||||
}
|
||||
|
||||
+114
-55
@@ -609,10 +609,10 @@ static auto ConvertPartialInitializerToNonPartial(
|
||||
}
|
||||
|
||||
// Common implementation for ConvertStructToStruct and ConvertStructToClass.
|
||||
template <typename TargetAccessInstT>
|
||||
template <typename TargetAccessInstT, typename GetDefault>
|
||||
static auto ConvertStructToStructOrClass(
|
||||
Context& context, SemIR::StructType src_type, SemIR::StructType dest_type,
|
||||
SemIR::InstId value_id, ConversionTarget target,
|
||||
SemIR::InstId value_id, ConversionTarget target, GetDefault get_default,
|
||||
SemIR::ClassType* vtable_class_type = nullptr) -> SemIR::InstId {
|
||||
static_assert(std::is_same_v<SemIR::ClassElementAccess, TargetAccessInstT> ||
|
||||
std::is_same_v<SemIR::StructAccess, TargetAccessInstT>);
|
||||
@@ -641,28 +641,38 @@ static auto ConvertStructToStructOrClass(
|
||||
value_id = MaterializeIfInitializer(context, value_id);
|
||||
}
|
||||
|
||||
// Check that the structs are the same size.
|
||||
// TODO: If not, include the name of the first source field that doesn't
|
||||
// exist in the destination or vice versa in the diagnostic.
|
||||
if (src_elem_fields.size() != dest_elem_fields_size) {
|
||||
if (target.diagnose) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
StructInitElementCountMismatch, Error,
|
||||
"cannot initialize {0:class|struct} with {1} field{1:s} from struct "
|
||||
"with {2} field{2:s}",
|
||||
Diagnostics::BoolAsSelect, Diagnostics::IntAsSelect,
|
||||
Diagnostics::IntAsSelect);
|
||||
context.emitter().Emit(value_loc_id, StructInitElementCountMismatch,
|
||||
ToClass, dest_elem_fields_size,
|
||||
src_elem_fields.size());
|
||||
}
|
||||
return SemIR::ErrorInst::InstId;
|
||||
Set<SemIR::NameId> dest_field_names;
|
||||
for (auto field : dest_elem_fields) {
|
||||
dest_field_names.Insert(field.name_id);
|
||||
}
|
||||
|
||||
// Prepare to look up fields in the source by index.
|
||||
// Prepare to look up fields in the source by index. Also check for
|
||||
// source fields that don't match any field in the destination.
|
||||
Map<SemIR::NameId, int32_t> src_field_indexes;
|
||||
if (src_type.fields_id != dest_type.fields_id) {
|
||||
for (auto [i, field] : llvm::enumerate(src_elem_fields)) {
|
||||
if (!dest_field_names.Lookup(field.name_id)) {
|
||||
if (target.diagnose) {
|
||||
if (literal_elems_id.has_value()) {
|
||||
CARBON_DIAGNOSTIC(StructInitUnexpectedFieldInLiteral, Error,
|
||||
"struct {0} has no field named `{1}`",
|
||||
SemIR::TypeId, SemIR::NameId);
|
||||
context.emitter().Emit(value_loc_id,
|
||||
StructInitUnexpectedFieldInLiteral,
|
||||
target.type_id, field.name_id);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(StructInitUnexpectedFieldInConversion, Error,
|
||||
"cannot convert from struct type {0} to {1}: "
|
||||
"unexpected field `{2}` in source type",
|
||||
TypeOfInstId, SemIR::TypeId, SemIR::NameId);
|
||||
context.emitter().Emit(value_loc_id,
|
||||
StructInitUnexpectedFieldInConversion,
|
||||
value_id, target.type_id, field.name_id);
|
||||
}
|
||||
}
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
auto result = src_field_indexes.Insert(field.name_id, i);
|
||||
CARBON_CHECK(result.is_inserted(), "Duplicate field in source structure");
|
||||
}
|
||||
@@ -675,7 +685,8 @@ static auto ConvertStructToStructOrClass(
|
||||
// of the source.
|
||||
// TODO: Annotate diagnostics coming from here with the element index.
|
||||
auto new_block =
|
||||
literal_elems_id.has_value() && !dest_vptr_index.has_value()
|
||||
literal_elems_id.has_value() && !dest_vptr_index.has_value() &&
|
||||
literal_elems.size() == dest_elem_fields_size
|
||||
? SemIR::CopyOnWriteInstBlock(&sem_ir, literal_elems_id)
|
||||
: SemIR::CopyOnWriteInstBlock(
|
||||
&sem_ir, SemIR::CopyOnWriteInstBlock::UninitializedBlock{
|
||||
@@ -717,33 +728,14 @@ static auto ConvertStructToStructOrClass(
|
||||
|
||||
// Find the matching source field.
|
||||
auto src_field_index = i;
|
||||
bool found = true;
|
||||
if (src_type.fields_id != dest_type.fields_id) {
|
||||
if (auto lookup = src_field_indexes.Lookup(dest_field.name_id)) {
|
||||
src_field_index = lookup.value();
|
||||
} else {
|
||||
if (target.diagnose) {
|
||||
if (literal_elems_id.has_value()) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
StructInitMissingFieldInLiteral, Error,
|
||||
"missing value for field `{0}` in struct initialization",
|
||||
SemIR::NameId);
|
||||
context.emitter().Emit(value_loc_id,
|
||||
StructInitMissingFieldInLiteral,
|
||||
dest_field.name_id);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(StructInitMissingFieldInConversion, Error,
|
||||
"cannot convert from struct type {0} to {1}: "
|
||||
"missing field `{2}` in source type",
|
||||
TypeOfInstId, SemIR::TypeId, SemIR::NameId);
|
||||
context.emitter().Emit(value_loc_id,
|
||||
StructInitMissingFieldInConversion, value_id,
|
||||
target.type_id, dest_field.name_id);
|
||||
}
|
||||
}
|
||||
return SemIR::ErrorInst::InstId;
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
auto src_field = src_elem_fields[src_field_index];
|
||||
|
||||
// When initializing the `.base` field of a class, the destination type is
|
||||
// `partial Base`, not `Base`.
|
||||
@@ -758,23 +750,51 @@ static auto ConvertStructToStructOrClass(
|
||||
dest_field_type_inst_id = context.types().GetTypeInstId(partial_type_id);
|
||||
}
|
||||
|
||||
// TODO: This call recurses back into conversion. Switch to an iterative
|
||||
// approach.
|
||||
auto dest_field_index = src_field_index;
|
||||
if (dest_vptr_index.has_value() &&
|
||||
static_cast<int32_t>(src_field_index) >= dest_vptr_index.index) {
|
||||
dest_field_index += 1;
|
||||
SemIR::InstId init_id = SemIR::InstId::None;
|
||||
if (found) {
|
||||
auto src_field = src_elem_fields[src_field_index];
|
||||
|
||||
// TODO: This call recurses back into conversion. Switch to an iterative
|
||||
// approach.
|
||||
auto dest_field_index = src_field_index;
|
||||
if (dest_vptr_index.has_value() &&
|
||||
static_cast<int32_t>(src_field_index) >= dest_vptr_index.index) {
|
||||
dest_field_index += 1;
|
||||
}
|
||||
init_id = ConvertAggregateElement<SemIR::StructAccess, TargetAccessInstT>(
|
||||
context, value_loc_id, value_id, src_field.type_inst_id,
|
||||
literal_elems, inner_kind, target.storage_id, dest_field_type_inst_id,
|
||||
target.storage_access_block, src_field_index, dest_field_index);
|
||||
} else {
|
||||
init_id = get_default(dest_field.name_id);
|
||||
}
|
||||
auto init_id =
|
||||
ConvertAggregateElement<SemIR::StructAccess, TargetAccessInstT>(
|
||||
context, value_loc_id, value_id, src_field.type_inst_id,
|
||||
literal_elems, inner_kind, target.storage_id,
|
||||
dest_field_type_inst_id, target.storage_access_block,
|
||||
src_field_index, dest_field_index);
|
||||
|
||||
if (init_id == SemIR::ErrorInst::InstId) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
if (!init_id.has_value()) {
|
||||
if (target.diagnose) {
|
||||
if (literal_elems_id.has_value()) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
StructInitMissingFieldInLiteral, Error,
|
||||
"missing value for field `{0}` in struct initialization",
|
||||
SemIR::NameId);
|
||||
context.emitter().Emit(value_loc_id, StructInitMissingFieldInLiteral,
|
||||
dest_field.name_id);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(StructInitMissingFieldInConversion, Error,
|
||||
"cannot convert from struct type {0} to {1}: "
|
||||
"missing field `{2}` in source type",
|
||||
TypeOfInstId, SemIR::TypeId, SemIR::NameId);
|
||||
context.emitter().Emit(value_loc_id,
|
||||
StructInitMissingFieldInConversion, value_id,
|
||||
target.type_id, dest_field.name_id);
|
||||
}
|
||||
}
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
// When initializing the base, adjust the type of the initializer from
|
||||
// `partial Base` to `Base`. This isn't strictly correct, since we haven't
|
||||
// finished initializing a `Base` until we store to the vptr, but is better
|
||||
@@ -825,7 +845,8 @@ static auto ConvertStructToStruct(Context& context, SemIR::StructType src_type,
|
||||
SemIR::InstId value_id,
|
||||
ConversionTarget target) -> SemIR::InstId {
|
||||
return ConvertStructToStructOrClass<SemIR::StructAccess>(
|
||||
context, src_type, dest_type, value_id, target);
|
||||
context, src_type, dest_type, value_id, target,
|
||||
/*get_default=*/[](SemIR::NameId) { return SemIR::InstId::None; });
|
||||
}
|
||||
|
||||
// Performs a conversion from a struct to a class type. This function only
|
||||
@@ -863,8 +884,46 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type,
|
||||
SemIR::LocId(value_id), {.type_id = target.type_id});
|
||||
}
|
||||
|
||||
const auto& dest_class_scope =
|
||||
context.name_scopes().Get(dest_class_info.scope_id);
|
||||
|
||||
// Provide the default value for a field. Returns `InstId::None` if no
|
||||
// default is available, or `ErrorInst::InstId` if a diagnosed error
|
||||
// occurs.
|
||||
auto get_default = [&](SemIR::NameId name_id) {
|
||||
if (!context.insts().Is<SemIR::StructLiteral>(value_id)) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
|
||||
// Look up the field name in the class to get the corresponding
|
||||
// `FieldDecl` `InstId`.
|
||||
auto entry_id = dest_class_scope.Lookup(name_id);
|
||||
if (!entry_id.has_value()) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
|
||||
// Look up the initializer `InstId` for the field and eval as a
|
||||
// constant.
|
||||
auto field_inst_id =
|
||||
dest_class_scope.GetEntry(*entry_id).result.target_inst_id();
|
||||
auto lookup = context.field_initializers().Lookup(field_inst_id);
|
||||
if (!lookup) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
auto initializer_id = lookup.value();
|
||||
SemIR::ConstantId const_id = SemIR::ConstantId::NotConstant;
|
||||
const_id = GetConstantValueInSpecific(
|
||||
context.sem_ir(), dest_type.specific_id, initializer_id);
|
||||
if (const_id == SemIR::ConstantId::NotConstant) {
|
||||
context.TODO(initializer_id, "field initializer is not constant");
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
return context.constant_values().GetInstId(const_id);
|
||||
};
|
||||
|
||||
return ConvertStructToStructOrClass<SemIR::ClassElementAccess>(
|
||||
context, src_type, dest_struct_type, value_id, target,
|
||||
context, src_type, dest_struct_type, value_id, target, get_default,
|
||||
is_partial ? nullptr : &dest_type);
|
||||
}
|
||||
|
||||
|
||||
@@ -126,12 +126,13 @@ auto HandleParseNode(Context& context, Parse::VariablePatternId node_id)
|
||||
pattern_id = AddInst<SemIR::VarPattern>(
|
||||
context, node_id,
|
||||
{.type_id = type_id, .subpattern_id = subpattern_id});
|
||||
break;
|
||||
} else {
|
||||
// For non-static class fields, a `FieldDecl` has already been
|
||||
// created; do not create a var pattern.
|
||||
return true;
|
||||
// For non-static class fields, a `FieldDecl` was created in
|
||||
// `AddBindingPattern`. Use that as the `pattern_id` so that
|
||||
// it's available when handling initializers.
|
||||
pattern_id = context.field_decls_stack().PeekArray().back();
|
||||
}
|
||||
break;
|
||||
case FullPatternStack::Kind::NotInEitherParamList:
|
||||
CARBON_FATAL("Unreachable");
|
||||
}
|
||||
@@ -209,11 +210,6 @@ auto HandleParseNode(Context& context,
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::VariableInitializerId node_id)
|
||||
-> bool {
|
||||
if (InNonStaticFieldDecl(context)) {
|
||||
context.TODO(node_id, "Field initializer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return HandleInitializer(context, node_id);
|
||||
}
|
||||
|
||||
@@ -298,9 +294,7 @@ static auto HandleDecl(Context& context, Parse::NodeId node_id) -> DeclInfo {
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_non_static_field_decl) {
|
||||
decl_info.pattern_id = context.node_stack().PopPattern();
|
||||
}
|
||||
decl_info.pattern_id = context.node_stack().PopPattern();
|
||||
|
||||
context.node_stack().PopAndDiscardSoloNodeId<IntroducerNodeKind>();
|
||||
|
||||
@@ -411,9 +405,7 @@ auto HandleParseNode(Context& context, Parse::VariableDeclId node_id) -> bool {
|
||||
KeywordModifierSet::Returned |
|
||||
KeywordModifierSet::Static);
|
||||
|
||||
if (!InNonStaticFieldDecl(context)) {
|
||||
LocalPatternMatch(context, decl_info.pattern_id, decl_info.init_id);
|
||||
}
|
||||
LocalPatternMatch(context, decl_info.pattern_id, decl_info.init_id);
|
||||
|
||||
context.full_pattern_stack().PopFullPattern();
|
||||
context.decl_introducer_state_stack().Pop<Lex::TokenKind::Var>();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/control_flow.h"
|
||||
#include "toolchain/check/convert.h"
|
||||
#include "toolchain/check/eval.h"
|
||||
#include "toolchain/check/pattern.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/diagnostics/format_providers.h"
|
||||
@@ -177,6 +178,8 @@ class MatchContext {
|
||||
SemIR::InstId scrutinee_id, WorkItem entry) -> void;
|
||||
auto DoPreWork(State state, SemIR::ExprPattern expr_pattern,
|
||||
SemIR::InstId scrutinee_id, WorkItem entry) -> void;
|
||||
auto DoPreWork(State state, SemIR::FieldDecl field_decl,
|
||||
SemIR::InstId scrutinee_id, WorkItem entry) -> void;
|
||||
auto DoPreWork(State state, SemIR::ReturnSlotPattern return_slot_pattern,
|
||||
SemIR::InstId scrutinee_id, WorkItem entry) -> void;
|
||||
auto DoPreWork(State state, SemIR::VarPattern var_pattern,
|
||||
@@ -537,6 +540,29 @@ auto MatchContext::DoPostWork(State /*state*/,
|
||||
SemIR::ExprPattern /*expr_pattern*/,
|
||||
WorkItem /*entry*/) -> void {}
|
||||
|
||||
auto MatchContext::DoPreWork(State /*state*/, SemIR::FieldDecl field_decl,
|
||||
SemIR::InstId scrutinee_id, WorkItem entry)
|
||||
-> void {
|
||||
if (!scrutinee_id.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the field initializer.
|
||||
auto unbound_element_type = context_.insts().GetAs<SemIR::UnboundElementType>(
|
||||
context_.types().GetTypeInstId(field_decl.type_id));
|
||||
auto element_type = context_.types().GetTypeIdForTypeInstId(
|
||||
unbound_element_type.element_type_inst_id);
|
||||
auto converted_id = ConvertToValueOfType(context_, SemIR::LocId(scrutinee_id),
|
||||
scrutinee_id, element_type,
|
||||
/*diagnose=*/true);
|
||||
if (converted_id == SemIR::ErrorInst::InstId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store a mapping to the field's initializer.
|
||||
context_.field_initializers().Insert(entry.pattern_id, converted_id);
|
||||
}
|
||||
|
||||
auto MatchContext::DoPreWork(State state,
|
||||
SemIR::ReturnSlotPattern return_slot_pattern,
|
||||
SemIR::InstId scrutinee_id, WorkItem entry)
|
||||
@@ -838,6 +864,10 @@ auto MatchContext::Dispatch(State state, WorkItem entry) -> void {
|
||||
DoPreWork(state, expr_pattern, work.scrutinee_id, entry);
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::FieldDecl field_decl): {
|
||||
DoPreWork(state, field_decl, work.scrutinee_id, entry);
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::ReturnSlotPattern return_slot_pattern): {
|
||||
DoPreWork(state, return_slot_pattern, work.scrutinee_id, entry);
|
||||
break;
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ library "[[@TEST_NAME]]";
|
||||
choice Never {}
|
||||
|
||||
// TODO: Can we produce a better diagnostic?
|
||||
// CHECK:STDERR: fail_no_alternative_construct.carbon:[[@LINE+4]]:20: error: cannot initialize class with 1 field from struct with 0 fields [StructInitElementCountMismatch]
|
||||
// CHECK:STDERR: fail_no_alternative_construct.carbon:[[@LINE+4]]:20: error: missing value for field `discriminant` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
// CHECK:STDERR: let never: Never = {};
|
||||
// CHECK:STDERR: ^~
|
||||
// CHECK:STDERR:
|
||||
|
||||
+3
-3
@@ -16,17 +16,17 @@ class Class {
|
||||
}
|
||||
|
||||
fn F() {
|
||||
// CHECK:STDERR: fail_init.carbon:[[@LINE+4]]:3: error: cannot initialize class with 2 fields from struct with 1 field [StructInitElementCountMismatch]
|
||||
// CHECK:STDERR: fail_init.carbon:[[@LINE+4]]:3: error: missing value for field `b` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
// CHECK:STDERR: {.a = 1} as Class;
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
{.a = 1} as Class;
|
||||
// CHECK:STDERR: fail_init.carbon:[[@LINE+4]]:3: error: missing value for field `b` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
// CHECK:STDERR: fail_init.carbon:[[@LINE+4]]:3: error: struct `Class` has no field named `c` [StructInitUnexpectedFieldInLiteral]
|
||||
// CHECK:STDERR: {.a = 1, .c = 2} as Class;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
{.a = 1, .c = 2} as Class;
|
||||
// CHECK:STDERR: fail_init.carbon:[[@LINE+4]]:3: error: cannot initialize class with 2 fields from struct with 3 fields [StructInitElementCountMismatch]
|
||||
// CHECK:STDERR: fail_init.carbon:[[@LINE+4]]:3: error: struct `Class` has no field named `c` [StructInitUnexpectedFieldInLiteral]
|
||||
// CHECK:STDERR: {.a = 1, .b = 2, .c = 3} as Class;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
|
||||
@@ -1,19 +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
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/field/fail_todo_field_initializer.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/field/fail_todo_field_initializer.carbon
|
||||
|
||||
class Class {
|
||||
// CHECK:STDERR: fail_todo_field_initializer.carbon:[[@LINE+4]]:18: error: semantics TODO: `Field initializer` [SemanticsTodo]
|
||||
// CHECK:STDERR: var field: i32 = 0;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR:
|
||||
var field: i32 = 0;
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// 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
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/field/field_initializer.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/field/field_initializer.carbon
|
||||
|
||||
// --- field_initializer.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
//@dump-sem-ir-begin
|
||||
class Class {
|
||||
var field: i32 = 123;
|
||||
}
|
||||
|
||||
var C: Class = {};
|
||||
//@dump-sem-ir-end
|
||||
|
||||
// --- fail_todo_field_initializer_import.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import library "field_initializer";
|
||||
|
||||
// CHECK:STDERR: fail_todo_field_initializer_import.carbon:[[@LINE+4]]:17: error: missing value for field `field` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
// CHECK:STDERR: var C2: Class = {};
|
||||
// CHECK:STDERR: ^~
|
||||
// CHECK:STDERR:
|
||||
var C2: Class = {};
|
||||
|
||||
// --- field_initializer_generic.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface I {
|
||||
let Default:! Self;
|
||||
}
|
||||
|
||||
impl i32 as I where .Default = 123 {}
|
||||
|
||||
class Class(T:! I) {
|
||||
var x: T = T.Default;
|
||||
}
|
||||
|
||||
var C: Class(i32) = {};
|
||||
|
||||
// --- fail_field_initializer_invalid_name.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class Class {
|
||||
var field: i32 = 123;
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_field_initializer_invalid_name.carbon:[[@LINE+4]]:16: error: struct `Class` has no field named `not_a_field` [StructInitUnexpectedFieldInLiteral]
|
||||
// CHECK:STDERR: var C: Class = {.not_a_field = 456};
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
var C: Class = {.not_a_field = 456};
|
||||
|
||||
// --- fail_field_initializer_wrong_type.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class Class {
|
||||
// CHECK:STDERR: fail_field_initializer_wrong_type.carbon:[[@LINE+7]]:20: error: cannot implicitly convert expression of type `()` to `i32` [ConversionFailure]
|
||||
// CHECK:STDERR: var field: i32 = ();
|
||||
// CHECK:STDERR: ^~
|
||||
// CHECK:STDERR: fail_field_initializer_wrong_type.carbon:[[@LINE+4]]:20: note: type `()` does not implement interface `Core.ImplicitAs(i32)` [MissingImplInMemberAccessInContext]
|
||||
// CHECK:STDERR: var field: i32 = ();
|
||||
// CHECK:STDERR: ^~
|
||||
// CHECK:STDERR:
|
||||
var field: i32 = ();
|
||||
}
|
||||
|
||||
// --- fail_field_initializer_not_constant.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
var x: i32;
|
||||
class Class {
|
||||
// CHECK:STDERR: fail_field_initializer_not_constant.carbon:[[@LINE+4]]:20: error: semantics TODO: `field initializer is not constant` [SemanticsTodo]
|
||||
// CHECK:STDERR: var field: i32 = x;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR:
|
||||
var field: i32 = x;
|
||||
}
|
||||
|
||||
var C: Class = {};
|
||||
|
||||
// CHECK:STDOUT: --- field_initializer.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %Class: type = class_type @Class [concrete]
|
||||
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
|
||||
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %Class.elem: type = unbound_element_type %Class, %i32 [concrete]
|
||||
// CHECK:STDOUT: %int_123.fff: Core.IntLiteral = int_value 123 [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.type.544: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
|
||||
// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.766: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.ec3: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.766 = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %ImplicitAs.impl_witness.fb6: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.1a5, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.ef7: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.ef7 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.544 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.fb6) [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.367: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%i32, %ImplicitAs.facet) [concrete]
|
||||
// CHECK:STDOUT: %.205: type = fn_type_with_self_type %ImplicitAs.WithSelf.Convert.type.367, %ImplicitAs.facet [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: <bound method> = bound_method %int_123.fff, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_123.fff, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
|
||||
// CHECK:STDOUT: %int_123.5a3: %i32 = int_value 123 [concrete]
|
||||
// CHECK:STDOUT: %struct_type.field: type = struct_type {.field: %i32} [concrete]
|
||||
// CHECK:STDOUT: %complete_type.97b: <witness> = complete_type_witness %struct_type.field [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.dd7: type = pattern_type %Class [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %empty_struct: %empty_struct_type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Class.val: %Class = struct_value (%int_123.5a3) [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Core.import_ref.dd3: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.766) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.ec3)]
|
||||
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.1a5 = impl_witness_table (%Core.import_ref.dd3), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: %Class.decl: type = class_decl @Class [concrete = constants.%Class] {} {}
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %C.patt: %pattern_type.dd7 = ref_binding_pattern C [concrete]
|
||||
// CHECK:STDOUT: %C.var_patt: %pattern_type.dd7 = var_pattern %C.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.var: ref %Class = var %C.var_patt [concrete]
|
||||
// CHECK:STDOUT: %Class.ref: type = name_ref Class, %Class.decl [concrete = constants.%Class]
|
||||
// CHECK:STDOUT: %C: ref %Class = ref_binding C, %C.var [concrete = %C.var]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Class {
|
||||
// CHECK:STDOUT: %.loc5_12: %Class.elem = field_decl field, element0 [concrete]
|
||||
// CHECK:STDOUT: %int_123: Core.IntLiteral = int_value 123 [concrete = constants.%int_123.fff]
|
||||
// CHECK:STDOUT: %impl.elem0: %.205 = impl_witness_access constants.%ImplicitAs.impl_witness.fb6, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b]
|
||||
// CHECK:STDOUT: %bound_method.loc5_20.1: <bound method> = bound_method %int_123, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
|
||||
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
|
||||
// CHECK:STDOUT: %bound_method.loc5_20.2: <bound method> = bound_method %int_123, %specific_fn [concrete = constants.%bound_method]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc5_20.2(%int_123) [concrete = constants.%int_123.5a3]
|
||||
// CHECK:STDOUT: %.loc5_20.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_123.5a3]
|
||||
// CHECK:STDOUT: %.loc5_20.2: %i32 = converted %int_123, %.loc5_20.1 [concrete = constants.%int_123.5a3]
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%struct_type.field [concrete = constants.%complete_type.97b]
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%Class
|
||||
// CHECK:STDOUT: .field = %.loc5_12
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %.loc8_17.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
|
||||
// CHECK:STDOUT: %.loc8_17.2: init %Class to file.%C.var = class_init (constants.%int_123.5a3) [concrete = constants.%Class.val]
|
||||
// CHECK:STDOUT: %.loc8_1: init %Class = converted %.loc8_17.1, %.loc8_17.2 [concrete = constants.%Class.val]
|
||||
// CHECK:STDOUT: assign file.%C.var, %.loc8_1
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+2
-2
@@ -398,7 +398,7 @@ library "[[@TEST_NAME]]";
|
||||
|
||||
interface K {
|
||||
let V:! type;
|
||||
// CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE+3]]:20: error: cannot convert from struct type `{.a: ()}` to `{.x: ()}`: missing field `x` in source type [StructInitMissingFieldInConversion]
|
||||
// CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE+3]]:20: error: cannot convert from struct type `{.a: ()}` to `{.x: ()}`: unexpected field `a` in source type [StructInitUnexpectedFieldInConversion]
|
||||
// CHECK:STDERR: fn F[self: Self](v: V) -> V;
|
||||
// CHECK:STDERR: ^~~~
|
||||
fn F[self: Self](v: V) -> V;
|
||||
@@ -412,7 +412,7 @@ impl () as K where .V = {.a: ()} {
|
||||
// CHECK:STDERR: fn F[self: Self](v: V) -> V;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE+7]]:3: error: cannot convert from struct type `{.x: ()}` to `{.a: ()}`: missing field `a` in source type [StructInitMissingFieldInConversion]
|
||||
// CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE+7]]:3: error: cannot convert from struct type `{.x: ()}` to `{.a: ()}`: unexpected field `x` in source type [StructInitUnexpectedFieldInConversion]
|
||||
// CHECK:STDERR: fn F[unused self: Self](v: {.x: ()}) -> {.x: ()} { return v; }
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_associated_type_in_signature_mismatch.carbon:[[@LINE-14]]:3: note: while building thunk to match the signature of this function [ThunkSignature]
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/fail_assign_empty.carbon
|
||||
|
||||
// CHECK:STDERR: fail_assign_empty.carbon:[[@LINE+4]]:20: error: cannot initialize struct with 1 field from struct with 0 fields [StructInitElementCountMismatch]
|
||||
// CHECK:STDERR: fail_assign_empty.carbon:[[@LINE+4]]:20: error: missing value for field `a` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
// CHECK:STDERR: var x: {.a: i32} = {};
|
||||
// CHECK:STDERR: ^~
|
||||
// CHECK:STDERR:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/fail_assign_nested.carbon
|
||||
|
||||
// CHECK:STDERR: fail_assign_nested.carbon:[[@LINE+4]]:19: error: missing value for field `a` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
// CHECK:STDERR: fail_assign_nested.carbon:[[@LINE+4]]:19: error: struct `{.a: {}}` has no field named `b` [StructInitUnexpectedFieldInLiteral]
|
||||
// CHECK:STDERR: var x: {.a: {}} = {.b = {}};
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/fail_assign_to_empty.carbon
|
||||
|
||||
// CHECK:STDERR: fail_assign_to_empty.carbon:[[@LINE+4]]:13: error: cannot initialize struct with 0 fields from struct with 1 field [StructInitElementCountMismatch]
|
||||
// CHECK:STDERR: fail_assign_to_empty.carbon:[[@LINE+4]]:13: error: struct `{}` has no field named `a` [StructInitUnexpectedFieldInLiteral]
|
||||
// CHECK:STDERR: var x: {} = {.a = 1};
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
|
||||
+110
-16
@@ -12,13 +12,20 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/fail_field_name_mismatch.carbon
|
||||
|
||||
// CHECK:STDERR: fail_field_name_mismatch.carbon:[[@LINE+4]]:20: error: missing value for field `a` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
var a: {.a: i32} = {.a = 1 };
|
||||
// CHECK:STDERR: fail_field_name_mismatch.carbon:[[@LINE+4]]:29: error: cannot convert from struct type `{.a: i32}` to `{.a: i32, .b: i32}`: missing field `b` in source type [StructInitMissingFieldInConversion]
|
||||
// CHECK:STDERR: var b: {.a: i32, .b: i32} = a;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR:
|
||||
var b: {.a: i32, .b: i32} = a;
|
||||
|
||||
// CHECK:STDERR: fail_field_name_mismatch.carbon:[[@LINE+4]]:20: error: struct `{.a: i32}` has no field named `b` [StructInitUnexpectedFieldInLiteral]
|
||||
// CHECK:STDERR: var x: {.a: i32} = {.b = 1};
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
var x: {.a: i32} = {.b = 1};
|
||||
|
||||
// CHECK:STDERR: fail_field_name_mismatch.carbon:[[@LINE+4]]:20: error: cannot convert from struct type `{.a: i32}` to `{.b: i32}`: missing field `b` in source type [StructInitMissingFieldInConversion]
|
||||
// CHECK:STDERR: fail_field_name_mismatch.carbon:[[@LINE+4]]:20: error: cannot convert from struct type `{.a: i32}` to `{.b: i32}`: unexpected field `a` in source type [StructInitUnexpectedFieldInConversion]
|
||||
// CHECK:STDERR: var y: {.b: i32} = x;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR:
|
||||
@@ -30,12 +37,46 @@ var y: {.b: i32} = x;
|
||||
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
|
||||
// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete]
|
||||
// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %N: Core.IntLiteral = symbolic_binding N, 0 [symbolic]
|
||||
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %struct_type.a: type = struct_type {.a: %i32} [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.79c: type = pattern_type %struct_type.a [concrete]
|
||||
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: %struct_type.a.72d: type = struct_type {.a: %i32} [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.79c: type = pattern_type %struct_type.a.72d [concrete]
|
||||
// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: %struct_type.a.a6c: type = struct_type {.a: Core.IntLiteral} [concrete]
|
||||
// CHECK:STDOUT: %struct.48c: %struct_type.a.a6c = struct_value (%int_1.5b8) [concrete]
|
||||
// CHECK:STDOUT: %.17c: ref %i32 = struct_access file.%a.var, element0 [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.type.649: type = generic_interface_type @ImplicitAs [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.generic: %ImplicitAs.type.649 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.type.544: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
|
||||
// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.766: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.ec3: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.766 = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %ImplicitAs.impl_witness.fb6: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.1a5, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.ef7: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.ef7 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.544 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.fb6) [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.367: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%i32, %ImplicitAs.facet) [concrete]
|
||||
// CHECK:STDOUT: %.205: type = fn_type_with_self_type %ImplicitAs.WithSelf.Convert.type.367, %ImplicitAs.facet [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
|
||||
// CHECK:STDOUT: %int_1.d5e: %i32 = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: %struct.096: %struct_type.a.72d = struct_value (%int_1.d5e) [concrete]
|
||||
// CHECK:STDOUT: %struct_type.a.b: type = struct_type {.a: %i32, .b: %i32} [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.32c: type = pattern_type %struct_type.a.b [concrete]
|
||||
// CHECK:STDOUT: %.568: ref %i32 = struct_access file.%b.var, element0 [concrete]
|
||||
// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete]
|
||||
// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.b5d: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%N) [symbolic]
|
||||
// CHECK:STDOUT: %Int.as.Copy.impl.Op.c85: %Int.as.Copy.impl.Op.type.b5d = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %Copy.impl_witness.32d: <witness> = impl_witness imports.%Copy.impl_witness_table.07a, @Int.as.Copy.impl(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.4a0: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %Int.as.Copy.impl.Op.c4a: %Int.as.Copy.impl.Op.type.4a0 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %Copy.facet: %Copy.type = facet_value %i32, (%Copy.impl_witness.32d) [concrete]
|
||||
// CHECK:STDOUT: %Copy.WithSelf.Op.type.afe: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%Copy.facet) [concrete]
|
||||
// CHECK:STDOUT: %.a5f: type = fn_type_with_self_type %Copy.WithSelf.Op.type.afe, %Copy.facet [concrete]
|
||||
// CHECK:STDOUT: %Int.as.Copy.impl.Op.specific_fn: <specific function> = specific_function %Int.as.Copy.impl.Op.c4a, @Int.as.Copy.impl.Op(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %struct_type.b.a15: type = struct_type {.b: Core.IntLiteral} [concrete]
|
||||
// CHECK:STDOUT: %struct: %struct_type.b.a15 = struct_value (%int_1) [concrete]
|
||||
// CHECK:STDOUT: %struct.62b: %struct_type.b.a15 = struct_value (%int_1.5b8) [concrete]
|
||||
// CHECK:STDOUT: %struct_type.b.177: type = struct_type {.b: %i32} [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.3b8: type = pattern_type %struct_type.b.177 [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
@@ -43,36 +84,67 @@ var y: {.b: i32} = x;
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
|
||||
// CHECK:STDOUT: .Int = %Core.Int
|
||||
// CHECK:STDOUT: .ImplicitAs = %Core.ImplicitAs
|
||||
// CHECK:STDOUT: .Copy = %Core.Copy
|
||||
// CHECK:STDOUT: import Core//prelude
|
||||
// CHECK:STDOUT: import Core//prelude/...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic]
|
||||
// CHECK:STDOUT: %Core.ImplicitAs: %ImplicitAs.type.649 = import_ref Core//prelude/parts/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
|
||||
// CHECK:STDOUT: %Core.import_ref.dd3: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.766) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.ec3)]
|
||||
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.1a5 = impl_witness_table (%Core.import_ref.dd3), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
|
||||
// CHECK:STDOUT: %Core.Copy: type = import_ref Core//prelude/parts/copy, Copy, loaded [concrete = constants.%Copy.type]
|
||||
// CHECK:STDOUT: %Core.import_ref.809: @Int.as.Copy.impl.%Int.as.Copy.impl.Op.type (%Int.as.Copy.impl.Op.type.b5d) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Int.as.Copy.impl.%Int.as.Copy.impl.Op (constants.%Int.as.Copy.impl.Op.c85)]
|
||||
// CHECK:STDOUT: %Copy.impl_witness_table.07a = impl_witness_table (%Core.import_ref.809), @Int.as.Copy.impl [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .Core = imports.%Core
|
||||
// CHECK:STDOUT: .a = %a
|
||||
// CHECK:STDOUT: .b = %b
|
||||
// CHECK:STDOUT: .x = %x
|
||||
// CHECK:STDOUT: .y = %y
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core.import = import Core
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %a.patt: %pattern_type.79c = ref_binding_pattern a [concrete]
|
||||
// CHECK:STDOUT: %a.var_patt: %pattern_type.79c = var_pattern %a.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a.var: ref %struct_type.a.72d = var %a.var_patt [concrete]
|
||||
// CHECK:STDOUT: %.loc15: type = splice_block %struct_type.a.loc15 [concrete = constants.%struct_type.a.72d] {
|
||||
// CHECK:STDOUT: %i32.loc15: type = type_literal constants.%i32 [concrete = constants.%i32]
|
||||
// CHECK:STDOUT: %struct_type.a.loc15: type = struct_type {.a: %i32} [concrete = constants.%struct_type.a.72d]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %a: ref %struct_type.a.72d = ref_binding a, %a.var [concrete = %a.var]
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %b.patt: %pattern_type.32c = ref_binding_pattern b [concrete]
|
||||
// CHECK:STDOUT: %b.var_patt: %pattern_type.32c = var_pattern %b.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %b.var: ref %struct_type.a.b = var %b.var_patt [concrete]
|
||||
// CHECK:STDOUT: %.loc20: type = splice_block %struct_type.a.b [concrete = constants.%struct_type.a.b] {
|
||||
// CHECK:STDOUT: %i32.loc20_13: type = type_literal constants.%i32 [concrete = constants.%i32]
|
||||
// CHECK:STDOUT: %i32.loc20_22: type = type_literal constants.%i32 [concrete = constants.%i32]
|
||||
// CHECK:STDOUT: %struct_type.a.b: type = struct_type {.a: %i32, .b: %i32} [concrete = constants.%struct_type.a.b]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %b: ref %struct_type.a.b = ref_binding b, %b.var [concrete = %b.var]
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %x.patt: %pattern_type.79c = ref_binding_pattern x [concrete]
|
||||
// CHECK:STDOUT: %x.var_patt: %pattern_type.79c = var_pattern %x.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %x.var: ref %struct_type.a = var %x.var_patt [concrete]
|
||||
// CHECK:STDOUT: %.loc19: type = splice_block %struct_type.a [concrete = constants.%struct_type.a] {
|
||||
// CHECK:STDOUT: %i32.loc19: type = type_literal constants.%i32 [concrete = constants.%i32]
|
||||
// CHECK:STDOUT: %struct_type.a: type = struct_type {.a: %i32} [concrete = constants.%struct_type.a]
|
||||
// CHECK:STDOUT: %x.var: ref %struct_type.a.72d = var %x.var_patt [concrete]
|
||||
// CHECK:STDOUT: %.loc26: type = splice_block %struct_type.a.loc26 [concrete = constants.%struct_type.a.72d] {
|
||||
// CHECK:STDOUT: %i32.loc26: type = type_literal constants.%i32 [concrete = constants.%i32]
|
||||
// CHECK:STDOUT: %struct_type.a.loc26: type = struct_type {.a: %i32} [concrete = constants.%struct_type.a.72d]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %x: ref %struct_type.a = ref_binding x, %x.var [concrete = %x.var]
|
||||
// CHECK:STDOUT: %x: ref %struct_type.a.72d = ref_binding x, %x.var [concrete = %x.var]
|
||||
// CHECK:STDOUT: name_binding_decl {
|
||||
// CHECK:STDOUT: %y.patt: %pattern_type.3b8 = ref_binding_pattern y [concrete]
|
||||
// CHECK:STDOUT: %y.var_patt: %pattern_type.3b8 = var_pattern %y.patt [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %y.var: ref %struct_type.b.177 = var %y.var_patt [concrete]
|
||||
// CHECK:STDOUT: %.loc25: type = splice_block %struct_type.b [concrete = constants.%struct_type.b.177] {
|
||||
// CHECK:STDOUT: %i32.loc25: type = type_literal constants.%i32 [concrete = constants.%i32]
|
||||
// CHECK:STDOUT: %.loc32: type = splice_block %struct_type.b [concrete = constants.%struct_type.b.177] {
|
||||
// CHECK:STDOUT: %i32.loc32: type = type_literal constants.%i32 [concrete = constants.%i32]
|
||||
// CHECK:STDOUT: %struct_type.b: type = struct_type {.b: %i32} [concrete = constants.%struct_type.b.177]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %y: ref %struct_type.b.177 = ref_binding y, %y.var [concrete = %y.var]
|
||||
@@ -80,10 +152,32 @@ var y: {.b: i32} = x;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1]
|
||||
// CHECK:STDOUT: %.loc19: %struct_type.b.a15 = struct_literal (%int_1) [concrete = constants.%struct]
|
||||
// CHECK:STDOUT: %int_1.loc15: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
|
||||
// CHECK:STDOUT: %.loc15_28.1: %struct_type.a.a6c = struct_literal (%int_1.loc15) [concrete = constants.%struct.48c]
|
||||
// CHECK:STDOUT: %impl.elem0.loc15: %.205 = impl_witness_access constants.%ImplicitAs.impl_witness.fb6, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b]
|
||||
// CHECK:STDOUT: %bound_method.loc15_28.1: <bound method> = bound_method %int_1.loc15, %impl.elem0.loc15 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
|
||||
// CHECK:STDOUT: %specific_fn.loc15: <specific function> = specific_function %impl.elem0.loc15, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
|
||||
// CHECK:STDOUT: %bound_method.loc15_28.2: <bound method> = bound_method %int_1.loc15, %specific_fn.loc15 [concrete = constants.%bound_method]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc15_28.2(%int_1.loc15) [concrete = constants.%int_1.d5e]
|
||||
// CHECK:STDOUT: %.loc15_28.2: init %i32 = converted %int_1.loc15, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_1.d5e]
|
||||
// CHECK:STDOUT: %.loc15_28.3: init %struct_type.a.72d to file.%a.var = struct_init (%.loc15_28.2) [concrete = constants.%struct.096]
|
||||
// CHECK:STDOUT: %.loc15_1: init %struct_type.a.72d = converted %.loc15_28.1, %.loc15_28.3 [concrete = constants.%struct.096]
|
||||
// CHECK:STDOUT: assign file.%a.var, %.loc15_1
|
||||
// CHECK:STDOUT: %a.ref: ref %struct_type.a.72d = name_ref a, file.%a [concrete = file.%a.var]
|
||||
// CHECK:STDOUT: %.loc20_29.1: ref %i32 = struct_access %a.ref, element0 [concrete = constants.%.17c]
|
||||
// CHECK:STDOUT: %.loc20_29.2: %i32 = acquire_value %.loc20_29.1
|
||||
// CHECK:STDOUT: %impl.elem0.loc20: %.a5f = impl_witness_access constants.%Copy.impl_witness.32d, element0 [concrete = constants.%Int.as.Copy.impl.Op.c4a]
|
||||
// CHECK:STDOUT: %bound_method.loc20_29.1: <bound method> = bound_method %.loc20_29.2, %impl.elem0.loc20
|
||||
// CHECK:STDOUT: %specific_fn.loc20: <specific function> = specific_function %impl.elem0.loc20, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
|
||||
// CHECK:STDOUT: %bound_method.loc20_29.2: <bound method> = bound_method %.loc20_29.2, %specific_fn.loc20
|
||||
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc20_29.2(%.loc20_29.2)
|
||||
// CHECK:STDOUT: %.loc20_29.3: ref %i32 = struct_access file.%b.var, element0 [concrete = constants.%.568]
|
||||
// CHECK:STDOUT: %.loc20_29.4: init %i32 to %.loc20_29.3 = in_place_init %Int.as.Copy.impl.Op.call
|
||||
// CHECK:STDOUT: assign file.%b.var, <error>
|
||||
// CHECK:STDOUT: %int_1.loc26: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
|
||||
// CHECK:STDOUT: %.loc26: %struct_type.b.a15 = struct_literal (%int_1.loc26) [concrete = constants.%struct.62b]
|
||||
// CHECK:STDOUT: assign file.%x.var, <error>
|
||||
// CHECK:STDOUT: %x.ref: ref %struct_type.a = name_ref x, file.%x [concrete = file.%x.var]
|
||||
// CHECK:STDOUT: %x.ref: ref %struct_type.a.72d = name_ref x, file.%x [concrete = file.%x.var]
|
||||
// CHECK:STDOUT: assign file.%y.var, <error>
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/fail_field_type_mismatch.carbon
|
||||
|
||||
// CHECK:STDERR: fail_field_type_mismatch.carbon:[[@LINE+4]]:20: error: missing value for field `a` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
// CHECK:STDERR: fail_field_type_mismatch.carbon:[[@LINE+4]]:20: error: struct `{.a: i32}` has no field named `b` [StructInitUnexpectedFieldInLiteral]
|
||||
// CHECK:STDERR: var x: {.a: i32} = {.b = 1.0};
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
|
||||
+34
-5
@@ -12,7 +12,7 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/struct/fail_too_few_values.carbon
|
||||
|
||||
// CHECK:STDERR: fail_too_few_values.carbon:[[@LINE+4]]:29: error: cannot initialize struct with 2 fields from struct with 1 field [StructInitElementCountMismatch]
|
||||
// CHECK:STDERR: fail_too_few_values.carbon:[[@LINE+4]]:29: error: missing value for field `b` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
// CHECK:STDERR: var x: {.a: i32, .b: i32} = {.a = 1};
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
@@ -27,18 +27,39 @@ var x: {.a: i32, .b: i32} = {.a = 1};
|
||||
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %struct_type.a.b: type = struct_type {.a: %i32, .b: %i32} [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.32c: type = pattern_type %struct_type.a.b [concrete]
|
||||
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: %struct_type.a: type = struct_type {.a: Core.IntLiteral} [concrete]
|
||||
// CHECK:STDOUT: %struct: %struct_type.a = struct_value (%int_1) [concrete]
|
||||
// CHECK:STDOUT: %struct: %struct_type.a = struct_value (%int_1.5b8) [concrete]
|
||||
// CHECK:STDOUT: %.2e9: ref %i32 = struct_access file.%x.var, element0 [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.type.649: type = generic_interface_type @ImplicitAs [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.generic: %ImplicitAs.type.649 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.type.544: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
|
||||
// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.766: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.ec3: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.766 = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %ImplicitAs.impl_witness.fb6: <witness> = impl_witness imports.%ImplicitAs.impl_witness_table.1a5, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.ef7: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.ef7 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.544 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.fb6) [concrete]
|
||||
// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.367: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%i32, %ImplicitAs.facet) [concrete]
|
||||
// CHECK:STDOUT: %.205: type = fn_type_with_self_type %ImplicitAs.WithSelf.Convert.type.367, %ImplicitAs.facet [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b [concrete]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: <specific function> = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete]
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
|
||||
// CHECK:STDOUT: %int_1.d5e: %i32 = int_value 1 [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
|
||||
// CHECK:STDOUT: .Int = %Core.Int
|
||||
// CHECK:STDOUT: .ImplicitAs = %Core.ImplicitAs
|
||||
// CHECK:STDOUT: import Core//prelude
|
||||
// CHECK:STDOUT: import Core//prelude/...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic]
|
||||
// CHECK:STDOUT: %Core.ImplicitAs: %ImplicitAs.type.649 = import_ref Core//prelude/parts/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic]
|
||||
// CHECK:STDOUT: %Core.import_ref.dd3: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.766) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.ec3)]
|
||||
// CHECK:STDOUT: %ImplicitAs.impl_witness_table.1a5 = impl_witness_table (%Core.import_ref.dd3), @Core.IntLiteral.as.ImplicitAs.impl [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
@@ -62,8 +83,16 @@ var x: {.a: i32, .b: i32} = {.a = 1};
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1]
|
||||
// CHECK:STDOUT: %.loc19: %struct_type.a = struct_literal (%int_1) [concrete = constants.%struct]
|
||||
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
|
||||
// CHECK:STDOUT: %.loc19_36.1: %struct_type.a = struct_literal (%int_1) [concrete = constants.%struct]
|
||||
// CHECK:STDOUT: %impl.elem0: %.205 = impl_witness_access constants.%ImplicitAs.impl_witness.fb6, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.e6b]
|
||||
// CHECK:STDOUT: %bound_method.loc19_36.1: <bound method> = bound_method %int_1, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
|
||||
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
|
||||
// CHECK:STDOUT: %bound_method.loc19_36.2: <bound method> = bound_method %int_1, %specific_fn [concrete = constants.%bound_method]
|
||||
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc19_36.2(%int_1) [concrete = constants.%int_1.d5e]
|
||||
// CHECK:STDOUT: %.loc19_36.2: init %i32 = converted %int_1, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_1.d5e]
|
||||
// CHECK:STDOUT: %.loc19_36.3: ref %i32 = struct_access file.%x.var, element0 [concrete = constants.%.2e9]
|
||||
// CHECK:STDOUT: %.loc19_36.4: init %i32 to %.loc19_36.3 = in_place_init %.loc19_36.2 [concrete = constants.%int_1.d5e]
|
||||
// CHECK:STDOUT: assign file.%x.var, <error>
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ var c: C({.a = 1, .b = 2}) = F();
|
||||
// --- fail_bad_type.impl.carbon
|
||||
|
||||
impl package Implicit;
|
||||
// CHECK:STDERR: fail_bad_type.impl.carbon:[[@LINE+8]]:14: error: missing value for field `a` in struct initialization [StructInitMissingFieldInLiteral]
|
||||
// CHECK:STDERR: fail_bad_type.impl.carbon:[[@LINE+8]]:14: error: struct `{.a: i32, .b: i32}` has no field named `c` [StructInitUnexpectedFieldInLiteral]
|
||||
// CHECK:STDERR: var c_bad: C({.c = 1, .d = 2}) = F();
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_bad_type.impl.carbon:[[@LINE-4]]:1: in import [InImport]
|
||||
|
||||
@@ -482,9 +482,10 @@ CARBON_DIAGNOSTIC_KIND(StringAtIndexNegative)
|
||||
CARBON_DIAGNOSTIC_KIND(StringLiteralTooLong)
|
||||
CARBON_DIAGNOSTIC_KIND(StringLiteralTypeIncomplete)
|
||||
CARBON_DIAGNOSTIC_KIND(StringLiteralTypeUnexpected)
|
||||
CARBON_DIAGNOSTIC_KIND(StructInitElementCountMismatch)
|
||||
CARBON_DIAGNOSTIC_KIND(StructInitMissingFieldInLiteral)
|
||||
CARBON_DIAGNOSTIC_KIND(StructInitMissingFieldInConversion)
|
||||
CARBON_DIAGNOSTIC_KIND(StructInitUnexpectedFieldInLiteral)
|
||||
CARBON_DIAGNOSTIC_KIND(StructInitUnexpectedFieldInConversion)
|
||||
CARBON_DIAGNOSTIC_KIND(StructNameDuplicate)
|
||||
CARBON_DIAGNOSTIC_KIND(StructNamePrevious)
|
||||
CARBON_DIAGNOSTIC_KIND(TupleIndexNotConstant)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/class/field_initializer.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/class/field_initializer.carbon
|
||||
|
||||
// --- field_initializer.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
class C {
|
||||
var a: i32 = 123;
|
||||
}
|
||||
|
||||
var c: C = {};
|
||||
|
||||
// CHECK:STDOUT: ; ModuleID = 'field_initializer.carbon'
|
||||
// CHECK:STDOUT: source_filename = "field_initializer.carbon"
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: @_Cc.Main = global { i32 } zeroinitializer
|
||||
// CHECK:STDOUT: @C.val.loc7_1 = internal constant { i32 } { i32 123 }
|
||||
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @_C__global_init.Main, ptr null }]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 @_Cc.Main, ptr align 4 @C.val.loc7_1, i64 4, i1 false), !dbg !7
|
||||
// CHECK:STDOUT: ret void, !dbg !8
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: attributes #0 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1}
|
||||
// CHECK:STDOUT: !llvm.dbg.cu = !{!2}
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5}
|
||||
// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
|
||||
// CHECK:STDOUT: !3 = !DIFile(filename: "field_initializer.carbon", directory: "")
|
||||
// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "__global_init", linkageName: "_C__global_init.Main", scope: null, file: !3, type: !5, spFlags: DISPFlagDefinition, unit: !2)
|
||||
// CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
|
||||
// CHECK:STDOUT: !6 = !{null}
|
||||
// CHECK:STDOUT: !7 = !DILocation(line: 7, column: 1, scope: !4)
|
||||
// CHECK:STDOUT: !8 = !DILocation(line: 0, scope: !4)
|
||||
@@ -6,6 +6,7 @@
|
||||
#define CARBON_TOOLCHAIN_SEM_IR_FILE_H_
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/map.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
@@ -206,6 +207,12 @@ class File : public Printable<File> {
|
||||
// TODO: Rename these to `facet_type_infos`.
|
||||
auto facet_types() -> FacetTypeInfoStore& { return facet_types_; }
|
||||
auto facet_types() const -> const FacetTypeInfoStore& { return facet_types_; }
|
||||
|
||||
using FieldInitializerMap = Map<SemIR::InstId, SemIR::InstId>;
|
||||
auto field_initializers() -> FieldInitializerMap& {
|
||||
return field_initializers_;
|
||||
}
|
||||
|
||||
auto identified_facet_types() -> IdentifiedFacetTypeStore& {
|
||||
return identified_facet_types_;
|
||||
}
|
||||
@@ -349,6 +356,13 @@ class File : public Printable<File> {
|
||||
// Storage for classes.
|
||||
ClassStore classes_;
|
||||
|
||||
// Map containing initializers for class fields. The map keys are
|
||||
// `InstId`s corresponding to `FielDecl`s.
|
||||
//
|
||||
// TODO: consider replacing this map with a separate store for fields
|
||||
// and tracking a new `FieldId` in the `FieldDecl`.
|
||||
FieldInitializerMap field_initializers_;
|
||||
|
||||
// Storage for interfaces.
|
||||
InterfaceStore interfaces_;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user