Lazily resolve type-alias-impl-trait defining uses
by using an opaque type obligation to bubble up comparisons between opaque types and other types Also uses proper obligation causes so that the body id works, because out of some reason nll uses body ids for logic instead of just diagnostics.
This commit is contained in:
parent
8d2b598459
commit
0f6e06b7c0
284 changed files with 2646 additions and 2097 deletions
|
@ -359,6 +359,7 @@ crate fn required_region_bounds<'tcx>(
|
|||
| ty::PredicateKind::RegionOutlives(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
|
||||
// Search for a bound of the form `erased_self_ty
|
||||
|
|
|
@ -853,6 +853,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -775,6 +775,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
span,
|
||||
"TypeWellFormedFromEnv predicate should only exist in the environment"
|
||||
),
|
||||
|
||||
ty::PredicateKind::OpaqueType(..) => {
|
||||
todo!("{:#?}", obligation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -397,6 +397,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(..) => {
|
||||
todo!("{:#?}", obligation);
|
||||
}
|
||||
},
|
||||
Some(pred) => match pred {
|
||||
ty::PredicateKind::Trait(data) => {
|
||||
|
@ -642,6 +645,20 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(a, b) => {
|
||||
match self.selcx.infcx().handle_opaque_type(
|
||||
a,
|
||||
b,
|
||||
&obligation.cause,
|
||||
obligation.param_env,
|
||||
) {
|
||||
Ok(value) => ProcessResult::Changed(mk_pending(value)),
|
||||
Err(err) => ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
|
||||
ExpectedFound::new(true, a, b),
|
||||
err,
|
||||
)),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -313,6 +313,7 @@ fn predicate_references_self<'tcx>(
|
|||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
}
|
||||
|
@ -347,6 +348,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|||
| ty::PredicateKind::TypeOutlives(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
|
||||
}
|
||||
})
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::infer::{InferCtxt, InferOk};
|
|||
use crate::traits::engine::TraitEngineExt as _;
|
||||
use crate::traits::query::type_op::TypeOpOutput;
|
||||
use crate::traits::query::Fallible;
|
||||
use crate::traits::{ObligationCause, TraitEngine};
|
||||
use crate::traits::TraitEngine;
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
|
||||
|
@ -60,7 +60,6 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
|
|||
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
|
||||
) -> Fallible<TypeOpOutput<'tcx, Op>> {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||
|
||||
// During NLL, we expect that nobody will register region
|
||||
// obligations **except** as part of a custom type op (and, at the
|
||||
|
@ -75,7 +74,6 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
|
|||
);
|
||||
|
||||
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
|
||||
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
|
||||
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
||||
let errors = fulfill_cx.select_all_or_error(infcx);
|
||||
if !errors.is_empty() {
|
||||
|
|
|
@ -254,6 +254,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
if obligation.predicate.skip_binder().self_ty().is_ty_var() {
|
||||
debug!(ty = ?obligation.predicate.skip_binder().self_ty(), "ambiguous inference var or opaque type");
|
||||
// Self is a type variable (e.g., `_: AsRef<str>`).
|
||||
//
|
||||
// This is somewhat problematic, as the current scheme can't really
|
||||
|
|
|
@ -37,6 +37,7 @@ use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
|||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
|
||||
|
@ -697,6 +698,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for chalk")
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(a, b) => {
|
||||
match self.infcx().handle_opaque_type(
|
||||
a,
|
||||
b,
|
||||
&obligation.cause,
|
||||
obligation.param_env,
|
||||
) {
|
||||
Ok(obligations) => {
|
||||
self.evaluate_predicates_recursively(previous_stack, obligations)
|
||||
}
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1337,6 +1351,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")]
|
||||
fn insert_candidate_cache(
|
||||
&mut self,
|
||||
mut param_env: ty::ParamEnv<'tcx>,
|
||||
|
@ -1377,6 +1392,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// a projection, look at the bounds of `T::Bar`, see if we can find a
|
||||
/// `Baz` bound. We return indexes into the list returned by
|
||||
/// `tcx.item_bounds` for any applicable bounds.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn match_projection_obligation_against_definition_bounds(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
|
@ -1384,10 +1400,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
|
||||
let placeholder_trait_predicate =
|
||||
self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
|
||||
debug!(
|
||||
?placeholder_trait_predicate,
|
||||
"match_projection_obligation_against_definition_bounds"
|
||||
);
|
||||
debug!(?placeholder_trait_predicate);
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
|
||||
|
@ -1438,7 +1451,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds");
|
||||
debug!(?matching_bounds);
|
||||
matching_bounds
|
||||
}
|
||||
|
||||
|
@ -1468,6 +1481,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
});
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
|
||||
.map(|InferOk { obligations: _, value: () }| {
|
||||
// This method is called within a probe, so we can't have
|
||||
|
@ -1523,6 +1537,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(obligation.predicate, infer_projection)
|
||||
.map_or(false, |InferOk { obligations, value: () }| {
|
||||
self.evaluate_predicates_recursively(
|
||||
|
@ -2081,11 +2096,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
match self.match_impl(impl_def_id, obligation) {
|
||||
Ok(substs) => substs,
|
||||
Err(()) => {
|
||||
bug!(
|
||||
"Impl {:?} was matchable against {:?} but now is not",
|
||||
impl_def_id,
|
||||
obligation
|
||||
self.infcx.tcx.sess.delay_span_bug(
|
||||
obligation.cause.span,
|
||||
&format!(
|
||||
"Impl {:?} was matchable against {:?} but now is not",
|
||||
impl_def_id, obligation
|
||||
),
|
||||
);
|
||||
let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
|
||||
let err = self.tcx().ty_error();
|
||||
let value = value.fold_with(&mut BottomUpFolder {
|
||||
tcx: self.tcx(),
|
||||
ty_op: |_| err,
|
||||
lt_op: |l| l,
|
||||
ct_op: |c| c,
|
||||
});
|
||||
Normalized { value, obligations: vec![] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2222,6 +2248,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
// We don't want opaque types to just randomly match everything,
|
||||
// they should be opaque, even in their defining scope.
|
||||
.define_opaque_types(false)
|
||||
.sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.map_err(|_| ())
|
||||
|
|
|
@ -146,6 +146,10 @@ pub fn predicate_obligations<'a, 'tcx>(
|
|||
wf.compute(c1.into());
|
||||
wf.compute(c2.into());
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(opaque, ty) => {
|
||||
wf.compute(opaque.into());
|
||||
wf.compute(ty.into());
|
||||
}
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue