Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track the type as written in BaseDecl and AdaptDecl. #4564

Merged
merged 13 commits into from
Nov 27, 2024
42 changes: 20 additions & 22 deletions toolchain/check/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,18 +381,19 @@ static auto DiagnoseInvalidQualifiedNameAccess(Context& context, SemIRLoc loc,
}

// TODO: Support scoped entities other than just classes.
auto class_info = context.classes().Get(class_type->class_id);
const auto& class_info = context.classes().Get(class_type->class_id);

auto parent_type_id = class_info.self_type_id;

if (access_kind == SemIR::AccessKind::Private && is_parent_access) {
if (auto base_decl = context.insts().TryGetAsIfValid<SemIR::BaseDecl>(
class_info.base_id)) {
parent_type_id = base_decl->base_type_id;
} else if (auto adapt_decl =
context.insts().TryGetAsIfValid<SemIR::AdaptDecl>(
class_info.adapt_id)) {
parent_type_id = adapt_decl->adapted_type_id;
if (auto base_type_id =
class_info.GetBaseType(context.sem_ir(), class_type->specific_id);
base_type_id.is_valid()) {
parent_type_id = base_type_id;
} else if (auto adapted_type_id = class_info.GetAdaptedType(
context.sem_ir(), class_type->specific_id);
adapted_type_id.is_valid()) {
parent_type_id = adapted_type_id;
} else {
CARBON_FATAL("Expected parent for parent access");
}
Expand Down Expand Up @@ -946,7 +947,13 @@ class TypeCompleter {
if (inst.specific_id.is_valid()) {
ResolveSpecificDefinition(context_, inst.specific_id);
}
Push(class_info.GetObjectRepr(context_.sem_ir(), inst.specific_id));
if (auto adapted_type_id =
class_info.GetAdaptedType(context_.sem_ir(), inst.specific_id);
adapted_type_id.is_valid()) {
Push(adapted_type_id);
} else {
Push(class_info.GetObjectRepr(context_.sem_ir(), inst.specific_id));
}
break;
}
case CARBON_KIND(SemIR::ConstType inst): {
Expand Down Expand Up @@ -1116,12 +1123,10 @@ class TypeCompleter {
auto& class_info = context_.classes().Get(inst.class_id);
// The value representation of an adapter is the value representation of
// its adapted type.
if (class_info.adapt_id.is_valid()) {
return GetNestedValueRepr(SemIR::GetTypeInSpecific(
context_.sem_ir(), inst.specific_id,
context_.insts()
.GetAs<SemIR::AdaptDecl>(class_info.adapt_id)
.adapted_type_id));
if (auto adapted_type_id =
class_info.GetAdaptedType(context_.sem_ir(), inst.specific_id);
adapted_type_id.is_valid()) {
return GetNestedValueRepr(adapted_type_id);
}
// Otherwise, the value representation for a class is a pointer to the
// object representation.
Expand Down Expand Up @@ -1388,13 +1393,6 @@ auto Context::GetUnboundElementType(SemIR::TypeId class_type_id,
element_type_id);
}

auto Context::GetUnqualifiedType(SemIR::TypeId type_id) -> SemIR::TypeId {
if (auto const_type = types().TryGetAs<SemIR::ConstType>(type_id)) {
return const_type->inner_id;
}
return type_id;
}

auto Context::PrintForStackDump(llvm::raw_ostream& output) const -> void {
output << "Check::Context\n";

Expand Down
3 changes: 0 additions & 3 deletions toolchain/check/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,6 @@ class Context {
auto GetUnboundElementType(SemIR::TypeId class_type_id,
SemIR::TypeId element_type_id) -> SemIR::TypeId;

// Removes any top-level `const` qualifiers from a type.
auto GetUnqualifiedType(SemIR::TypeId type_id) -> SemIR::TypeId;

// Adds an exported name.
auto AddExport(SemIR::InstId inst_id) -> void { exports_.push_back(inst_id); }

Expand Down
20 changes: 10 additions & 10 deletions toolchain/check/convert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,15 +604,12 @@ static auto ComputeInheritancePath(Context& context, SemIR::TypeId derived_id,
break;
}
auto& derived_class = context.classes().Get(derived_class_type->class_id);
if (!derived_class.base_id.is_valid()) {
auto base_type_id = derived_class.GetBaseType(
context.sem_ir(), derived_class_type->specific_id);
if (!base_type_id.is_valid()) {
result = std::nullopt;
break;
}
auto base_decl =
context.insts().GetAs<SemIR::BaseDecl>(derived_class.base_id);
auto base_type_id = SemIR::GetTypeInSpecific(
context.sem_ir(), derived_class_type->specific_id,
base_decl.base_type_id);
result->push_back({derived_class.base_id, base_type_id});
derived_id = base_type_id;
}
Expand Down Expand Up @@ -709,12 +706,15 @@ static auto GetCompatibleBaseType(Context& context, SemIR::TypeId type_id)
-> SemIR::TypeId {
// If the type is an adapter, its object representation type is its compatible
// non-adapter type.
if (auto class_type = context.types().TryGetAs<SemIR::ClassType>(type_id)) {
while (auto class_type =
context.types().TryGetAs<SemIR::ClassType>(type_id)) {
auto& class_info = context.classes().Get(class_type->class_id);
if (class_info.adapt_id.is_valid()) {
return class_info.GetObjectRepr(context.sem_ir(),
class_type->specific_id);
auto adapted_type_id =
class_info.GetAdaptedType(context.sem_ir(), class_type->specific_id);
if (!adapted_type_id.is_valid()) {
break;
}
type_id = adapted_type_id;
}

// Otherwise, the type itself is a non-adapter type.
Expand Down
12 changes: 7 additions & 5 deletions toolchain/check/eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ static auto PerformCheckedIntConvert(Context& context, SemIRLoc loc,
auto arg_val = context.ints().Get(arg.int_id);

auto [is_signed, bit_width_id] =
context.sem_ir().GetIntTypeInfo(dest_type_id);
context.sem_ir().types().GetIntTypeInfo(dest_type_id);
auto width = bit_width_id.is_valid()
? context.ints().Get(bit_width_id).getZExtValue()
: arg_val.getBitWidth();
Expand Down Expand Up @@ -717,7 +717,8 @@ static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLoc loc,
SemIR::InstId arg_id)
-> SemIR::ConstantId {
auto op = context.insts().GetAs<SemIR::IntValue>(arg_id);
auto [is_signed, bit_width_id] = context.sem_ir().GetIntTypeInfo(op.type_id);
auto [is_signed, bit_width_id] =
context.sem_ir().types().GetIntTypeInfo(op.type_id);
CARBON_CHECK(bit_width_id != IntId::Invalid,
"Cannot evaluate a generic bit width integer: {0}", op);
llvm::APInt op_val = context.ints().GetAtWidth(op.int_id, bit_width_id);
Expand Down Expand Up @@ -770,7 +771,7 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc,
}

auto [lhs_is_signed, lhs_bit_width_id] =
context.sem_ir().GetIntTypeInfo(lhs.type_id);
context.sem_ir().types().GetIntTypeInfo(lhs.type_id);
llvm::APInt lhs_val = context.ints().GetAtWidth(lhs.int_id, lhs_bit_width_id);

llvm::APInt result_val;
Expand Down Expand Up @@ -915,7 +916,8 @@ static auto PerformBuiltinIntComparison(Context& context,
CARBON_CHECK(lhs.type_id == rhs.type_id,
"Builtin comparison with mismatched types!");

auto [is_signed, bit_width_id] = context.sem_ir().GetIntTypeInfo(lhs.type_id);
auto [is_signed, bit_width_id] =
context.sem_ir().types().GetIntTypeInfo(lhs.type_id);
CARBON_CHECK(bit_width_id != IntId::Invalid,
"Cannot evaluate a generic bit width integer: {0}", lhs);
llvm::APInt lhs_val = context.ints().GetAtWidth(lhs.int_id, bit_width_id);
Expand Down Expand Up @@ -1491,6 +1493,7 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
// TODO: This doesn't properly handle redeclarations. Consider adding a
// corresponding `Value` inst for each of these cases, or returning the
// first declaration.
case SemIR::AdaptDecl::Kind:
case SemIR::AssociatedConstantDecl::Kind:
case SemIR::BaseDecl::Kind:
case SemIR::FieldDecl::Kind:
Expand Down Expand Up @@ -1669,7 +1672,6 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
}

// These cases are either not expressions or not constant.
case SemIR::AdaptDecl::Kind:
case SemIR::AddrPattern::Kind:
case SemIR::Assign::Kind:
case SemIR::BindName::Kind:
Expand Down
50 changes: 22 additions & 28 deletions toolchain/check/handle_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "toolchain/check/context.h"
#include "toolchain/check/convert.h"
#include "toolchain/check/decl_name_stack.h"
#include "toolchain/check/diagnostic_helpers.h"
#include "toolchain/check/eval.h"
#include "toolchain/check/generic.h"
#include "toolchain/check/handle.h"
Expand Down Expand Up @@ -387,21 +388,23 @@ auto HandleParseNode(Context& context, Parse::AdaptDeclId node_id) -> bool {
[&] {
CARBON_DIAGNOSTIC(IncompleteTypeInAdaptDecl, Error,
"adapted type {0} is an incomplete type",
SemIR::TypeId);
InstIdAsType);
return context.emitter().Build(node_id, IncompleteTypeInAdaptDecl,
adapted_type_id);
adapted_inst_id);
},
[&] {
CARBON_DIAGNOSTIC(AbstractTypeInAdaptDecl, Error,
"adapted type {0} is an abstract type",
SemIR::TypeId);
"adapted type {0} is an abstract type", InstIdAsType);
return context.emitter().Build(node_id, AbstractTypeInAdaptDecl,
adapted_type_id);
adapted_inst_id);
});
if (adapted_type_id == SemIR::TypeId::Error) {
adapted_inst_id = SemIR::InstId::BuiltinErrorInst;
}

// Build a SemIR representation for the declaration.
class_info.adapt_id = context.AddInst<SemIR::AdaptDecl>(
node_id, {.adapted_type_id = adapted_type_id});
node_id, {.adapted_type_inst_id = adapted_inst_id});

// Extend the class scope with the adapted type's scope if requested.
if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
Expand Down Expand Up @@ -432,9 +435,10 @@ struct BaseInfo {
SemIR::NameScopeId scope_id;
SemIR::InstId inst_id;
};
constexpr BaseInfo BaseInfo::Error = {.type_id = SemIR::TypeId::Error,
.scope_id = SemIR::NameScopeId::Invalid,
.inst_id = SemIR::InstId::Invalid};
constexpr BaseInfo BaseInfo::Error = {
.type_id = SemIR::TypeId::Error,
.scope_id = SemIR::NameScopeId::Invalid,
.inst_id = SemIR::InstId::BuiltinErrorInst};
} // namespace

// Diagnoses an attempt to derive from a final type.
Expand Down Expand Up @@ -529,7 +533,7 @@ auto HandleParseNode(Context& context, Parse::BaseDeclId node_id) -> bool {
context.GetUnboundElementType(class_info.self_type_id, base_info.type_id);
class_info.base_id = context.AddInst<SemIR::BaseDecl>(
node_id, {.type_id = field_type_id,
.base_type_id = base_info.type_id,
.base_type_inst_id = base_info.inst_id,
.index = SemIR::ElementIndex(
context.struct_type_fields_stack().PeekArray().size())});

Expand Down Expand Up @@ -616,26 +620,15 @@ static auto CheckCompleteAdapterClassType(Context& context,
}

// The object representation of the adapter is the object representation
// of the adapted type. This is the adapted type itself unless it's a class
// type.
//
// TODO: The object representation of `const T` should also be the object
// representation of `T`.
auto adapted_type_id = context.insts()
.GetAs<SemIR::AdaptDecl>(class_info.adapt_id)
.adapted_type_id;
if (auto adapted_class =
context.types().TryGetAs<SemIR::ClassType>(adapted_type_id)) {
auto& adapted_class_info = context.classes().Get(adapted_class->class_id);
if (adapted_class_info.adapt_id.is_valid()) {
return adapted_class_info.complete_type_witness_id;
}
}
// of the adapted type.
auto adapted_type_id =
class_info.GetAdaptedType(context.sem_ir(), SemIR::SpecificId::Invalid);
auto object_repr_id = context.types().GetObjectRepr(adapted_type_id);

return context.AddInst<SemIR::CompleteTypeWitness>(
node_id,
{.type_id = context.GetBuiltinType(SemIR::BuiltinInstKind::WitnessType),
.object_repr_id = adapted_type_id});
.object_repr_id = object_repr_id});
}

// Checks that the specified finished class definition is valid and builds and
Expand All @@ -653,10 +646,11 @@ static auto CheckCompleteClassType(Context& context, Parse::NodeId node_id,

bool defining_vtable_ptr = class_info.is_dynamic;
if (class_info.base_id.is_valid()) {
auto base_info = context.insts().GetAs<SemIR::BaseDecl>(class_info.base_id);
auto base_type_id =
class_info.GetBaseType(context.sem_ir(), SemIR::SpecificId::Invalid);
// TODO: If the base class is template dependent, we will need to decide
// whether to add a vptr as part of instantiation.
if (auto* base_class_info = TryGetAsClass(context, base_info.base_type_id);
if (auto* base_class_info = TryGetAsClass(context, base_type_id);
base_class_info && base_class_info->is_dynamic) {
defining_vtable_ptr = false;
}
Expand Down
48 changes: 41 additions & 7 deletions toolchain/check/import_ref.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,9 @@ class ImportRefResolver {

auto untyped_inst = import_ir_.insts().Get(inst_id);
CARBON_KIND_SWITCH(untyped_inst) {
case CARBON_KIND(SemIR::AdaptDecl inst): {
return TryResolveTypedInst(inst, inst_id);
}
case CARBON_KIND(SemIR::AssociatedEntity inst): {
return TryResolveTypedInst(inst);
}
Expand Down Expand Up @@ -1323,6 +1326,27 @@ class ImportRefResolver {
return ResolveAsUntyped(inst);
}

auto TryResolveTypedInst(SemIR::AdaptDecl inst, SemIR::InstId import_inst_id)
-> ResolveResult {
auto adapted_type_const_id = GetLocalConstantId(
import_ir_.constant_values().Get(inst.adapted_type_inst_id));
if (HasNewWork()) {
return Retry();
}

auto adapted_type_inst_id = AddLoadedImportRef(
context_,
{.ir_id = import_ir_id_, .inst_id = inst.adapted_type_inst_id},
SemIR::TypeId::TypeType, adapted_type_const_id);

// Create a corresponding instruction to represent the declaration.
auto inst_id = context_.AddInstInNoBlock(
context_.MakeImportedLocAndInst<SemIR::AdaptDecl>(
AddImportIRInst(import_inst_id),
{.adapted_type_inst_id = adapted_type_inst_id}));
return ResolveAsConstant(context_.constant_values().Get(inst_id));
}

auto TryResolveTypedInst(SemIR::AssociatedEntity inst) -> ResolveResult {
auto type_const_id = GetLocalConstantId(inst.type_id);
if (HasNewWork()) {
Expand Down Expand Up @@ -1359,19 +1383,22 @@ class ImportRefResolver {
auto TryResolveTypedInst(SemIR::BaseDecl inst, SemIR::InstId import_inst_id)
-> ResolveResult {
auto type_const_id = GetLocalConstantId(inst.type_id);
auto base_type_const_id = GetLocalConstantId(inst.base_type_id);
auto base_type_const_id = GetLocalConstantId(
import_ir_.constant_values().Get(inst.base_type_inst_id));
if (HasNewWork()) {
return Retry();
}

// Import the instruction in order to update contained base_type_id and
// track the import location.
auto base_type_inst_id = AddLoadedImportRef(
context_, {.ir_id = import_ir_id_, .inst_id = inst.base_type_inst_id},
SemIR::TypeId::TypeType, base_type_const_id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth trying to share logic with AdaptDecl, maybe with a template? It looks like this section mirrors.

Of course, maybe the answer is just "that's not how we do it elsewhere" or "think about it as part of the other refactoring"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's think about it as part of the other refactoring :-)


// Create a corresponding instruction to represent the declaration.
auto inst_id = context_.AddInstInNoBlock(
context_.MakeImportedLocAndInst<SemIR::BaseDecl>(
AddImportIRInst(import_inst_id),
{.type_id = context_.GetTypeIdForTypeConstant(type_const_id),
.base_type_id =
context_.GetTypeIdForTypeConstant(base_type_const_id),
.base_type_inst_id = base_type_inst_id,
.index = inst.index}));
return ResolveAsConstant(context_.constant_values().Get(inst_id));
}
Expand Down Expand Up @@ -1454,7 +1481,8 @@ class ImportRefResolver {
auto AddClassDefinition(const SemIR::Class& import_class,
SemIR::Class& new_class,
SemIR::InstId complete_type_witness_id,
SemIR::InstId base_id) -> void {
SemIR::InstId base_id, SemIR::InstId adapt_id)
-> void {
new_class.definition_id = new_class.first_owning_decl_id;

new_class.complete_type_witness_id = complete_type_witness_id;
Expand All @@ -1474,6 +1502,9 @@ class ImportRefResolver {
if (import_class.base_id.is_valid()) {
new_class.base_id = base_id;
}
if (import_class.adapt_id.is_valid()) {
new_class.adapt_id = adapt_id;
}
}

auto TryResolveTypedInst(SemIR::ClassDecl inst,
Expand Down Expand Up @@ -1534,6 +1565,9 @@ class ImportRefResolver {
auto base_id = import_class.base_id.is_valid()
? GetLocalConstantInstId(import_class.base_id)
: SemIR::InstId::Invalid;
auto adapt_id = import_class.adapt_id.is_valid()
? GetLocalConstantInstId(import_class.adapt_id)
: SemIR::InstId::Invalid;

if (HasNewWork()) {
return Retry(class_const_id);
Expand All @@ -1553,7 +1587,7 @@ class ImportRefResolver {

if (import_class.is_defined()) {
AddClassDefinition(import_class, new_class, complete_type_witness_id,
base_id);
base_id, adapt_id);
}

return ResolveAsConstant(class_const_id);
Expand Down
Loading
Loading