Auto merge of #122317 - compiler-errors:fulfill-method-probe, r=lcnr

Use fulfillment in method probe, not evaluation

This PR reworks method probing to use fulfillment instead of a `for`-loop of `evaluate_predicate` calls, and moves normalization from method candidate assembly into the `consider_probe`, where it's applied to *all* candidates. This last part coincidentally fixes https://github.com/rust-lang/rust/issues/121643#issuecomment-1975371248.

Regarding *why* this large rewrite is done: In general, it's an anti-pattern to do `for o in obligations { evaluate(o); }` because it's not compatible with the way that the new solver emits alias-relate obligations which constrain variables that may show up in other predicates.

r? lcnr
This commit is contained in:
bors 2024-04-23 14:07:05 +00:00
commit cd90d5c035
19 changed files with 322 additions and 457 deletions

View File

@ -889,7 +889,7 @@ fn annotate_alternative_method_deref(
[candidate] => format!(
"the method of the same name on {} `{}`",
match candidate.kind {
probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for",
probe::CandidateKind::InherentImplCandidate(_) => "the inherent impl for",
_ => "trait",
},
self.tcx.def_path_str(candidate.item.container_id(self.tcx))

View File

@ -21,7 +21,7 @@
use rustc_middle::ty::AssocItem;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_session::lint;
use rustc_span::def_id::DefId;
@ -37,7 +37,7 @@
CandidateStep, MethodAutoderefStepsResult,
};
use rustc_trait_selection::traits::query::CanonicalTyGoal;
use rustc_trait_selection::traits::NormalizeExt;
use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCause};
use std::cell::RefCell;
use std::cmp::max;
@ -99,39 +99,6 @@ fn deref(&self) -> &Self::Target {
#[derive(Debug, Clone)]
pub(crate) struct Candidate<'tcx> {
// Candidates are (I'm not quite sure, but they are mostly) basically
// some metadata on top of a `ty::AssocItem` (without args).
//
// However, method probing wants to be able to evaluate the predicates
// for a function with the args applied - for example, if a function
// has `where Self: Sized`, we don't want to consider it unless `Self`
// is actually `Sized`, and similarly, return-type suggestions want
// to consider the "actual" return type.
//
// The way this is handled is through `xform_self_ty`. It contains
// the receiver type of this candidate, but `xform_self_ty`,
// `xform_ret_ty` and `kind` (which contains the predicates) have the
// generic parameters of this candidate instantiated with the *same set*
// of inference variables, which acts as some weird sort of "query".
//
// When we check out a candidate, we require `xform_self_ty` to be
// a subtype of the passed-in self-type, and this equates the type
// variables in the rest of the fields.
//
// For example, if we have this candidate:
// ```
// trait Foo {
// fn foo(&self) where Self: Sized;
// }
// ```
//
// Then `xform_self_ty` will be `&'erased ?X` and `kind` will contain
// the predicate `?X: Sized`, so if we are evaluating `Foo` for a
// the receiver `&T`, we'll do the subtyping which will make `?X`
// get the right value, then when we evaluate the predicate we'll check
// if `T: Sized`.
xform_self_ty: Ty<'tcx>,
xform_ret_ty: Option<Ty<'tcx>>,
pub(crate) item: ty::AssocItem,
pub(crate) kind: CandidateKind<'tcx>,
pub(crate) import_ids: SmallVec<[LocalDefId; 1]>,
@ -139,17 +106,10 @@ pub(crate) struct Candidate<'tcx> {
#[derive(Debug, Clone)]
pub(crate) enum CandidateKind<'tcx> {
InherentImplCandidate(
GenericArgsRef<'tcx>,
// Normalize obligations
Vec<traits::PredicateObligation<'tcx>>,
),
ObjectCandidate,
TraitCandidate(ty::TraitRef<'tcx>),
WhereClauseCandidate(
// Trait
ty::PolyTraitRef<'tcx>,
),
InherentImplCandidate(DefId),
ObjectCandidate(ty::PolyTraitRef<'tcx>),
TraitCandidate(ty::PolyTraitRef<'tcx>),
WhereClauseCandidate(ty::PolyTraitRef<'tcx>),
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@ -743,42 +703,10 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
self.record_static_candidate(CandidateSource::Impl(impl_def_id));
continue;
}
let (impl_ty, impl_args) = self.impl_ty_and_args(impl_def_id);
let impl_ty = impl_ty.instantiate(self.tcx, impl_args);
debug!("impl_ty: {:?}", impl_ty);
// Determine the receiver type that the method itself expects.
let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_args);
debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
// We can't use `FnCtxt::normalize` as it will pollute the
// fcx's fulfillment context after this probe is over.
//
// Note: we only normalize `xform_self_ty` here since the normalization
// of the return type can lead to inference results that prohibit
// valid candidates from being found, see issue #85671
//
// FIXME Postponing the normalization of the return type likely only hides a deeper bug,
// which might be caused by the `param_env` itself. The clauses of the `param_env`
// maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,
// see issue #89650
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let InferOk { value: xform_self_ty, obligations } =
self.fcx.at(&cause, self.param_env).normalize(xform_self_ty);
debug!(
"assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}",
xform_self_ty, xform_ret_ty
);
self.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
kind: InherentImplCandidate(impl_args, obligations),
kind: InherentImplCandidate(impl_def_id),
import_ids: smallvec![],
},
true,
@ -810,26 +738,8 @@ fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) {
// a `&self` method will wind up with an argument type like `&dyn Trait`.
let trait_ref = principal.with_self_ty(self.tcx, self_ty);
self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
if new_trait_ref.has_non_region_bound_vars() {
this.dcx().span_delayed_bug(
this.span,
"tried to select method from HRTB with non-lifetime bound vars",
);
return;
}
let new_trait_ref = this.instantiate_bound_regions_with_erased(new_trait_ref);
let (xform_self_ty, xform_ret_ty) =
this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args);
this.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
kind: ObjectCandidate,
import_ids: smallvec![],
},
Candidate { item, kind: ObjectCandidate(new_trait_ref), import_ids: smallvec![] },
true,
);
});
@ -860,19 +770,8 @@ fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
});
self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
let trait_ref = this.instantiate_binder_with_fresh_vars(
this.span,
infer::BoundRegionConversionTime::FnCall,
poly_trait_ref,
);
let (xform_self_ty, xform_ret_ty) =
this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.args);
this.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
kind: WhereClauseCandidate(poly_trait_ref),
import_ids: smallvec![],
@ -929,27 +828,12 @@ fn assemble_extension_candidates_for_all_traits(&mut self) {
}
}
fn matches_return_type(
&self,
method: ty::AssocItem,
self_ty: Option<Ty<'tcx>>,
expected: Ty<'tcx>,
) -> bool {
fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool {
match method.kind {
ty::AssocKind::Fn => self.probe(|_| {
let args = self.fresh_args_for_item(self.span, method.def_id);
let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
if let Some(self_ty) = self_ty {
if self
.at(&ObligationCause::dummy(), self.param_env)
.sup(DefineOpaqueTypes::No, fty.inputs()[0], self_ty)
.is_err()
{
return false;
}
}
self.can_sub(self.param_env, fty.output(), expected)
}),
_ => false,
@ -978,21 +862,11 @@ fn assemble_extension_candidates_for_trait(
bound_trait_ref.def_id(),
));
} else {
let new_trait_ref = self.instantiate_binder_with_fresh_vars(
self.span,
infer::BoundRegionConversionTime::FnCall,
bound_trait_ref,
);
let (xform_self_ty, xform_ret_ty) =
self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args);
self.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
import_ids: import_ids.clone(),
kind: TraitCandidate(new_trait_ref),
kind: TraitCandidate(bound_trait_ref),
},
false,
);
@ -1011,16 +885,11 @@ fn assemble_extension_candidates_for_trait(
self.record_static_candidate(CandidateSource::Trait(trait_def_id));
continue;
}
let (xform_self_ty, xform_ret_ty) =
self.xform_self_ty(item, trait_ref.self_ty(), trait_args);
self.push_candidate(
Candidate {
xform_self_ty,
xform_ret_ty,
item,
import_ids: import_ids.clone(),
kind: TraitCandidate(trait_ref),
kind: TraitCandidate(ty::Binder::dummy(trait_ref)),
},
false,
);
@ -1040,7 +909,7 @@ fn candidate_method_names(
.filter(|candidate| candidate_filter(&candidate.item))
.filter(|candidate| {
if let Some(return_ty) = self.return_type {
self.matches_return_type(candidate.item, None, return_ty)
self.matches_return_type(candidate.item, return_ty)
} else {
true
}
@ -1450,16 +1319,20 @@ fn select_trait_candidate(
fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource {
match candidate.kind {
InherentImplCandidate(..) => {
InherentImplCandidate(_) => {
CandidateSource::Impl(candidate.item.container_id(self.tcx))
}
ObjectCandidate | WhereClauseCandidate(_) => {
ObjectCandidate(_) | WhereClauseCandidate(_) => {
CandidateSource::Trait(candidate.item.container_id(self.tcx))
}
TraitCandidate(trait_ref) => self.probe(|_| {
let trait_ref =
self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, trait_ref);
let (xform_self_ty, _) =
self.xform_self_ty(candidate.item, trait_ref.self_ty(), trait_ref.args);
let _ = self.at(&ObligationCause::dummy(), self.param_env).sup(
DefineOpaqueTypes::No,
candidate.xform_self_ty,
xform_self_ty,
self_ty,
);
match self.select_trait_candidate(trait_ref) {
@ -1486,54 +1359,46 @@ fn consider_probe(
) -> ProbeResult {
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
self.probe(|_| {
// First check that the self type can be related.
let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup(
DefineOpaqueTypes::No,
probe.xform_self_ty,
self_ty,
) {
Ok(InferOk { obligations, value: () }) => obligations,
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
};
self.probe(|snapshot| {
let outer_universe = self.universe();
let mut result = ProbeResult::Match;
let mut xform_ret_ty = probe.xform_ret_ty;
debug!(?xform_ret_ty);
let cause = &self.misc(self.span);
let ocx = ObligationCtxt::new(self);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let mut trait_predicate = None;
let (mut xform_self_ty, mut xform_ret_ty);
let mut parent_pred = None;
// If so, impls may carry other conditions (e.g., where
// clauses) that must be considered. Make sure that those
// match as well (or at least may match, sometimes we
// don't have enough information to fully evaluate).
match probe.kind {
InherentImplCandidate(args, ref ref_obligations) => {
// `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
// see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
// for why this is necessary
let InferOk {
value: normalized_xform_ret_ty,
obligations: normalization_obligations,
} = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty);
xform_ret_ty = normalized_xform_ret_ty;
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
InherentImplCandidate(impl_def_id) => {
let impl_args = self.fresh_args_for_item(self.span, impl_def_id);
let impl_ty = self.tcx.type_of(impl_def_id).instantiate(self.tcx, impl_args);
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, impl_ty, impl_args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
// FIXME: Make this `ocx.sup` once we define opaques more eagerly.
match self.at(cause, self.param_env).sup(
DefineOpaqueTypes::No,
xform_self_ty,
self_ty,
) {
Ok(infer_ok) => {
ocx.register_infer_ok_obligations(infer_ok);
}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
}
// FIXME: Weirdly, we normalize the ret ty in this candidate, but no other candidates.
xform_ret_ty = ocx.normalize(cause, self.param_env, xform_ret_ty);
// Check whether the impl imposes obligations we have to worry about.
let impl_def_id = probe.item.container_id(self.tcx);
let impl_bounds = self.tcx.predicates_of(impl_def_id);
let impl_bounds = impl_bounds.instantiate(self.tcx, args);
let InferOk { value: impl_bounds, obligations: norm_obligations } =
self.fcx.at(&cause, self.param_env).normalize(impl_bounds);
let impl_bounds =
self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args);
let impl_bounds = ocx.normalize(cause, self.param_env, impl_bounds);
// Convert the bounds into obligations.
let impl_obligations = traits::predicates_for_generics(
ocx.register_obligations(traits::predicates_for_generics(
|idx, span| {
let code = if span.is_dummy() {
traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx)
@ -1549,106 +1414,92 @@ fn consider_probe(
},
self.param_env,
impl_bounds,
);
let candidate_obligations = impl_obligations
.chain(norm_obligations)
.chain(ref_obligations.iter().cloned())
.chain(normalization_obligations);
// Evaluate those obligations to see if they might possibly hold.
for o in candidate_obligations {
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
let parent_o = o.clone();
let implied_obligations = traits::elaborate(self.tcx, vec![o]);
for o in implied_obligations {
let parent = if o == parent_o {
None
} else {
if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
== self.tcx.lang_items().sized_trait()
{
// We don't care to talk about implicit `Sized` bounds.
continue;
}
Some(parent_o.predicate)
};
if !self.predicate_may_hold(&o) {
possibly_unsatisfied_predicates.push((
o.predicate,
parent,
Some(o.cause),
));
}
}
}
}
));
}
ObjectCandidate | WhereClauseCandidate(..) => {
// These have no additional conditions to check.
}
TraitCandidate(trait_ref) => {
TraitCandidate(poly_trait_ref) => {
// Some trait methods are excluded for arrays before 2021.
// (`array.into_iter()` wants a slice iterator for compatibility.)
if let Some(method_name) = self.method_name {
// Some trait methods are excluded for arrays before 2021.
// (`array.into_iter()` wants a slice iterator for compatibility.)
if self_ty.is_array() && !method_name.span.at_least_rust_2021() {
let trait_def = self.tcx.trait_def(trait_ref.def_id);
let trait_def = self.tcx.trait_def(poly_trait_ref.def_id());
if trait_def.skip_array_during_method_dispatch {
return ProbeResult::NoMatch;
}
}
}
let predicate = ty::Binder::dummy(trait_ref).to_predicate(self.tcx);
parent_pred = Some(predicate);
let obligation =
traits::Obligation::new(self.tcx, cause.clone(), self.param_env, predicate);
if !self.predicate_may_hold(&obligation) {
let trait_ref = self.instantiate_binder_with_fresh_vars(
self.span,
infer::FnCall,
poly_trait_ref,
);
let trait_ref = ocx.normalize(cause, self.param_env, trait_ref);
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
// FIXME: Make this `ocx.sup` once we define opaques more eagerly.
match self.at(cause, self.param_env).sup(
DefineOpaqueTypes::No,
xform_self_ty,
self_ty,
) {
Ok(infer_ok) => {
ocx.register_infer_ok_obligations(infer_ok);
}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
}
let obligation = traits::Obligation::new(
self.tcx,
cause.clone(),
self.param_env,
ty::Binder::dummy(trait_ref),
);
// FIXME(-Znext-solver): We only need this hack to deal with fatal
// overflow in the old solver.
if self.infcx.next_trait_solver() || self.infcx.predicate_may_hold(&obligation)
{
ocx.register_obligation(obligation);
} else {
result = ProbeResult::NoMatch;
if self.probe(|_| {
match self.select_trait_candidate(trait_ref) {
Err(_) => return true,
Ok(Some(impl_source))
if !impl_source.borrow_nested_obligations().is_empty() =>
{
for obligation in impl_source.borrow_nested_obligations() {
// Determine exactly which obligation wasn't met, so
// that we can give more context in the error.
if !self.predicate_may_hold(obligation) {
let nested_predicate =
self.resolve_vars_if_possible(obligation.predicate);
let predicate =
self.resolve_vars_if_possible(predicate);
let p = if predicate == nested_predicate {
// Avoid "`MyStruct: Foo` which is required by
// `MyStruct: Foo`" in E0599.
None
} else {
Some(predicate)
};
possibly_unsatisfied_predicates.push((
nested_predicate,
p,
Some(obligation.cause.clone()),
));
}
}
}
_ => {
// Some nested subobligation of this predicate
// failed.
let predicate = self.resolve_vars_if_possible(predicate);
possibly_unsatisfied_predicates.push((predicate, None, None));
if let Ok(Some(candidate)) = self.select_trait_candidate(trait_ref) {
for nested_obligation in candidate.nested_obligations() {
if !self.infcx.predicate_may_hold(&nested_obligation) {
possibly_unsatisfied_predicates.push((
self.resolve_vars_if_possible(nested_obligation.predicate),
Some(self.resolve_vars_if_possible(obligation.predicate)),
Some(nested_obligation.cause),
));
}
}
false
}) {
// This candidate's primary obligation doesn't even
// select - don't bother registering anything in
// `potentially_unsatisfied_predicates`.
}
}
trait_predicate = Some(ty::Binder::dummy(trait_ref).to_predicate(self.tcx));
}
ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => {
let trait_ref = self.instantiate_binder_with_fresh_vars(
self.span,
infer::FnCall,
poly_trait_ref,
);
(xform_self_ty, xform_ret_ty) =
self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args);
xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty);
// FIXME: Make this `ocx.sup` once we define opaques more eagerly.
match self.at(cause, self.param_env).sup(
DefineOpaqueTypes::No,
xform_self_ty,
self_ty,
) {
Ok(infer_ok) => {
ocx.register_infer_ok_obligations(infer_ok);
}
Err(err) => {
debug!("--> cannot relate self-types {:?}", err);
return ProbeResult::NoMatch;
}
}
@ -1656,11 +1507,22 @@ fn consider_probe(
}
// Evaluate those obligations to see if they might possibly hold.
for o in sub_obligations {
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
possibly_unsatisfied_predicates.push((o.predicate, parent_pred, Some(o.cause)));
for error in ocx.select_where_possible() {
result = ProbeResult::NoMatch;
let nested_predicate = self.resolve_vars_if_possible(error.obligation.predicate);
if let Some(trait_predicate) = trait_predicate
&& nested_predicate == self.resolve_vars_if_possible(trait_predicate)
{
// Don't report possibly unsatisfied predicates if the root
// trait obligation from a `TraitCandidate` is unsatisfied.
// That just means the candidate doesn't hold.
} else {
possibly_unsatisfied_predicates.push((
nested_predicate,
Some(self.resolve_vars_if_possible(error.root_obligation.predicate))
.filter(|root_predicate| *root_predicate != nested_predicate),
Some(error.obligation.cause),
));
}
}
@ -1672,36 +1534,37 @@ fn consider_probe(
// We don't normalize the other candidates for perf/backwards-compat reasons...
// but `self.return_type` is only set on the diagnostic-path, so we
// should be okay doing it here.
if !matches!(probe.kind, InherentImplCandidate(..)) {
let InferOk {
value: normalized_xform_ret_ty,
obligations: normalization_obligations,
} = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty);
xform_ret_ty = normalized_xform_ret_ty;
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
// Evaluate those obligations to see if they might possibly hold.
for o in normalization_obligations {
let o = self.resolve_vars_if_possible(o);
if !self.predicate_may_hold(&o) {
result = ProbeResult::NoMatch;
possibly_unsatisfied_predicates.push((
o.predicate,
None,
Some(o.cause),
));
}
}
if !matches!(probe.kind, InherentImplCandidate(_)) {
xform_ret_ty = ocx.normalize(&cause, self.param_env, xform_ret_ty);
}
debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty);
if let ProbeResult::Match = result
&& self
.at(&ObligationCause::dummy(), self.param_env)
.sup(DefineOpaqueTypes::Yes, return_ty, xform_ret_ty)
.is_err()
{
result = ProbeResult::BadReturnType;
match ocx.sup(cause, self.param_env, return_ty, xform_ret_ty) {
Ok(()) => {}
Err(_) => {
result = ProbeResult::BadReturnType;
}
}
// Evaluate those obligations to see if they might possibly hold.
for error in ocx.select_where_possible() {
result = ProbeResult::NoMatch;
possibly_unsatisfied_predicates.push((
error.obligation.predicate,
Some(error.root_obligation.predicate)
.filter(|predicate| *predicate != error.obligation.predicate),
Some(error.root_obligation.cause),
));
}
}
// Previously, method probe used `evaluate_predicate` to determine if a predicate
// was impossible to satisfy. This did a leak check, so we must also do a leak
// check here to prevent backwards-incompatible ambiguity being introduced. See
// `tests/ui/methods/leak-check-disquality.rs` for a simple example of when this
// may happen.
if let Err(_) = self.leak_check(outer_universe, Some(snapshot)) {
result = ProbeResult::NoMatch;
}
result
@ -1894,40 +1757,7 @@ fn xform_method_sig(&self, method: DefId, args: GenericArgsRef<'tcx>) -> ty::FnS
fn_sig.instantiate(self.tcx, args)
};
self.instantiate_bound_regions_with_erased(xform_fn_sig)
}
/// Gets the type of an impl and generate generic parameters with inference vars.
fn impl_ty_and_args(
&self,
impl_def_id: DefId,
) -> (ty::EarlyBinder<Ty<'tcx>>, GenericArgsRef<'tcx>) {
(self.tcx.type_of(impl_def_id), self.fresh_args_for_item(self.span, impl_def_id))
}
/// Replaces late-bound-regions bound by `value` with `'static` using
/// `ty::instantiate_bound_regions_with_erased`.
///
/// This is only a reasonable thing to do during the *probe* phase, not the *confirm* phase, of
/// method matching. It is reasonable during the probe phase because we don't consider region
/// relationships at all. Therefore, we can just replace all the region variables with 'static
/// rather than creating fresh region variables. This is nice for two reasons:
///
/// 1. Because the numbers of the region variables would otherwise be fairly unique to this
/// particular method call, it winds up creating fewer types overall, which helps for memory
/// usage. (Admittedly, this is a rather small effect, though measurable.)
///
/// 2. It makes it easier to deal with higher-ranked trait bounds, because we can replace any
/// late-bound regions with 'static. Otherwise, if we were going to replace late-bound
/// regions with actual region variables as is proper, we'd have to ensure that the same
/// region got replaced with the same variable, which requires a bit more coordination
/// and/or tracking the instantiations and
/// so forth.
fn instantiate_bound_regions_with_erased<T>(&self, value: ty::Binder<'tcx, T>) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
self.tcx.instantiate_bound_regions_with_erased(value)
self.tcx.instantiate_bound_regions_with_erased(xform_fn_sig)
}
/// Determine if the given associated item type is relevant in the current context.
@ -2051,10 +1881,10 @@ fn to_unadjusted_pick(
Pick {
item: self.item,
kind: match self.kind {
InherentImplCandidate(..) => InherentImplPick,
ObjectCandidate => ObjectPick,
InherentImplCandidate(_) => InherentImplPick,
ObjectCandidate(_) => ObjectPick,
TraitCandidate(_) => TraitPick,
WhereClauseCandidate(ref trait_ref) => {
WhereClauseCandidate(trait_ref) => {
// Only trait derived from where-clauses should
// appear here, so they should not contain any
// inference variables or other artifacts. This
@ -2065,7 +1895,7 @@ fn to_unadjusted_pick(
&& !trait_ref.skip_binder().args.has_placeholders()
);
WhereClausePick(*trait_ref)
WhereClausePick(trait_ref)
}
},
import_ids: self.import_ids.clone(),

View File

@ -2,15 +2,13 @@ error[E0599]: the method `insert` exists for struct `HashSet<Value>`, but its tr
--> $DIR/issue-91550.rs:8:8
|
LL | struct Value(u32);
| ------------ doesn't satisfy `Value: Eq`, `Value: Hash` or `Value: PartialEq`
| ------------ doesn't satisfy `Value: Eq` or `Value: Hash`
...
LL | hs.insert(Value(0));
| ^^^^^^
|
= note: the following trait bounds were not satisfied:
`Value: Eq`
`Value: PartialEq`
which is required by `Value: Eq`
`Value: Hash`
help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
|
@ -22,7 +20,7 @@ error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its
--> $DIR/issue-91550.rs:26:9
|
LL | pub struct NoDerives;
| -------------------- doesn't satisfy `NoDerives: Eq` or `NoDerives: PartialEq`
| -------------------- doesn't satisfy `NoDerives: Eq`
LL |
LL | struct Object<T>(T);
| ---------------- method `use_eq` not found for this struct
@ -37,9 +35,6 @@ LL | impl<T: Eq> Object<T> {
| ^^ ---------
| |
| unsatisfied trait bound introduced here
= note: the following trait bounds were not satisfied:
`NoDerives: PartialEq`
which is required by `NoDerives: Eq`
help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
|
LL + #[derive(Eq, PartialEq)]
@ -50,7 +45,7 @@ error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but it
--> $DIR/issue-91550.rs:27:9
|
LL | pub struct NoDerives;
| -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd`
| -------------------- doesn't satisfy `NoDerives: Ord`
LL |
LL | struct Object<T>(T);
| ---------------- method `use_ord` not found for this struct
@ -65,13 +60,6 @@ LL | impl<T: Ord> Object<T> {
| ^^^ ---------
| |
| unsatisfied trait bound introduced here
= note: the following trait bounds were not satisfied:
`NoDerives: PartialOrd`
which is required by `NoDerives: Ord`
`NoDerives: PartialEq`
which is required by `NoDerives: Ord`
`NoDerives: Eq`
which is required by `NoDerives: Ord`
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
LL + #[derive(Eq, Ord, PartialEq, PartialOrd)]
@ -82,7 +70,7 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoD
--> $DIR/issue-91550.rs:28:9
|
LL | pub struct NoDerives;
| -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd`
| -------------------- doesn't satisfy `NoDerives: Ord` or `NoDerives: PartialOrd`
LL |
LL | struct Object<T>(T);
| ---------------- method `use_ord_and_partial_ord` not found for this struct
@ -100,13 +88,6 @@ LL | impl<T: Ord + PartialOrd> Object<T> {
| | |
| | unsatisfied trait bound introduced here
| unsatisfied trait bound introduced here
= note: the following trait bounds were not satisfied:
`NoDerives: PartialEq`
which is required by `NoDerives: Ord`
`NoDerives: Eq`
which is required by `NoDerives: Ord`
`NoDerives: PartialEq`
which is required by `NoDerives: PartialOrd`
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
LL + #[derive(Eq, Ord, PartialEq, PartialOrd)]

View File

@ -29,5 +29,5 @@ fn new() -> P::Pointer<Self> {
fn main() {
let mut list = RcNode::<i32>::new();
//~^ ERROR trait bounds were not satisfied
//~^ ERROR the variant or associated item `new` exists for enum `Node<i32, RcFamily>`, but its trait bounds were not satisfied
}

View File

@ -1,12 +1,17 @@
use std::marker::PhantomData;
fn _alias_check() {
fn a() {
WrongImpl::foo(0i32);
//~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
//~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
//~^ ERROR overflow assigning `_` to `[_]`
}
fn b() {
WrongImpl::<()>::foo(0i32);
//~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied
//~| ERROR trait bounds were not satisfied
}
fn c() {
CorrectImpl::foo(0i32);
}

View File

@ -1,33 +1,11 @@
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
--> $DIR/issue-62742.rs:4:5
error[E0275]: overflow assigning `_` to `[_]`
--> $DIR/issue-62742.rs:4:16
|
LL | WrongImpl::foo(0i32);
| ^^^^^^^^^^^^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
note: required by a bound in `SafeImpl::<T, A>::foo`
--> $DIR/issue-62742.rs:29:20
|
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
| ^^^^^^ required by this bound in `SafeImpl::<T, A>::foo`
LL | pub fn foo(value: A::Value) {}
| --- required by a bound in this associated function
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
--> $DIR/issue-62742.rs:4:5
|
LL | WrongImpl::foo(0i32);
| ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:27:35
|
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl`
| ^^^
error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied
--> $DIR/issue-62742.rs:7:22
--> $DIR/issue-62742.rs:9:22
|
LL | WrongImpl::<()>::foo(0i32);
| ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds
@ -39,20 +17,20 @@ LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ----------------------------------------- function or associated item `foo` not found for this struct
|
note: trait bound `RawImpl<()>: Raw<()>` was not satisfied
--> $DIR/issue-62742.rs:29:20
--> $DIR/issue-62742.rs:34:20
|
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
| ^^^^^^ --------------
| |
| unsatisfied trait bound introduced here
note: the trait `Raw` must be implemented
--> $DIR/issue-62742.rs:13:1
--> $DIR/issue-62742.rs:18:1
|
LL | pub trait Raw<T: ?Sized> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
--> $DIR/issue-62742.rs:7:5
--> $DIR/issue-62742.rs:9:5
|
LL | WrongImpl::<()>::foo(0i32);
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
@ -60,12 +38,12 @@ LL | WrongImpl::<()>::foo(0i32);
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
= help: for that trait implementation, expected `[()]`, found `()`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:27:35
--> $DIR/issue-62742.rs:32:35
|
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl`
error: aborting due to 4 previous errors
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0275, E0277, E0599.
For more information about an error, try `rustc --explain E0275`.

View File

@ -29,5 +29,6 @@ pub fn new(race: R) {}
}
fn main() {
Race::new(|race| race.when()); //~ ERROR overflow assigning `_` to `Option<_>`
Race::new(|race| race.when());
//~^ ERROR overflow assigning `_` to `Option<_>`
}

View File

@ -1,8 +1,8 @@
error[E0275]: overflow assigning `_` to `Option<_>`
--> $DIR/issue-84073.rs:32:22
--> $DIR/issue-84073.rs:32:27
|
LL | Race::new(|race| race.when());
| ^^^^
| ^^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,32 @@
// Tests that using fulfillment in the trait solver means that we detect that a
// method is impossible, leading to no ambiguity.
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
#[derive(Default)]
struct W<A, B>(A, B);
trait Constrain {
type Output;
}
impl Constrain for i32 {
type Output = u32;
}
trait Impossible {}
impl<A, B> W<A, B> where A: Constrain<Output = B>, B: Impossible {
fn method(&self) {}
}
impl W<i32, u32> {
fn method(&self) {}
}
fn main() {
let w: W<i32, _> = W::default();
w.method();
}

View File

@ -0,0 +1,26 @@
// Tests that using fulfillment in the trait solver means that we detect that a
// method is impossible, leading to no ambiguity.
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
struct W<T, U>(Option<T>, Option<U>);
impl<'a> W<fn(&'a ()), u32> {
fn method(&self) {}
}
trait Leak {}
impl<T: Fn(&())> Leak for T {}
impl<T: Leak> W<T, i32> {
fn method(&self) {}
}
fn test<'a>() {
let x: W<fn(&'a ()), _> = W(None, None);
x.method();
}
fn main() {}

View File

@ -0,0 +1,24 @@
//@ check-pass
// Test that we use `sup` not `eq` during method probe, since this has an effect
// on the leak check. This is (conceptually) minimized from a crater run for
// `wrend 0.3.6`.
use std::ops::Deref;
struct A;
impl Deref for A {
type Target = B<dyn Fn(&())>;
fn deref(&self) -> &<Self as Deref>::Target { todo!() }
}
struct B<T: ?Sized>(T);
impl<T> B<dyn Fn(T)> {
fn method(&self) {}
}
fn main() {
A.method();
}

View File

@ -6,8 +6,6 @@ LL | this.is_subset(other)
|
= note: the following trait bounds were not satisfied:
`T: Eq`
`T: PartialEq`
which is required by `T: Eq`
`T: Hash`
help: consider restricting the type parameters to satisfy the trait bounds
|

View File

@ -18,8 +18,10 @@ fn make_g() -> Self::G {
}
}
// FIXME(@compiler-errors): This error message is less than helpful.
fn g() {
let x = <fn (&())>::make_g(); //~ ERROR the function
let x = <fn (&())>::make_g();
//~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope
}
fn main() {}

View File

@ -1,11 +1,9 @@
error[E0599]: the function or associated item `make_g` exists for fn pointer `fn(&())`, but its trait bounds were not satisfied
--> $DIR/issue-57362-2.rs:22:25
error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope
--> $DIR/issue-57362-2.rs:23:25
|
LL | let x = <fn (&())>::make_g();
| ^^^^^^ function or associated item cannot be called on `fn(&())` due to unsatisfied trait bounds
| ^^^^^^ function or associated item not found in `fn(&())`
|
= note: the following trait bounds were not satisfied:
`for<'a> fn(&'a ()): X`
= help: items from traits can only be used if the trait is implemented and in scope
note: `X` defines an item `make_g`, perhaps you need to implement it
--> $DIR/issue-57362-2.rs:8:1

View File

@ -28,7 +28,8 @@ fn make_f() -> Self::F {
}
fn higher_ranked_region_has_lost_its_binder() {
let x = <fn (&())>::make_g(); //~ ERROR the function
let x = <fn (&())>::make_g();
//~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope
}
fn magical() {

View File

@ -1,11 +1,9 @@
error[E0599]: the function or associated item `make_g` exists for fn pointer `fn(&())`, but its trait bounds were not satisfied
error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope
--> $DIR/issue-57642-higher-ranked-subtype.rs:31:25
|
LL | let x = <fn (&())>::make_g();
| ^^^^^^ function or associated item cannot be called on `fn(&())` due to unsatisfied trait bounds
| ^^^^^^ function or associated item not found in `fn(&())`
|
= note: the following trait bounds were not satisfied:
`for<'a> fn(&'a ()): X`
= help: items from traits can only be used if the trait is implemented and in scope
note: `X` defines an item `make_g`, perhaps you need to implement it
--> $DIR/issue-57642-higher-ranked-subtype.rs:4:1
@ -14,7 +12,7 @@ LL | trait X {
| ^^^^^^^
error[E0599]: no function or associated item named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope
--> $DIR/issue-57642-higher-ranked-subtype.rs:35:25
--> $DIR/issue-57642-higher-ranked-subtype.rs:36:25
|
LL | let x = <fn (&())>::make_f();
| ^^^^^^ function or associated item not found in `fn(&())`

View File

@ -74,22 +74,30 @@ LL | struct Struct {
error[E0599]: the method `test` exists for struct `Foo<Vec<Enum>, Instant>`, but its trait bounds were not satisfied
--> $DIR/derive-trait-for-method-call.rs:40:15
|
LL | enum Enum {
| --------- doesn't satisfy `Enum: Clone`
...
LL | struct Foo<X, Y> (X, Y);
| ---------------- method `test` not found for this struct
...
LL | let y = x.test();
| ^^^^ method cannot be called on `Foo<Vec<Enum>, Instant>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`Instant: Default`
`Vec<Enum>: Clone`
--> $DIR/derive-trait-for-method-call.rs:20:9
note: trait bound `Instant: Default` was not satisfied
--> $DIR/derive-trait-for-method-call.rs:20:40
|
LL | impl<X: Clone + Default + , Y: Clone + Default> Foo<X, Y> {
| ^^^^^ ^^^^^^^ ---------
| | |
| | unsatisfied trait bound introduced here
| unsatisfied trait bound introduced here
| ^^^^^^^ ---------
| |
| unsatisfied trait bound introduced here
= note: the following trait bounds were not satisfied:
`Enum: Clone`
which is required by `Vec<Enum>: Clone`
help: consider annotating `Enum` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | enum Enum {
|
error: aborting due to 3 previous errors

View File

@ -12,13 +12,6 @@ note: trait bound `(): Iterator` was not satisfied
|
LL | trait IteratorAlias = Iterator;
| ------------- ^^^^^^^^ unsatisfied trait bound introduced here
note: trait bound `(): IteratorAlias` was not satisfied
--> $DIR/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs:9:9
|
LL | impl<I: IteratorAlias> Foo<I> {
| ^^^^^^^^^^^^^ ------
| |
| unsatisfied trait bound introduced here
error: aborting due to 1 previous error

View File

@ -2,7 +2,10 @@ error[E0599]: the method `check` exists for struct `Client<()>`, but its trait b
--> $DIR/track-obligations.rs:83:16
|
LL | struct ALayer<C>(C);
| ---------------- doesn't satisfy `<_ as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service` or `ALayer<()>: ParticularServiceLayer<()>`
| ---------------- doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
...
LL | struct AService;
| --------------- doesn't satisfy `<AService as Service<Req>>::Response = Res`
...
LL | struct Client<C>(C);
| ---------------- method `check` not found for this struct
@ -10,27 +13,14 @@ LL | struct Client<C>(C);
LL | Client(()).check();
| ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
|
note: trait bound `<ALayer<()> as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service` was not satisfied
--> $DIR/track-obligations.rs:35:14
note: trait bound `<AService as Service<Req>>::Response = Res` was not satisfied
--> $DIR/track-obligations.rs:24:21
|
LL | pub trait ParticularServiceLayer<C>:
| ----------------------
LL | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied
--> $DIR/track-obligations.rs:71:16
|
LL | impl<C> Client<C>
| ---------
LL | impl<T> ParticularService for T
| ----------------- -
LL | where
LL | ALayer<C>: ParticularServiceLayer<C>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
note: the trait `ParticularServiceLayer` must be implemented
--> $DIR/track-obligations.rs:34:1
|
LL | / pub trait ParticularServiceLayer<C>:
LL | | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
| |____________________________________________________________________^
LL | T: Service<Req, Response = Res>,
| ^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
--> $DIR/track-obligations.rs:87:11