mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Step through splices when checking for a bound method. (#7700)
`GetCallee` is sometimes called on a spliced instruction, and is checking its exact inst operand to see if it's a `BoundMethod`. This fails if the `BoundMethod` is wrapped in another instruction, such as a splice. Normally our approach for such a situation would be to constant-evaluate the operand, but that doesn't work here because the `BoundMethod` will be non-constant if its bound `self` is. So instead we now step through splice instructions manually when looking for the `BoundMethod`.
This commit is contained in:
@@ -16,6 +16,33 @@
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
auto TryGetCalleeAsBoundMethod(const File& sem_ir, InstId callee_id,
|
||||
SpecificId caller_specific_id)
|
||||
-> std::optional<BoundMethod> {
|
||||
// Step through splices before checking for a bound method. Unfortunately we
|
||||
// can't just look at the constant value of callee_id here, because bound
|
||||
// methods are non-constant if their `self` is, so we do a mini-eval here.
|
||||
while (true) {
|
||||
auto inst = sem_ir.insts().Get(callee_id);
|
||||
if (auto splice_inst = inst.TryAs<SpliceInst>()) {
|
||||
auto inst_value_id = GetConstantValueInSpecific(
|
||||
sem_ir, caller_specific_id, splice_inst->inst_id);
|
||||
if (!inst_value_id.is_concrete()) {
|
||||
break;
|
||||
}
|
||||
callee_id = sem_ir.constant_values()
|
||||
.GetInstAs<SemIR::InstValue>(inst_value_id)
|
||||
.inst_id;
|
||||
} else if (auto splice_block = inst.TryAs<SpliceBlock>()) {
|
||||
callee_id = splice_block->result_id;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sem_ir.insts().TryGetAs<BoundMethod>(callee_id);
|
||||
}
|
||||
|
||||
auto GetCallee(const File& sem_ir, InstId callee_id,
|
||||
SpecificId caller_specific_id) -> Callee {
|
||||
CalleeFunction fn = {.function_id = FunctionId::None,
|
||||
@@ -23,7 +50,8 @@ auto GetCallee(const File& sem_ir, InstId callee_id,
|
||||
.resolved_specific_id = SpecificId::None,
|
||||
.self_type_id = InstId::None,
|
||||
.self_id = InstId::None};
|
||||
if (auto bound_method = sem_ir.insts().TryGetAs<BoundMethod>(callee_id)) {
|
||||
if (auto bound_method =
|
||||
TryGetCalleeAsBoundMethod(sem_ir, callee_id, caller_specific_id)) {
|
||||
fn.self_id = bound_method->object_id;
|
||||
callee_id = bound_method->function_decl_id;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user