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
|
@ -78,6 +78,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
err_count_on_creation: self.err_count_on_creation,
|
||||
in_snapshot: self.in_snapshot.clone(),
|
||||
universe: self.universe.clone(),
|
||||
normalize_fn_sig_for_diagnostic: self
|
||||
.normalize_fn_sig_for_diagnostic
|
||||
.as_ref()
|
||||
.map(|f| f.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -961,12 +961,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn normalize_fn_sig_for_diagnostic(&self, sig: ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> {
|
||||
if let Some(normalize) = &self.normalize_fn_sig_for_diagnostic {
|
||||
normalize(self, sig)
|
||||
} else {
|
||||
sig
|
||||
}
|
||||
}
|
||||
|
||||
/// Given two `fn` signatures highlight only sub-parts that are different.
|
||||
fn cmp_fn_sig(
|
||||
&self,
|
||||
sig1: &ty::PolyFnSig<'tcx>,
|
||||
sig2: &ty::PolyFnSig<'tcx>,
|
||||
) -> (DiagnosticStyledString, DiagnosticStyledString) {
|
||||
let sig1 = &self.normalize_fn_sig_for_diagnostic(*sig1);
|
||||
let sig2 = &self.normalize_fn_sig_for_diagnostic(*sig2);
|
||||
|
||||
let get_lifetimes = |sig| {
|
||||
use rustc_hir::def::Namespace;
|
||||
let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
|
||||
|
|
|
@ -337,6 +337,9 @@ pub struct InferCtxt<'a, 'tcx> {
|
|||
/// when we enter into a higher-ranked (`for<..>`) type or trait
|
||||
/// bound.
|
||||
universe: Cell<ty::UniverseIndex>,
|
||||
|
||||
normalize_fn_sig_for_diagnostic:
|
||||
Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
|
||||
}
|
||||
|
||||
/// See the `error_reporting` module for more details.
|
||||
|
@ -540,6 +543,8 @@ pub struct InferCtxtBuilder<'tcx> {
|
|||
defining_use_anchor: DefiningAnchor,
|
||||
considering_regions: bool,
|
||||
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
|
||||
normalize_fn_sig_for_diagnostic:
|
||||
Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
|
||||
}
|
||||
|
||||
pub trait TyCtxtInferExt<'tcx> {
|
||||
|
@ -553,6 +558,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
|
|||
defining_use_anchor: DefiningAnchor::Error,
|
||||
considering_regions: true,
|
||||
fresh_typeck_results: None,
|
||||
normalize_fn_sig_for_diagnostic: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -582,6 +588,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_normalize_fn_sig_for_diagnostic(
|
||||
mut self,
|
||||
fun: Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>,
|
||||
) -> Self {
|
||||
self.normalize_fn_sig_for_diagnostic = Some(fun);
|
||||
self
|
||||
}
|
||||
|
||||
/// Given a canonical value `C` as a starting point, create an
|
||||
/// inference context that contains each of the bound values
|
||||
/// within instantiated as a fresh variable. The `f` closure is
|
||||
|
@ -611,6 +625,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
defining_use_anchor,
|
||||
considering_regions,
|
||||
ref fresh_typeck_results,
|
||||
ref normalize_fn_sig_for_diagnostic,
|
||||
} = *self;
|
||||
let in_progress_typeck_results = fresh_typeck_results.as_ref();
|
||||
f(InferCtxt {
|
||||
|
@ -629,6 +644,9 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
in_snapshot: Cell::new(false),
|
||||
skip_leak_check: Cell::new(false),
|
||||
universe: Cell::new(ty::UniverseIndex::ROOT),
|
||||
normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic
|
||||
.as_ref()
|
||||
.map(|f| f.clone()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue