Skip to content

Conversation

@jonmeow
Copy link
Contributor

@jonmeow jonmeow commented Oct 3, 2025

This is modifying the TypeCanDestroy implementation to more closely examine types, in particular making it more sensitive about type structure. Note abstract cannot be destroyed per #6124, and partial is a question per #6161 but this makes it destructible for consistency with existing tests.

Note this leaves TODOs to dig into types further. This PR led to substantial work solving issues in generics handling, so trying to get it in partly to prevent regressions.

@jonmeow jonmeow force-pushed the destroy-more branch 2 times, most recently from 723c9a9 to ca6eb8d Compare October 7, 2025 17:17
@jonmeow jonmeow force-pushed the destroy-more branch 2 times, most recently from c45f33e to 8b66dca Compare December 3, 2025 23:07
@jonmeow
Copy link
Contributor Author

jonmeow commented Dec 3, 2025

Note this PR currently depends on #6458; the main commit is 8b66dca

@jonmeow jonmeow marked this pull request as ready for review December 3, 2025 23:11
@jonmeow jonmeow requested a review from a team as a code owner December 3, 2025 23:11
@jonmeow jonmeow requested review from zygoloid and removed request for a team December 3, 2025 23:11
// TODO: We don't have an approved design for an `Optional` type yet, but it's
// used by the design for `Iterate`. The API here is a placeholder.
class Optional(T:! OptionalStorage) {
class Optional(T:! Destroy & OptionalStorage) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not necessarily opposed to this constraint, but I wonder it would be better for this to be a constraint on the Destroy impl rather than on the type -- that is, that Optional(T) should implement Destroy only if T implements Destroy rather than requiring that T impls Destroy. I don't think we're destroying a T as part of the definition of Optional (other than in its Destroy impl).

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. This lingered from the earlier Optional approach, and I didn't think about it while updating.

fn G(T:! Core.Destroy) {
// We can initialize this without knowing T.
//@dump-sem-ir-begin
var arr: array(T, 0) = ();
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if arrays with bound 0 should be a special case and not require T to be destroyable here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there a use-case for that? If not I'd suggest not special casing... it seems to not be supported in C++ (https://cpp.compiler-explorer.com/z/98q6c1e7K) so perhaps niche enough it's not needed.

A 0-sized array seems like a niche use-case. My guess would be the most common use would be something like a generic where the array size is a parameter, and often 0. But such a thing would typically still need to support non-0-sized arrays (if they're special-casing only nondestroyable types as a 0-sized array, it seems they could equally special-case some other way)

Comment on lines +694 to +695
auto obj_repr_id =
class_info.GetObjectRepr(context.sem_ir(), SemIR::SpecificId::None);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
auto obj_repr_id =
class_info.GetObjectRepr(context.sem_ir(), SemIR::SpecificId::None);
auto obj_repr_id =
class_info.GetObjectRepr(context.sem_ir(), class_type.specific_id);

I think this might allow you to undo a bunch of the test changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This doesn't work right now, adding a TODO

Comment on lines 672 to 676
case CARBON_KIND(SemIR::BaseDecl base_decl): {
work.push_back(
{.id = base_decl.base_type_inst_id, .allow_abstract = true});
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this reachable? We seem to generally only have types on the worklist, and BaseDecl isn't a 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.

Removed, must've been lingering.

Comment on lines +765 to +766
default:
CARBON_FATAL("TypeCanDestroy found unexpected inst: {0}", inst);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we arrange this so that we get a build failure if someone adds a new type for which is_type is not InstIsType::Never and misses it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is that desirable? There's a lot of InstIsType::Maybe and I'm not clear they can occur here

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 think ImplWitnessAccess is the only Maybe I'm seeing as required to handle, at least for now)

Copy link
Contributor Author

@jonmeow jonmeow Dec 4, 2025

Choose a reason for hiding this comment

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

(and I assume it'd require refactoring into an overload dispatch to make a build failure)

jonmeow and others added 5 commits December 4, 2025 09:51
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
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.

2 participants