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 @@ -390,18 +390,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 @@ -957,7 +958,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 @@ -1127,12 +1134,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 @@ -1400,13 +1405,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 @@ -431,9 +431,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 @@ -607,15 +607,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 @@ -712,12 +709,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 @@ -676,7 +676,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 @@ -718,7 +718,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 @@ -771,7 +772,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 @@ -916,7 +917,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 @@ -1497,6 +1499,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 @@ -1699,7 +1702,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
60 changes: 26 additions & 34 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 @@ -531,7 +535,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::Invalid});

if (base_info.type_id != SemIR::TypeId::Error) {
Expand Down Expand Up @@ -607,27 +611,17 @@ 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});
}

static auto AddStructTypeFields(
Context& context,
llvm::SmallVector<SemIR::StructTypeField>& struct_type_fields)
Expand Down Expand Up @@ -664,11 +658,12 @@ static auto CheckCompleteClassType(Context& context, Parse::NodeId node_id,
}

bool defining_vptr = 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);
if (base_type_id.is_valid()) {
// 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_vptr = false;
}
Expand All @@ -684,16 +679,13 @@ static auto CheckCompleteClassType(Context& context, Parse::NodeId node_id,
.type_id = context.GetPointerType(
context.GetBuiltinType(SemIR::BuiltinInstKind::VtableType))});
}
if (class_info.base_id.is_valid()) {
if (base_type_id.is_valid()) {
auto base_decl = context.insts().GetAs<SemIR::BaseDecl>(class_info.base_id);
base_decl.index =
SemIR::ElementIndex{static_cast<int>(struct_type_fields.size())};
context.ReplaceInstPreservingConstantValue(class_info.base_id, base_decl);
struct_type_fields.push_back(
{.name_id = SemIR::NameId::Base,
.type_id = context.insts()
.GetAs<SemIR::BaseDecl>(class_info.base_id)
.base_type_id});
{.name_id = SemIR::NameId::Base, .type_id = base_type_id});
}

return context.AddInst<SemIR::CompleteTypeWitness>(
Expand Down
Loading