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

Conversation

zygoloid
Copy link
Contributor

Represent the type as an InstId rather than as a TypeId to preserve how it was written and better support tracking its value in a generic. Add accessors to Class to get the base and adapted type to reduce code duplication, and add TypeStore::GetObjectRepr to make it easier to map from a type to its possibly-adapted object representation type. In passing, also move GetIntTypeInfo and GetUnqualifiedType into TypeStore.

This fixes specifics of generic adapters to properly look at the specific adapted type, and also fixes importing of adapters.

Comment on lines 13 to 38
auto Class::GetAdaptedType(const File& file, SpecificId specific_id) const
-> TypeId {
if (!adapt_id.is_valid()) {
return TypeId::Invalid;
}
if (base_id == SemIR::InstId::BuiltinErrorInst) {
return TypeId::Error;
}
return TypeId::ForTypeConstant(GetConstantValueInSpecific(
file, specific_id,
file.insts().GetAs<AdaptDecl>(adapt_id).adapted_type_inst_id));
}

auto Class::GetBaseType(const File& file, SpecificId specific_id) const
-> TypeId {
if (!base_id.is_valid()) {
return TypeId::Invalid;
}
if (base_id == SemIR::InstId::BuiltinErrorInst) {
return TypeId::Error;
}
CARBON_CHECK(base_id.index >= 0);
return TypeId::ForTypeConstant(GetConstantValueInSpecific(
file, specific_id,
file.insts().GetAs<BaseDecl>(base_id).base_type_inst_id));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looking at the rename of adapted_type_inst_id, had you considered renaming base_type_inst_id and adapted_type_inst_id to something like extended_type_inst_id? It looks like adding AnyExtendedDecl (or a template on AdaptDecl/BaseDecl) would allow code sharing here:

Suggested change
auto Class::GetAdaptedType(const File& file, SpecificId specific_id) const
-> TypeId {
if (!adapt_id.is_valid()) {
return TypeId::Invalid;
}
if (base_id == SemIR::InstId::BuiltinErrorInst) {
return TypeId::Error;
}
return TypeId::ForTypeConstant(GetConstantValueInSpecific(
file, specific_id,
file.insts().GetAs<AdaptDecl>(adapt_id).adapted_type_inst_id));
}
auto Class::GetBaseType(const File& file, SpecificId specific_id) const
-> TypeId {
if (!base_id.is_valid()) {
return TypeId::Invalid;
}
if (base_id == SemIR::InstId::BuiltinErrorInst) {
return TypeId::Error;
}
CARBON_CHECK(base_id.index >= 0);
return TypeId::ForTypeConstant(GetConstantValueInSpecific(
file, specific_id,
file.insts().GetAs<BaseDecl>(base_id).base_type_inst_id));
}
// Returns the extended type for an `adapt` or `base` declaration.
static auto GetExtendedType(const File& file, SpecificId specific_id, InstId extended_id) -> TypeId {
if (!extended_id.is_valid()) {
return TypeId::Invalid;
}
if (extended_id == SemIR::InstId::BuiltinErrorInst) {
return TypeId::Error;
}
return TypeId::ForTypeConstant(GetConstantValueInSpecific(
file, specific_id,
file.insts().GetAs<AnyExtendedDecl>(extended_id).extended_type_inst_id));
}
auto Class::GetAdaptedType(const File& file, SpecificId specific_id) const
-> TypeId {
return GetExtendedType(file, specific_id, adapt_id);
}
auto Class::GetBaseType(const File& file, SpecificId specific_id) const
-> TypeId {
return GetExtendedType(file, specific_id, base_id);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems like a nice idea. The name doesn't work for me, though -- an adapted type need not be extended (you can use adapt without extend), and I think there's a reasonable chance we'll decide at some point we want to allow base without extend too. Will take to #naming.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, went with "foundation declaration" for base type or adapted type.

toolchain/check/handle_class.cpp Outdated Show resolved Hide resolved
Comment on lines 1386 to 1394
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 :-)

Comment on lines +84 to +93
if (auto base_type_id = self_class_info.GetBaseType(
context.sem_ir(), self_class_type->specific_id);
base_type_id.is_valid()) {
if (context.types().GetConstantId(base_type_id) == name_scope_const_id) {
return SemIR::AccessKind::Protected;
}
} else if (auto adapt_decl =
context.insts().TryGetAsIfValid<SemIR::AdaptDecl>(
self_class_info.adapt_id)) {
if (adapt_decl->adapted_type_id == class_info.self_type_id) {
// TODO: Also check whether this base class has a base class of its own.
} else if (auto adapt_type_id = self_class_info.GetAdaptedType(
context.sem_ir(), self_class_type->specific_id);
adapt_type_id.is_valid()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You've written similar in a couple spots (e.g. context.cpp), where the same logic is done on the extended type. Would it be worth having a function like GetExtendedType that returns base or adapt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I plan to send a follow-up PR that removes the adapter handling here and in DiagnoseInvalidQualifiedNameAccess, because it doesn't match the design (see #4560), which I think would not leave much use of this facility.

@@ -239,6 +209,24 @@ static auto EmitAsConstant(ConstantContext& /*context*/,
CARBON_FATAL("TODO: Add support: {0}", inst);
}

template <typename InstT>
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add a comment explaining this...

Though I'll note this strays a little from the original change (as does TypeStore). Some of this feels like it would've been nicer split out, but I'm basically done reviewing now. :-P

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, sorry about that. (I started with the TypeStore refactoring and ended up cleaning up too much other stuff "in passing", ending up with this mostly being a change to base / adapt declarations instead.) :(

Comment added.

@chandlerc chandlerc self-requested a review November 26, 2024 02:19
Copy link
Contributor

@chandlerc chandlerc left a comment

Choose a reason for hiding this comment

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

Nice! Comments from previous review round seem addressed. One optional one below, but LG if you'd like to do that in a follow-up.

Comment on lines +39 to +50
auto TypeStore::IsSignedInt(TypeId int_type_id) const -> bool {
auto object_repr_id = GetObjectRepr(int_type_id);
if (!object_repr_id.is_valid()) {
return false;
}
auto inst_id = GetInstId(int_type_id);
if (inst_id == InstId::BuiltinIntLiteralType) {
return true;
}
auto int_type = file_->insts().TryGetAs<IntType>(inst_id);
return int_type && int_type->int_kind.is_signed();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that this GetIntTypeInfo is a method here, do you want to implement this in terms of it?

Happy for this to be a follow-up PR if that's easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think this is completely straightforward, given that IsSignedInt returns false on non-integer types whereas GetIntTypeInfo CHECK-fails, so I'm going to look at this in a follow-up PR.


// No type_id; this is not a value.
TypeId adapted_type_id;
InstId adapted_type_inst_id;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be foundation_type_inst_id? Given the amount of implicit magic in this header, especially with respect to Any types, I think it would be helpful to be as unambiguous as possible about the intended correspondence of the fields. I think it could also help readability, by acting as an illustration of the meaning of "foundation type".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm, I see your point. On the other hand, all producers and consumers of this field (and the field on BaseDecl) know that they're using this specific kind of declaration, and we use the term "base type" and "adapted type" elsewhere to refer to this value.

The pattern we use elsewhere for Any types is to have generic field names in the Any type and more specific field names in the corresponding specific Insts -- for example, AnyAggregateAccess::aggregate_id corresponds to StructAccess::struct_id, TupleAccess::tuple_id, ClassElementAccess::base_id (not a great name), and InterfaceWitnessAccess::witness_id. I think the usages of those fields would be made less clear by using aggregate_id in all cases.

Perhaps a comment linking the insts in a category back to any corresponding category would work better? In any case, I think this goes beyond this PR, so I'd suggest we discuss it separately. Will start a discussion in #toolchain.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, resolving this separately sounds good.

@zygoloid zygoloid requested a review from geoffromer November 27, 2024 01:27

// No type_id; this is not a value.
TypeId adapted_type_id;
InstId adapted_type_inst_id;
Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, resolving this separately sounds good.

toolchain/check/testdata/class/generic/adapt.carbon Outdated Show resolved Hide resolved
@zygoloid zygoloid enabled auto-merge November 27, 2024 21:41
@zygoloid zygoloid added this pull request to the merge queue Nov 27, 2024
Merged via the queue into carbon-language:trunk with commit d6ec885 Nov 27, 2024
8 checks passed
@zygoloid zygoloid deleted the toolchain-refactor-typestore branch November 27, 2024 22:38
bricknerb pushed a commit to bricknerb/carbon-lang that referenced this pull request Nov 28, 2024
…uage#4564)

Represent the type as an `InstId` rather than as a `TypeId` to preserve
how it was written and better support tracking its value in a generic.
Add accessors to `Class` to get the base and adapted type to reduce code
duplication, and add `TypeStore::GetObjectRepr` to make it easier to map
from a type to its possibly-adapted object representation type. In
passing, also move `GetIntTypeInfo` and `GetUnqualifiedType` into
`TypeStore`.

This fixes specifics of generic adapters to properly look at the
specific adapted type, and also fixes importing of adapters.

---------

Co-authored-by: Jon Ross-Perkins <[email protected]>
danakj pushed a commit to danakj/carbon-lang that referenced this pull request Dec 3, 2024
…uage#4564)

Represent the type as an `InstId` rather than as a `TypeId` to preserve
how it was written and better support tracking its value in a generic.
Add accessors to `Class` to get the base and adapted type to reduce code
duplication, and add `TypeStore::GetObjectRepr` to make it easier to map
from a type to its possibly-adapted object representation type. In
passing, also move `GetIntTypeInfo` and `GetUnqualifiedType` into
`TypeStore`.

This fixes specifics of generic adapters to properly look at the
specific adapted type, and also fixes importing of adapters.

---------

Co-authored-by: Jon Ross-Perkins <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants