Make use of ObligationCtxt
This commit is contained in:
@@ -4,6 +4,7 @@ use rustc_data_structures::fx::FxHashMap;
|
|||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
|
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_infer::traits::FulfillmentError;
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::lev_distance::find_best_match_for_name;
|
use rustc_span::lev_distance::find_best_match_for_name;
|
||||||
@@ -226,8 +227,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
&self,
|
&self,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
candidates: &[DefId],
|
candidates: Vec<(DefId, (DefId, DefId))>,
|
||||||
unsatisfied_predicates: Vec<ty::Predicate<'tcx>>,
|
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
@@ -245,16 +246,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if unsatisfied_predicates.is_empty() {
|
if fulfillment_errors.is_empty() {
|
||||||
// FIXME(fmease): Copied from `rustc_hir_typeck::method::probe`. Deduplicate.
|
// FIXME(fmease): Copied from `rustc_hir_typeck::method::probe`. Deduplicate.
|
||||||
|
|
||||||
let limit = if candidates.len() == 5 { 5 } else { 4 };
|
let limit = if candidates.len() == 5 { 5 } else { 4 };
|
||||||
let type_candidates = candidates
|
let type_candidates = candidates
|
||||||
.iter()
|
.iter()
|
||||||
.take(limit)
|
.take(limit)
|
||||||
.map(|candidate| {
|
.map(|&(impl_, _)| format!("- `{}`", tcx.at(span).type_of(impl_).subst_identity()))
|
||||||
format!("- `{}`", tcx.at(span).type_of(candidate).subst_identity())
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
let additional_types = if candidates.len() > limit {
|
let additional_types = if candidates.len() > limit {
|
||||||
@@ -348,8 +347,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
|
|
||||||
// FIXME(fmease): `rustc_hir_typeck::method::suggest` uses a `skip_list` to filter out some bounds.
|
// FIXME(fmease): `rustc_hir_typeck::method::suggest` uses a `skip_list` to filter out some bounds.
|
||||||
// I would do the same here if it didn't mean more code duplication.
|
// I would do the same here if it didn't mean more code duplication.
|
||||||
let mut bounds: Vec<_> = unsatisfied_predicates
|
let mut bounds: Vec<_> = fulfillment_errors
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.map(|error| error.root_obligation.predicate)
|
||||||
.filter_map(format_pred)
|
.filter_map(format_pred)
|
||||||
.map(|(p, _)| format!("`{}`", p))
|
.map(|(p, _)| format!("`{}`", p))
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
|||||||
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
||||||
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
|
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
|
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||||
use rustc_middle::middle::stability::AllowUnstable;
|
use rustc_middle::middle::stability::AllowUnstable;
|
||||||
@@ -42,13 +42,11 @@ use rustc_span::lev_distance::find_best_match_for_name;
|
|||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||||
use rustc_span::{sym, Span, DUMMY_SP};
|
use rustc_span::{sym, Span, DUMMY_SP};
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use rustc_trait_selection::traits;
|
|
||||||
use rustc_trait_selection::traits::error_reporting::{
|
use rustc_trait_selection::traits::error_reporting::{
|
||||||
report_object_safety_error, suggestions::NextTypeParamName,
|
report_object_safety_error, suggestions::NextTypeParamName,
|
||||||
};
|
};
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
|
||||||
use rustc_trait_selection::traits::wf::object_region_bounds;
|
use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||||
use rustc_trait_selection::traits::{astconv_object_safety_violations, NormalizeExt};
|
use rustc_trait_selection::traits::{self, astconv_object_safety_violations, ObligationCtxt};
|
||||||
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
@@ -1948,7 +1946,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
Res::Err
|
Res::Err
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if we have an enum variant.
|
// Check if we have an enum variant or an inherent associated type.
|
||||||
let mut variant_resolution = None;
|
let mut variant_resolution = None;
|
||||||
if let Some(adt_def) = self.probe_adt(span, qself_ty) {
|
if let Some(adt_def) = self.probe_adt(span, qself_ty) {
|
||||||
if adt_def.is_enum() {
|
if adt_def.is_enum() {
|
||||||
@@ -2221,62 +2219,37 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
|
|
||||||
let param_env = tcx.param_env(block.owner.to_def_id());
|
let param_env = tcx.param_env(block.owner.to_def_id());
|
||||||
let cause = ObligationCause::misc(span, block.owner.def_id);
|
let cause = ObligationCause::misc(span, block.owner.def_id);
|
||||||
let mut unsatisfied_predicates = Vec::new();
|
let mut fulfillment_errors = Vec::new();
|
||||||
|
|
||||||
for &(impl_, (assoc_item, def_scope)) in &candidates {
|
for &(impl_, (assoc_item, def_scope)) in &candidates {
|
||||||
let infcx = tcx.infer_ctxt().ignoring_regions().build();
|
let infcx = tcx.infer_ctxt().ignoring_regions().build();
|
||||||
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
|
|
||||||
let impl_ty = tcx.type_of(impl_);
|
let impl_ty = tcx.type_of(impl_);
|
||||||
let impl_substs = self.fresh_item_substs(impl_, &infcx);
|
let impl_substs = self.fresh_item_substs(impl_, &infcx);
|
||||||
let impl_ty = impl_ty.subst(tcx, impl_substs);
|
let impl_ty = impl_ty.subst(tcx, impl_substs);
|
||||||
|
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
|
||||||
let InferOk { value: impl_ty, obligations } =
|
|
||||||
infcx.at(&cause, param_env).normalize(impl_ty);
|
|
||||||
|
|
||||||
// Check that the Self-types can be related.
|
// Check that the Self-types can be related.
|
||||||
let Ok(InferOk { obligations: sub_obligations, value: () }) = infcx
|
// FIXME(fmease): Should we use `eq` here?
|
||||||
.at(&ObligationCause::dummy(), param_env)
|
if ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() {
|
||||||
.define_opaque_types(false)
|
|
||||||
.sup(impl_ty, self_ty)
|
|
||||||
else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Check whether the impl imposes obligations we have to worry about.
|
// Check whether the impl imposes obligations we have to worry about.
|
||||||
let impl_bounds = tcx.predicates_of(impl_);
|
let impl_bounds = tcx.predicates_of(impl_);
|
||||||
let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
|
let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
|
||||||
|
|
||||||
let InferOk { value: impl_bounds, obligations: norm_obligations } =
|
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
|
||||||
infcx.at(&cause, param_env).normalize(impl_bounds);
|
|
||||||
|
|
||||||
let impl_obligations =
|
let impl_obligations =
|
||||||
traits::predicates_for_generics(|_, _| cause.clone(), param_env, impl_bounds);
|
traits::predicates_for_generics(|_, _| cause.clone(), param_env, impl_bounds);
|
||||||
|
|
||||||
let candidate_obligations = impl_obligations
|
ocx.register_obligations(impl_obligations);
|
||||||
.chain(norm_obligations.into_iter())
|
|
||||||
.chain(obligations.iter().cloned());
|
|
||||||
|
|
||||||
let mut matches = true;
|
let errors = ocx.select_where_possible();
|
||||||
|
if !errors.is_empty() {
|
||||||
// Evaluate those obligations to see if they might possibly hold.
|
fulfillment_errors = errors;
|
||||||
for o in candidate_obligations {
|
|
||||||
let o = infcx.resolve_vars_if_possible(o);
|
|
||||||
if !infcx.predicate_may_hold(&o) {
|
|
||||||
matches = false;
|
|
||||||
unsatisfied_predicates.push(o.predicate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate those obligations to see if they might possibly hold.
|
|
||||||
for o in sub_obligations {
|
|
||||||
let o = infcx.resolve_vars_if_possible(o);
|
|
||||||
if !infcx.predicate_may_hold(&o) {
|
|
||||||
matches = false;
|
|
||||||
unsatisfied_predicates.push(o.predicate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !matches {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2286,19 +2259,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
bug!("unreachable: `lookup_inherent_assoc_ty` is only called on ADTs");
|
bug!("unreachable: `lookup_inherent_assoc_ty` is only called on ADTs");
|
||||||
};
|
};
|
||||||
|
|
||||||
let item_substs =
|
let item_substs = self.create_substs_for_associated_item(
|
||||||
self.create_substs_for_associated_item(span, assoc_item, segment, adt_substs);
|
span, assoc_item, segment,
|
||||||
// FIXME(inherent_associated_types): Check if the obligations arising from the
|
// FIXME(fmease, #107468, #105305): Don't use `adt_substs` here but `impl_substs`.
|
||||||
// where-clause & the bounds on the associated type and its parameters hold.
|
adt_substs,
|
||||||
|
);
|
||||||
|
|
||||||
|
// FIXME(fmease, #106722): Check if the bounds on the parameters of the
|
||||||
|
// associated type hold, if any.
|
||||||
let ty = tcx.type_of(assoc_item).subst(tcx, item_substs);
|
let ty = tcx.type_of(assoc_item).subst(tcx, item_substs);
|
||||||
|
|
||||||
|
// FIXME(fmease): Don't return early here! There might be multiple applicable candidates.
|
||||||
return Ok(Some((ty, assoc_item)));
|
return Ok(Some((ty, assoc_item)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(self.complain_about_inherent_assoc_type_not_found(
|
Err(self.complain_about_inherent_assoc_type_not_found(
|
||||||
name,
|
name,
|
||||||
self_ty,
|
self_ty,
|
||||||
&candidates.into_iter().map(|(impl_, _)| impl_).collect::<Vec<_>>(),
|
candidates,
|
||||||
unsatisfied_predicates,
|
fulfillment_errors,
|
||||||
span,
|
span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user