diff --git a/explorer/interpreter/interpreter.cpp b/explorer/interpreter/interpreter.cpp index d3c43bca5e67..313cd72c83cb 100644 --- a/explorer/interpreter/interpreter.cpp +++ b/explorer/interpreter/interpreter.cpp @@ -494,7 +494,6 @@ auto Interpreter::Convert(Nonnull value, case Value::Kind::FunctionType: case Value::Kind::PointerType: case Value::Kind::AutoType: - case Value::Kind::StructType: case Value::Kind::NominalClassType: case Value::Kind::InterfaceType: case Value::Kind::Witness: @@ -548,6 +547,19 @@ auto Interpreter::Convert(Nonnull value, << *destination_type; } } + case Value::Kind::StructType: { + // The value `{}` has kind `StructType` not `StructValue`. This value can + // be converted to an empty class type. + if (auto* destination_class_type = + dyn_cast(destination_type)) { + CARBON_CHECK(cast(*value).fields().empty()) + << "only an empty struct type value converts to class type"; + CARBON_ASSIGN_OR_RETURN(Nonnull inst_dest, + InstantiateType(destination_type, source_loc)); + return arena_->New(inst_dest, value); + } + return value; + } case Value::Kind::TupleValue: { const auto& tuple = cast(value); std::vector> destination_element_types; diff --git a/explorer/interpreter/value.cpp b/explorer/interpreter/value.cpp index 06e43f5894bd..2565623a52ab 100644 --- a/explorer/interpreter/value.cpp +++ b/explorer/interpreter/value.cpp @@ -17,6 +17,7 @@ namespace Carbon { using llvm::cast; +using llvm::dyn_cast; auto StructValue::FindField(const std::string& name) const -> std::optional> { @@ -72,9 +73,13 @@ static auto GetMember(Nonnull arena, Nonnull v, } case Value::Kind::NominalClassValue: { const auto& object = cast(*v); - // Look for a field - std::optional> field = - cast(object.inits()).FindField(f); + // Look for a field. + // Note that the value representation of an empty class is a + // `StructType`, not a `StructValue`. + std::optional> field; + if (auto* struct_value = dyn_cast(&object.inits())) { + field = struct_value->FindField(f); + } if (field.has_value()) { return *field; } else { diff --git a/explorer/testdata/class/empty_class.carbon b/explorer/testdata/class/empty_class.carbon new file mode 100644 index 000000000000..3133a683c777 --- /dev/null +++ b/explorer/testdata/class/empty_class.carbon @@ -0,0 +1,21 @@ +// 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 +// +// RUN: %{explorer} %s 2>&1 | \ +// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s +// RUN: %{explorer} --parser_debug --trace_file=- %s 2>&1 | \ +// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s +// AUTOUPDATE: %{explorer} %s +// CHECK: result: 0 + +package ExplorerTest api; + +class A { fn F[me: Self]() -> i32 { return 0; } } + +fn Main() -> i32 { + // {} is a bit strange; its type is {}. Make sure we can properly convert a + // value of type {} to type TypeOfClassType. + var a: A = {}; + return a.F(); +}