Skip to content

Avoid resolving the decl block for specifics in imported instructions #5517

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

Merged
merged 9 commits into from
May 23, 2025

Conversation

danakj
Copy link
Contributor

@danakj danakj commented May 22, 2025

Move the operation of resolving the specific decl block from GetConstantValue() to TryEvalTypedInst(), with is now happening after replacing the fields of the instruction with new constant values, but before running the evaluation of the instruction. Since imported instructions are not evaluated, this avoids resolving the specific decl block from imported instructions, resolving a TODO in AddImportedConstant(). Now AddImportedConstant() can replace constant values in its fields without having to worry about that operation resolving any specific decl blocks.

We get to add a new TODO however, to explain why we still need a special case in resolving specific decl blocks for handling Impl construction. The witness table contains instructions with specifics referring to the generic self of the impl declaration. But the table must be constructed before the impl's generic is finished, in order to make the instructions dependent for the generic. But then resolving the specific decl block can't be done when the instructions are created and evaluated, as that requires a finished generic.

@danakj danakj requested a review from zygoloid May 22, 2025 16:16
@github-actions github-actions bot requested a review from geoffromer May 22, 2025 16:16
@danakj danakj removed the request for review from geoffromer May 22, 2025 16:16
danakj and others added 2 commits May 22, 2025 14:18
Co-authored-by: Jon Ross-Perkins <[email protected]>
Copy link
Contributor Author

@danakj danakj left a comment

Choose a reason for hiding this comment

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

PTAL

@danakj danakj requested a review from jonmeow May 22, 2025 18:18
@danakj
Copy link
Contributor Author

danakj commented May 22, 2025

I resolved the TODO in ResolveSpecificDeclForInst by only not resolving specific decls for self-specifics. A generic's self specific has its decl block explicitly resolved in FinishGenericDecl(), and that is the only specific that should be appearing inside dependent instructions that refers to the being-built generic.

Copy link
Contributor

@jonmeow jonmeow left a comment

Choose a reason for hiding this comment

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

Thanks! To be sure, I agree the switch is a trade-off, wasn't sure which way you'd really lean.

Comment on lines +772 to +773
((values[SemIR::IdKind::template For<Types>.ToIndex()] =
HasGetConstantValueOverload<Types>),
Copy link
Contributor

@jonmeow jonmeow May 22, 2025

Choose a reason for hiding this comment

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

The way this is initializing from a concept seems weird. I would've thought you could write something like:

    constexpr std::array<bool, SemIR::IdKind::NumTypes> Values = {
        ((HasGetConstantValueOverload<Types>), ...)};

But that doesn't work. I don't know if you have ideas -- I also would suggest spending against much time on this, it seems minor. I assume you're using the struct to duck the nullptr thing I was doing, which seems fine though the need for a forward declaration seems like an odd quirk of C++.

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 that doesn't work because Types does not include Invalid and None, so the RHS will be incorrect (wrong size, possibly wrong positions). And yeah, I was trying to avoid the nullptr dance :)

Copy link
Contributor

Choose a reason for hiding this comment

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

That's why NumTypes. ;)

RHS should have right size and positions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yeah I see.

I think this doesn't work because (x,...) is very different than writing x,y,z. The operator comma is applied to each value in the fold expression, it doesn't expand like a macro would leaving behind all the elements from the fold.

Regardless, using NumTypes is a little improvement here, doing that.

Copy link
Contributor

@jonmeow jonmeow May 23, 2025

Choose a reason for hiding this comment

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

To just note, NumTypes may not work as-is. You'd need to still handle None, which is used for zero- and single- argument instructions (in ArgAndKind). Though you could also just handle that (and Invalid) directly in the switch.

(like I said, I could easily get the init to work)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh hm, okay thanks

@danakj danakj enabled auto-merge May 23, 2025 15:56
Copy link
Contributor

@jonmeow jonmeow left a comment

Choose a reason for hiding this comment

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

LG

@jonmeow
Copy link
Contributor

jonmeow commented May 23, 2025

(sorry, was playing with changes and accidentally did a push -- shouldn't have made any modifications)

@danakj danakj added this pull request to the merge queue May 23, 2025
Merged via the queue into carbon-language:trunk with commit 5aea18f May 23, 2025
12 of 15 checks passed
@danakj danakj deleted the eval-specifics branch May 23, 2025 17:25
github-merge-queue bot pushed a commit that referenced this pull request May 23, 2025
Tinkering with #5517, splitting out this suggestion to try to avoid
delaying merge. I figured out what I was missing on the variadiac
expansion. :)

(and also realized the struct could probably be a function)
chandlerc pushed a commit to chandlerc/carbon-lang that referenced this pull request May 31, 2025
…carbon-language#5517)

Move the operation of resolving the specific decl block from
`GetConstantValue()` to `TryEvalTypedInst()`, with is now happening
after replacing the fields of the instruction with new constant values,
but before running the evaluation of the instruction. Since imported
instructions are not evaluated, this avoids resolving the specific decl
block from imported instructions, resolving a TODO in
`AddImportedConstant()`. Now `AddImportedConstant()` can replace
constant values in its fields without having to worry about that
operation resolving any specific decl blocks.

We get to add a new TODO however, to explain why we still need a special
case in resolving specific decl blocks for handling `Impl` construction.
The witness table contains instructions with specifics referring to the
generic self of the impl declaration. But the table must be constructed
before the impl's generic is finished, in order to make the instructions
dependent for the generic. But then resolving the specific decl block
can't be done when the instructions are created and evaluated, as that
requires a finished generic.

---------

Co-authored-by: Jon Ross-Perkins <[email protected]>
chandlerc pushed a commit to chandlerc/carbon-lang that referenced this pull request May 31, 2025
Tinkering with carbon-language#5517, splitting out this suggestion to try to avoid
delaying merge. I figured out what I was missing on the variadiac
expansion. :)

(and also realized the struct could probably be a function)
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