Skip to content

Commit 89aefb9

Browse files
committed
Auto merge of #127172 - compiler-errors:full-can_eq-everywhere, r=lcnr
Make `can_eq` process obligations (almost) everywhere Move `can_eq` to an extension trait on `InferCtxt` in `rustc_trait_selection`, and change it so that it processes obligations. This should strengthen it to be more accurate in some cases, but is most important for the new trait solver which delays relating aliases to `AliasRelate` goals. Without this, we always basically just return true when passing aliases to `can_eq`, which can lead to weird errors, for example #127149. I'm not actually certain if we should *have* `can_eq` be called on the good path. In cases where we need `can_eq`, we probably should just be using a regular probe. Fixes #127149 r? lcnr
2 parents 20ae37c + 465e7d5 commit 89aefb9

30 files changed

+133
-154
lines changed

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_middle::ty::{
2121
use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
2222
use rustc_middle::{bug, span_bug};
2323
use rustc_span::Span;
24+
use rustc_trait_selection::infer::InferCtxtExt;
2425
use rustc_trait_selection::regions::InferCtxtRegionExt;
2526
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
2627
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+42-49
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _
3939
use rustc_trait_selection::traits::{
4040
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
4141
};
42+
use rustc_type_ir::solve::NoSolution;
4243
use rustc_type_ir::TypeFlags;
4344

4445
use std::cell::LazyCell;
@@ -1712,13 +1713,12 @@ fn receiver_is_valid<'tcx>(
17121713
let cause =
17131714
ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver);
17141715

1715-
let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty);
1716-
1717-
// `self: Self` is always valid.
1718-
if can_eq_self(receiver_ty) {
1719-
if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) {
1720-
infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
1721-
}
1716+
// Special case `receiver == self_ty`, which doesn't necessarily require the `Receiver` lang item.
1717+
if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
1718+
let ocx = ObligationCtxt::new(wfcx.infcx);
1719+
ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?;
1720+
if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
1721+
}) {
17221722
return true;
17231723
}
17241724

@@ -1729,58 +1729,51 @@ fn receiver_is_valid<'tcx>(
17291729
autoderef = autoderef.include_raw_pointers();
17301730
}
17311731

1732-
// The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it.
1733-
autoderef.next();
1734-
17351732
let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span));
17361733

17371734
// Keep dereferencing `receiver_ty` until we get to `self_ty`.
1738-
loop {
1739-
if let Some((potential_self_ty, _)) = autoderef.next() {
1740-
debug!(
1741-
"receiver_is_valid: potential self type `{:?}` to match `{:?}`",
1742-
potential_self_ty, self_ty
1743-
);
1744-
1745-
if can_eq_self(potential_self_ty) {
1746-
wfcx.register_obligations(autoderef.into_obligations());
1735+
while let Some((potential_self_ty, _)) = autoderef.next() {
1736+
debug!(
1737+
"receiver_is_valid: potential self type `{:?}` to match `{:?}`",
1738+
potential_self_ty, self_ty
1739+
);
17471740

1748-
if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) {
1749-
infcx
1750-
.err_ctxt()
1751-
.report_mismatched_types(&cause, self_ty, potential_self_ty, err)
1752-
.emit();
1753-
}
1741+
// Check if the self type unifies. If it does, then commit the result
1742+
// since it may have region side-effects.
1743+
if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
1744+
let ocx = ObligationCtxt::new(wfcx.infcx);
1745+
ocx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty)?;
1746+
if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
1747+
}) {
1748+
wfcx.register_obligations(autoderef.into_obligations());
1749+
return true;
1750+
}
17541751

1752+
// Without `feature(arbitrary_self_types)`, we require that each step in the
1753+
// deref chain implement `receiver`.
1754+
if !arbitrary_self_types_enabled {
1755+
if !receiver_is_implemented(
1756+
wfcx,
1757+
receiver_trait_def_id,
1758+
cause.clone(),
1759+
potential_self_ty,
1760+
) {
1761+
// We cannot proceed.
17551762
break;
1756-
} else {
1757-
// Without `feature(arbitrary_self_types)`, we require that each step in the
1758-
// deref chain implement `receiver`
1759-
if !arbitrary_self_types_enabled
1760-
&& !receiver_is_implemented(
1761-
wfcx,
1762-
receiver_trait_def_id,
1763-
cause.clone(),
1764-
potential_self_ty,
1765-
)
1766-
{
1767-
return false;
1768-
}
17691763
}
1770-
} else {
1771-
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
1772-
return false;
1773-
}
1774-
}
17751764

