Rollup merge of #144915 - compiler-errors:tail-call-ret-ty-equality, r=WaffleLapkin,lcnr
Defer tail call ret ty equality to check_tail_calls
Fixes rust-lang/rust#144892.
Currently the tail call signature check assumes that return types have been accounted for. However, this is not complete for several reasons.
Firstly, we were using subtyping instead of equality in the HIR typeck code:
e1b9081e69/compiler/rustc_hir_typeck/src/expr.rs (L1096)
We could fix this, but it doesn't really do much for us anyways since HIR typeck doesn't care about regions.
That means, secondly, we'd need to fix the terminator type check in MIR typeck to account for variances, since tail call terminators need to relate their arguments invariantly to account for the "signature must be equal" rule. This seems annoying.
All of this seems like a lot of work, and we already are *manually* checking argument equality. Let's just extend the `check_tail_calls` to account for mismatches in return types anyways.
r? ``````@WaffleLapkin``````
This commit is contained in:
commit
f1a7294e09
5 changed files with 61 additions and 25 deletions
|
|
@ -1895,7 +1895,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
if !output_ty
|
||||
.is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env))
|
||||
{
|
||||
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
||||
span_mirbug!(self, term, "call to non-diverging function {:?} w/o dest", sig);
|
||||
}
|
||||
} else {
|
||||
let dest_ty = destination.ty(self.body, tcx).ty;
|
||||
|
|
|
|||
|
|
@ -135,30 +135,23 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
|||
self.report_abi_mismatch(expr.span, caller_sig.abi, callee_sig.abi);
|
||||
}
|
||||
|
||||
// FIXME(explicit_tail_calls): this currently fails for cases where opaques are used.
|
||||
// e.g.
|
||||
// ```
|
||||
// fn a() -> impl Sized { become b() } // ICE
|
||||
// fn b() -> u8 { 0 }
|
||||
// ```
|
||||
// we should think what is the expected behavior here.
|
||||
// (we should probably just accept this by revealing opaques?)
|
||||
if caller_sig.inputs_and_output != callee_sig.inputs_and_output {
|
||||
if caller_sig.inputs() != callee_sig.inputs() {
|
||||
self.report_arguments_mismatch(
|
||||
expr.span,
|
||||
self.tcx.liberate_late_bound_regions(
|
||||
CRATE_DEF_ID.to_def_id(),
|
||||
self.caller_ty.fn_sig(self.tcx),
|
||||
),
|
||||
self.tcx
|
||||
.liberate_late_bound_regions(CRATE_DEF_ID.to_def_id(), ty.fn_sig(self.tcx)),
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME(explicit_tail_calls): this currently fails for cases where opaques are used.
|
||||
// e.g.
|
||||
// ```
|
||||
// fn a() -> impl Sized { become b() } // ICE
|
||||
// fn b() -> u8 { 0 }
|
||||
// ```
|
||||
// we should think what is the expected behavior here.
|
||||
// (we should probably just accept this by revealing opaques?)
|
||||
if caller_sig.output() != callee_sig.output() {
|
||||
span_bug!(expr.span, "hir typeck should have checked the return type already");
|
||||
}
|
||||
self.report_signature_mismatch(
|
||||
expr.span,
|
||||
self.tcx.liberate_late_bound_regions(
|
||||
CRATE_DEF_ID.to_def_id(),
|
||||
self.caller_ty.fn_sig(self.tcx),
|
||||
),
|
||||
self.tcx.liberate_late_bound_regions(CRATE_DEF_ID.to_def_id(), ty.fn_sig(self.tcx)),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -365,7 +358,7 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
|||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_arguments_mismatch(
|
||||
fn report_signature_mismatch(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
caller_sig: ty::FnSig<'_>,
|
||||
|
|
|
|||
15
tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.rs
Normal file
15
tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#![feature(explicit_tail_calls)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
fn foo() -> for<'a> fn(&'a i32) {
|
||||
become bar();
|
||||
//~^ ERROR mismatched signatures
|
||||
}
|
||||
|
||||
fn bar() -> fn(&'static i32) {
|
||||
dummy
|
||||
}
|
||||
|
||||
fn dummy(_: &i32) {}
|
||||
|
||||
fn main() {}
|
||||
12
tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.stderr
Normal file
12
tests/ui/explicit-tail-calls/ret-ty-hr-mismatch.stderr
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
error: mismatched signatures
|
||||
--> $DIR/ret-ty-hr-mismatch.rs:5:5
|
||||
|
|
||||
LL | become bar();
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: `become` requires caller and callee to have matching signatures
|
||||
= note: caller signature: `fn() -> for<'a> fn(&'a i32)`
|
||||
= note: callee signature: `fn() -> fn(&'static i32)`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
16
tests/ui/explicit-tail-calls/ret-ty-modulo-anonymization.rs
Normal file
16
tests/ui/explicit-tail-calls/ret-ty-modulo-anonymization.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Ensure that we anonymize the output of a function for tail call signature compatibility.
|
||||
|
||||
//@ check-pass
|
||||
|
||||
#![feature(explicit_tail_calls)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
fn foo() -> for<'a> fn(&'a ()) {
|
||||
become bar();
|
||||
}
|
||||
|
||||
fn bar() -> for<'b> fn(&'b ()) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue