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

Rework how we check calls to support deduced implicit parameters #4302

Merged
merged 18 commits into from
Sep 13, 2024

Conversation

zygoloid
Copy link
Contributor

Instead of the call instruction having a block with one argument per explicit argument, preceded optionally by self and followed optionally by a return slot, change the call to store only the runtime arguments. Store an index on the runtime parameters to make it easier to determine the correspondence between arguments and parameters in a call. Compile-time parameters, whether implicit or explicit, are no longer included in the call argument list. Instead, they're tracked only in the specific_id on the callee.

For calls to generic classes and generic interfaces, it no longer makes sense to form a call instruction, given that the entirety of the result is determined by the specific_id, which is now formed when checking the call. Instead, the call instruction now only models function calls, and not calls to other kinds of parameterized entity names, and we create a class_type or interface_type instead of a call instruction to model these kinds of calls. Notionally the model here is that we're following the #3720 approach for calls, but for now we inline the Call.Op function when forming SemIR.

We now also track the enclosing specific for a generic class or generic interface that appears within an enclosing generic. This is necessary in order for deduction of the inner generic parameters to not get confused by the outer generic parameters being absent.

In order to not regress diagnostics, the template argument deduction mechanism has been extended to specify the name of the parameter we're deducing against when possible, and call arity mismatch errors are now diagnosed before performing deduction rather than afterwards.

@zygoloid
Copy link
Contributor Author

Let me know if you'd prefer that I try to split some smaller parts out of this for review purposes -- there's probably a few pieces here that could be landed separately.

@@ -829,6 +837,14 @@ class FormatterImpl {
}
}

auto FormatInstRHS(GenericInterfaceType inst) -> void {
if (inst.enclosing_specific_id.is_valid()) {
Copy link
Contributor

@jonmeow jonmeow Sep 13, 2024

Choose a reason for hiding this comment

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

Minor suggestion, comparing with FunctionType, ClassType, and InterfaceType, maybe add a helper:

// Shared formatting for entities that have an optional specific.
template<typename EntityId>
auto FormatInstRHSForEntity(EntityId entity_id, SpecificId specific_id) -> void {
  if (specific_id.is_valid()) {
    FormatArgs(entity_id, specific_id);
  } else {
    FormatArgs(entity_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.

Yeah, we have a bunch of instructions like this. I'll send a follow-up PR for this.

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.

This makes sense to me. There's just one inconsistency in import_ref.cpp that I'm trying to figure out, but otherwise looks good. Approving per my comment there.

Comment on lines 218 to 219
if (!param.index.is_valid()) {
// Parameter is not passed at runtime.
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think the comment would still be helpful if the name were param.runtime_index?

Partly noting due to the identical comment on 316. It strikes me a related option might be, had you considered starting to add accessors to the typed instructions, e.g. param.is_runtime() or is_lowered?

Note, I'm also fine leaving this as-is if you prefer the comment, the code is clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to runtime_index.

SemIR::SpecificId specific_id;
};

static auto ResolveCalleeInCall(Context& context, SemIR::LocId loc_id,
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like a pretty complex signature, is it worth a comment? What's the semantic of self_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.

Commented.

callee_info.implicit_param_refs_id, callee_info.param_refs_id, self_id,
arg_ids);
if (!specific_id.is_valid()) {
return {.is_valid = false, .specific_id = SemIR::SpecificId::Invalid};
Copy link
Contributor

Choose a reason for hiding this comment

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

Had you considered a std::optional<SpecificId> return, with nullopt for invalid calls?

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.

if (!param_inst) {
// Once we support more generalized patterns we will need to diagnose
// parameters with unsupported patterns.
context.TODO(param_id, "unexpected syntax for parameter");
Copy link
Contributor

Choose a reason for hiding this comment

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

There aren't any tests hitting this case, can there be, or is the code just not there yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The code to parse more complex patterns isn't there yet; I've added a test so we should cover this once we get the parsing support.

Comment on lines +1280 to +1281
// This is the end of the first phase. Don't make a new class yet if
// we already have new work.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is marked as the end of the first phase, but so is line 1289. Is this actually becoming four phases? Should the check on line 1288 just be removed, comparing with the interface version?

I'll be approving assuming 1288 should just be removed, please let me know if I'm misunderstanding.

(note, this inconsistency makes me wonder if there's a good way to factor towards more code sharing)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, the second check is redundant and it looks like I forgot to delete it. Deleted now matching the other cases.

Yeah, I think it'd be good to look into refactoring function / class / interface handling.

@zygoloid zygoloid enabled auto-merge September 13, 2024 19:54
@zygoloid zygoloid added this pull request to the merge queue Sep 13, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Sep 13, 2024
@zygoloid zygoloid enabled auto-merge September 13, 2024 20:53
@zygoloid zygoloid added this pull request to the merge queue Sep 13, 2024
Merged via the queue into carbon-language:trunk with commit 0354efa Sep 13, 2024
8 checks passed
@zygoloid zygoloid deleted the toolchain-numbered-params branch September 13, 2024 22:10
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