1776-
// Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`.
1777-
if !arbitrary_self_types_enabled
1778-
&& !receiver_is_implemented(wfcx, receiver_trait_def_id, cause.clone(), receiver_ty)
1779-
{
1780-
return false;
1765+
// Register the bound, in case it has any region side-effects.
1766+
wfcx.register_bound(
1767+
cause.clone(),
1768+
wfcx.param_env,
1769+
potential_self_ty,
1770+
receiver_trait_def_id,
1771+
);
1772+
}
17811773
}
17821774

1783-
true
1775+
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
1776+
false
17841777
}
17851778

17861779
fn receiver_is_implemented<'tcx>(

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
4949
use rustc_span::symbol::{kw, Ident, Symbol};
5050
use rustc_span::{sym, Span, DUMMY_SP};
5151
use rustc_target::spec::abi;
52+
use rustc_trait_selection::infer::InferCtxtExt;
5253
use rustc_trait_selection::traits::wf::object_region_bounds;
5354
use rustc_trait_selection::traits::{self, ObligationCtxt};
5455

compiler/rustc_hir_typeck/src/demand.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
1313
use rustc_middle::ty::{self, AssocItem, Ty, TypeFoldable, TypeVisitableExt};
1414
use rustc_span::symbol::sym;
1515
use rustc_span::{Span, DUMMY_SP};
16+
use rustc_trait_selection::infer::InferCtxtExt;
1617
use rustc_trait_selection::traits::ObligationCause;
1718

1819
use super::method::probe;

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use rustc_middle::{bug, span_bug};
4040
use rustc_session::Session;
4141
use rustc_span::symbol::{kw, Ident};
4242
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
43+
use rustc_trait_selection::infer::InferCtxtExt;
4344
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
4445

4546
use std::iter;

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2582,7 +2582,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25822582
}
25832583
}
25842584
(hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr), _, &ty::Ref(_, checked, _))
2585-
if self.can_sub(self.param_env, checked, expected) =>
2585+
if self.can_eq(self.param_env, checked, expected) =>
25862586
{
25872587
let make_sugg = |start: Span, end: BytePos| {
25882588
// skip `(` for tuples such as `(c) = (&123)`.

compiler/rustc_hir_typeck/src/method/probe.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use rustc_span::edit_distance::{
3333
};
3434
use rustc_span::symbol::sym;
3535
use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
36+
use rustc_trait_selection::infer::InferCtxtExt as _;
3637
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
3738
use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
3839
use rustc_trait_selection::traits::query::method_autoderef::{
@@ -857,7 +858,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
857858
let args = self.fresh_args_for_item(self.span, method.def_id);
858859
let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
859860
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
860-
self.can_sub(self.param_env, fty.output(), expected)
861+
self.can_eq(self.param_env, fty.output(), expected)
861862
}),
862863
_ => false,
863864
}

compiler/rustc_hir_typeck/src/pat.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_span::source_map::Spanned;
1919
use rustc_span::symbol::{kw, sym, Ident};
2020
use rustc_span::{BytePos, Span, DUMMY_SP};
2121
use rustc_target::abi::FieldIdx;
22+
use rustc_trait_selection::infer::InferCtxtExt;
2223
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
2324
use ty::VariantDef;
2425

compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,7 @@ fn foo(&self) -> Self::T { String::new() }
820820
tcx.defaultness(item.id.owner_id)
821821
{
822822
let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
823-
if self.infcx.can_eq(param_env, assoc_ty, found) {
823+
if self.infcx.can_eq_shallow(param_env, assoc_ty, found) {
824824
diag.span_label(
825825
item.span,
826826
"associated type defaults can't be assumed inside the \
@@ -843,7 +843,7 @@ fn foo(&self) -> Self::T { String::new() }
843843
let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
844844
if let hir::Defaultness::Default { has_value: true } =
845845
tcx.defaultness(item.id.owner_id)
846-
&& self.infcx.can_eq(param_env, assoc_ty, found)
846+
&& self.infcx.can_eq_shallow(param_env, assoc_ty, found)
847847
{
848848
diag.span_label(
849849
item.span,

compiler/rustc_infer/src/infer/mod.rs

+3-13
Original file line numberDiff line numberDiff line change
@@ -768,19 +768,9 @@ impl<'tcx> InferCtxt<'tcx> {
768768
.collect()
769769
}
770770

771-
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool
772-
where
773-
T: at::ToTrace<'tcx>,
774-
{
775-
let origin = &ObligationCause::dummy();
776-
self.probe(|_| {
777-
// We're only answering whether there could be a subtyping relation, and with
778-
// opaque types, "there could be one", via registering a hidden type.
779-
self.at(origin, param_env).sub(DefineOpaqueTypes::Yes, expected, actual).is_ok()
780-
})
781-
}
782-
783-
pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
771+
// FIXME(-Znext-solver): Get rid of this method, it's never correct. Either that,
772+
// or we need to process the obligations.
773+
pub fn can_eq_shallow<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
784774
where
785775
T: at::ToTrace<'tcx>,
786776
{

compiler/rustc_trait_selection/src/infer.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::infer::at::ToTrace;
12
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
23
use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt, SelectionContext};
34

@@ -17,6 +18,16 @@ pub use rustc_infer::infer::*;
1718

1819
#[extension(pub trait InferCtxtExt<'tcx>)]
1920
impl<'tcx> InferCtxt<'tcx> {
21+
fn can_eq<T: ToTrace<'tcx>>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool {
22+
self.probe(|_| {
23+
let ocx = ObligationCtxt::new(self);
24+
let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, a, b) else {
25+
return false;
26+
};
27+
ocx.select_where_possible().is_empty()
28+
})
29+
}
30+
2031
fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
2132
let ty = self.resolve_vars_if_possible(ty);
2233

compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
use super::{ObligationCauseCode, PredicateObligation};
2+
use crate::errors::{
3+
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
4+
};
25
use crate::infer::error_reporting::TypeErrCtxt;
6+
use crate::infer::InferCtxtExt;
7+
use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
38
use rustc_ast::AttrArgs;
49
use rustc_ast::AttrArgsEq;
510
use rustc_ast::AttrKind;
@@ -21,12 +26,6 @@ use rustc_span::Span;
2126
use std::iter;
2227
use std::path::PathBuf;
2328

24-
use crate::errors::{
25-
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
26-
};
27-
28-
use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
29-
3029
/// The symbols which are always allowed in a format string
3130
static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
3231
kw::SelfUpper,

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
10731073
// mismatched, then we have a totally different error to report.
10741074
if self.enter_forall(found_args, |found_args| {
10751075
self.enter_forall(expected_args, |expected_args| {
1076-
!self.can_sub(obligation.param_env, expected_args, found_args)
1076+
!self.can_eq(obligation.param_env, expected_args, found_args)
10771077
})
10781078
}) {
10791079
return None;

compiler/rustc_trait_selection/src/traits/select/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use super::{
1818
TraitQueryMode,
1919
};
2020

21-
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
21+
use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
2222
use crate::solve::InferCtxtSelectExt as _;
2323
use crate::traits::error_reporting::TypeErrCtxtExt;
2424
use crate::traits::normalize::normalize_with_depth;

tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0277]: the trait bound `i32: Baz<Self>` is not satisfied
1+
error[E0277]: the trait bound `<Self as Foo>::Bar<()>: Eq<i32>` is not satisfied
22
--> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30
33
|
44
LL | type Bar<T>: Baz<Self> = i32;

tests/ui/impl-trait/nested_impl_trait.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ fn fine(x: impl Into<u32>) -> impl Into<u32> { x }
55

66
fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
77
//~^ ERROR nested `impl Trait` is not allowed
8-
//~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
8+
//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
99

1010
fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
1111
//~^ ERROR nested `impl Trait` is not allowed
@@ -18,7 +18,7 @@ struct X;
1818
impl X {
1919
fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
2020
//~^ ERROR nested `impl Trait` is not allowed
21-
//~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
21+
//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
2222
}
2323

2424
fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {

tests/ui/impl-trait/nested_impl_trait.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
4242
|
4343
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
4444

45-
error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
45+
error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
4646
--> $DIR/nested_impl_trait.rs:6:46
4747
|
4848
LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
@@ -51,7 +51,7 @@ LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
5151
= help: the trait `Into<U>` is implemented for `T`
5252
= note: required for `impl Into<u32>` to implement `Into<impl Debug>`
5353

54-
error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
54+
error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
5555
--> $DIR/nested_impl_trait.rs:19:34
5656
|
5757
LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }

tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr

-12
This file was deleted.

tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr

-12
This file was deleted.

tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//@ revisions: nn ny yn yy
2-
//@ known-bug: #110395
32
//@ compile-flags: -Znext-solver
3+
//@ check-pass
4+
45
#![allow(incomplete_features)]
56
#![feature(const_trait_impl, effects, associated_type_defaults, const_mut_refs)]
67

tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr

-12
This file was deleted.

tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr

-12
This file was deleted.

0 commit comments

Comments
 (0)