Rollup merge of #100473 - compiler-errors:normalize-the-fn-def-sig-plz, r=lcnr
Attempt to normalize `FnDef` signature in `InferCtxt::cmp` Stashes a normalization callback in `InferCtxt` so that the signature we get from `tcx.fn_sig(..).subst(..)` in `InferCtxt::cmp` can be properly normalized, since we cannot expect for it to have normalized types since it comes straight from astconv. This is kind of a hack, but I will say that `@jyn514` found the fact that we present unnormalized types to be very confusing in real life code, and I agree with that feeling. Though altogether I am still a bit unsure about whether this PR is worth the effort, so I'm open to alternatives and/or just closing it outright. On the other hand, this isn't a ridiculously heavy implementation anyways -- it's less than a hundred lines of changes, and half of that is just miscellaneous cleanup. This is stacked onto #100471 which is basically unrelated, and it can be rebased off of that when that lands or if needed. --- The code: ```rust trait Foo { type Bar; } impl<T> Foo for T { type Bar = i32; } fn foo<T>(_: <T as Foo>::Bar) {} fn needs_i32_ref_fn(f: fn(&'static i32)) {} fn main() { needs_i32_ref_fn(foo::<()>); } ``` Before: ``` = note: expected fn pointer `fn(&'static i32)` found fn item `fn(<() as Foo>::Bar) {foo::<()>}` ``` After: ``` = note: expected fn pointer `fn(&'static i32)` found fn item `fn(i32) {foo::<()>}` ```
This commit is contained in:
commit
15e2e5185a
8 changed files with 125 additions and 14 deletions
|
@ -17,6 +17,7 @@ use rustc_span::Span;
|
|||
|
||||
pub trait TraitEngineExt<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
|
||||
fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self>;
|
||||
}
|
||||
|
||||
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
|
||||
|
@ -27,6 +28,14 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
|
|||
Box::new(FulfillmentContext::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
|
||||
if tcx.sess.opts.unstable_opts.chalk {
|
||||
Box::new(ChalkFulfillmentContext::new())
|
||||
} else {
|
||||
Box::new(FulfillmentContext::new_in_snapshot())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used if you want to have pleasant experience when dealing
|
||||
|
@ -41,6 +50,10 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
|||
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx.tcx)) }
|
||||
}
|
||||
|
||||
pub fn new_in_snapshot(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
|
||||
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new_in_snapshot(infcx.tcx)) }
|
||||
}
|
||||
|
||||
pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
|
||||
self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_middle::hir::map;
|
||||
use rustc_middle::ty::{
|
||||
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
|
||||
|
@ -1589,32 +1589,38 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
expected: ty::PolyTraitRef<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
pub(crate) fn build_fn_sig_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let inputs = trait_ref.skip_binder().substs.type_at(1);
|
||||
let sig = match inputs.kind() {
|
||||
ty::Tuple(inputs)
|
||||
if tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() =>
|
||||
if infcx.tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() =>
|
||||
{
|
||||
tcx.mk_fn_sig(
|
||||
infcx.tcx.mk_fn_sig(
|
||||
inputs.iter(),
|
||||
tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
|
||||
infcx.next_ty_var(TypeVariableOrigin {
|
||||
span: DUMMY_SP,
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
}),
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
abi::Abi::Rust,
|
||||
)
|
||||
}
|
||||
_ => tcx.mk_fn_sig(
|
||||
_ => infcx.tcx.mk_fn_sig(
|
||||
std::iter::once(inputs),
|
||||
tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
|
||||
infcx.next_ty_var(TypeVariableOrigin {
|
||||
span: DUMMY_SP,
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
}),
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
abi::Abi::Rust,
|
||||
),
|
||||
};
|
||||
|
||||
tcx.mk_fn_ptr(trait_ref.rebind(sig))
|
||||
infcx.tcx.mk_fn_ptr(trait_ref.rebind(sig))
|
||||
}
|
||||
|
||||
let argument_kind = match expected.skip_binder().self_ty().kind() {
|
||||
|
@ -1634,11 +1640,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
let found_span = found_span.unwrap_or(span);
|
||||
err.span_label(found_span, "found signature defined here");
|
||||
|
||||
let expected = build_fn_sig_ty(self.tcx, expected);
|
||||
let found = build_fn_sig_ty(self.tcx, found);
|
||||
let expected = build_fn_sig_ty(self, expected);
|
||||
let found = build_fn_sig_ty(self, found);
|
||||
|
||||
let (expected_str, found_str) =
|
||||
self.tcx.infer_ctxt().enter(|infcx| infcx.cmp(expected, found));
|
||||
let (expected_str, found_str) = self.cmp(expected, found);
|
||||
|
||||
let signature_kind = format!("{argument_kind} signature");
|
||||
err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue