1
Fork 0

eagerly prove WF when resolving fully qualified paths

This commit is contained in:
lcnr 2025-02-12 15:52:02 +01:00
parent c241e14650
commit 81c6d5ec9b
2 changed files with 47 additions and 25 deletions

View file

@ -798,13 +798,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
}
};
self.register_wf_obligation(
ty.raw.into(),
qself.span,
ObligationCauseCode::WellFormed(None),
);
self.select_obligations_where_possible(|_| {});
if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
{
self.register_wf_obligation(
ty.raw.into(),
qself.span,
ObligationCauseCode::WellFormed(None),
);
// Return directly on cache hit. This is useful to avoid doubly reporting
// errors with default match binding modes. See #44614.
let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id));
@ -824,18 +827,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let trait_missing_method =
matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait();
// If we have a path like `MyTrait::missing_method`, then don't register
// a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise,
// register a WF obligation so that we can detect any additional
// errors in the self type.
if !trait_missing_method {
self.register_wf_obligation(
ty.raw.into(),
qself.span,
ObligationCauseCode::WellFormed(None),
);
}
if item_name.name != kw::Empty {
self.report_method_error(
hir_id,
@ -849,14 +840,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
result
});
if result.is_ok() {
self.register_wf_obligation(
ty.raw.into(),
qself.span,
ObligationCauseCode::WellFormed(None),
);
}
// Write back the new resolution.
self.write_resolution(hir_id, result);
(

View file

@ -0,0 +1,39 @@
//@ compile-flags: -Znext-solver
//@ check-pass
// A regression test for trait-system-refactor-initiative#161
trait Constrain<T> {
type Assoc;
}
impl<T> Constrain<T> for () {
type Assoc = ();
}
struct Foo<T, U = <() as Constrain<T>>::Assoc>(T, U);
impl<T: Copy> Foo<T> {
fn foo() {}
}
struct B;
impl Foo<B> {
fn foo() {}
}
type Alias<T> = Foo<T>;
fn via_guidance<T: Copy>()
where
(): Constrain<T>,
{
// Method selection on `Foo<?t, <() as Constrain<?t>>::Assoc>` is ambiguous.
// only by unnecessarily constraining `?t` to `T` when proving `(): Constrain<?t>`
// are we able to select the first impl.
//
// This happens in the old solver when normalizing `Alias<?t>`. The new solver doesn't try
// to eagerly normalize `<() as Constrain<?t>>::Assoc` so we instead always prove that the
// self type is well-formed before method lookup.
Alias::foo();
}
fn main() {
via_guidance::<()>();
}