introduce enter_forall
This commit is contained in:
parent
af88f7db51
commit
ac559af98f
15 changed files with 524 additions and 446 deletions
|
@ -1032,10 +1032,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty::SubtypePredicate { a_is_expected, a, b } =
|
// FIXME(tree_universes): leaking universes
|
||||||
self.instantiate_binder_with_placeholders(predicate);
|
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
|
||||||
|
Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
|
||||||
Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn region_outlives_predicate(
|
pub fn region_outlives_predicate(
|
||||||
|
@ -1043,10 +1043,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
cause: &traits::ObligationCause<'tcx>,
|
cause: &traits::ObligationCause<'tcx>,
|
||||||
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
|
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
|
||||||
) {
|
) {
|
||||||
let ty::OutlivesPredicate(r_a, r_b) = self.instantiate_binder_with_placeholders(predicate);
|
// FIXME(tree_universes): leaking universes
|
||||||
let origin =
|
self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| {
|
||||||
SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
|
let origin = SubregionOrigin::from_obligation_cause(cause, || {
|
||||||
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
|
RelateRegionParamBound(cause.span)
|
||||||
|
});
|
||||||
|
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of type variables created so far.
|
/// Number of type variables created so far.
|
||||||
|
@ -1455,7 +1458,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
// Use this method if you'd like to find some substitution of the binder's
|
// Use this method if you'd like to find some substitution of the binder's
|
||||||
// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`]
|
// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`]
|
||||||
// that corresponds to your use case, consider whether or not you should
|
// that corresponds to your use case, consider whether or not you should
|
||||||
// use [`InferCtxt::instantiate_binder_with_placeholders`] instead.
|
// use [`InferCtxt::enter_forall`] instead.
|
||||||
pub fn instantiate_binder_with_fresh_vars<T>(
|
pub fn instantiate_binder_with_fresh_vars<T>(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
|
@ -38,24 +38,24 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
|
||||||
// First, we instantiate each bound region in the supertype with a
|
// First, we instantiate each bound region in the supertype with a
|
||||||
// fresh placeholder region. Note that this automatically creates
|
// fresh placeholder region. Note that this automatically creates
|
||||||
// a new universe if needed.
|
// a new universe if needed.
|
||||||
let sup_prime = self.infcx.instantiate_binder_with_placeholders(sup);
|
self.infcx.enter_forall(sup, |sup_prime| {
|
||||||
|
// Next, we instantiate each bound region in the subtype
|
||||||
|
// with a fresh region variable. These region variables --
|
||||||
|
// but no other preexisting region variables -- can name
|
||||||
|
// the placeholders.
|
||||||
|
let sub_prime =
|
||||||
|
self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
|
||||||
|
debug!("a_prime={:?}", sub_prime);
|
||||||
|
debug!("b_prime={:?}", sup_prime);
|
||||||
|
|
||||||
// Next, we instantiate each bound region in the subtype
|
// Compare types now that bound regions have been replaced.
|
||||||
// with a fresh region variable. These region variables --
|
// FIXME(tree_universes): leaked dead universes
|
||||||
// but no other preexisting region variables -- can name
|
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime);
|
||||||
// the placeholders.
|
if result.is_ok() {
|
||||||
let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
|
debug!("OK result={result:?}");
|
||||||
|
}
|
||||||
debug!("a_prime={:?}", sub_prime);
|
result.map(|_| ())
|
||||||
debug!("b_prime={:?}", sup_prime);
|
})
|
||||||
|
|
||||||
// Compare types now that bound regions have been replaced.
|
|
||||||
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?;
|
|
||||||
|
|
||||||
debug!("OK result={result:?}");
|
|
||||||
// NOTE: returning the result here would be dangerous as it contains
|
|
||||||
// placeholders which **must not** be named afterwards.
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,6 +106,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
self.tcx.replace_bound_vars_uncached(binder, delegate)
|
self.tcx.replace_bound_vars_uncached(binder, delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U
|
||||||
|
where
|
||||||
|
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
|
||||||
|
{
|
||||||
|
let value = self.instantiate_binder_with_placeholders(forall);
|
||||||
|
f(value)
|
||||||
|
}
|
||||||
|
|
||||||
/// See [RegionConstraintCollector::leak_check][1]. We only check placeholder
|
/// See [RegionConstraintCollector::leak_check][1]. We only check placeholder
|
||||||
/// leaking into `outer_universe`, i.e. placeholders which cannot be named by that
|
/// leaking into `outer_universe`, i.e. placeholders which cannot be named by that
|
||||||
/// universe.
|
/// universe.
|
||||||
|
|
|
@ -309,6 +309,18 @@ where
|
||||||
replaced
|
replaced
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enter_forall<T, U>(
|
||||||
|
&mut self,
|
||||||
|
binder: ty::Binder<'tcx, T>,
|
||||||
|
f: impl FnOnce(&mut Self, T) -> U,
|
||||||
|
) -> U
|
||||||
|
where
|
||||||
|
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
|
||||||
|
{
|
||||||
|
let value = self.instantiate_binder_with_placeholders(binder);
|
||||||
|
f(self, value)
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
|
fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
|
||||||
where
|
where
|
||||||
|
@ -630,10 +642,10 @@ where
|
||||||
|
|
||||||
// Note: the order here is important. Create the placeholders first, otherwise
|
// Note: the order here is important. Create the placeholders first, otherwise
|
||||||
// we assign the wrong universe to the existential!
|
// we assign the wrong universe to the existential!
|
||||||
let b_replaced = self.instantiate_binder_with_placeholders(b);
|
self.enter_forall(b, |this, b| {
|
||||||
let a_replaced = self.instantiate_binder_with_existentials(a);
|
let a = this.instantiate_binder_with_existentials(a);
|
||||||
|
this.relate(a, b)
|
||||||
self.relate(a_replaced, b_replaced)?;
|
})?;
|
||||||
|
|
||||||
self.ambient_variance = variance;
|
self.ambient_variance = variance;
|
||||||
}
|
}
|
||||||
|
@ -650,10 +662,10 @@ where
|
||||||
let variance =
|
let variance =
|
||||||
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
|
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
|
||||||
|
|
||||||
let a_replaced = self.instantiate_binder_with_placeholders(a);
|
self.enter_forall(a, |this, a| {
|
||||||
let b_replaced = self.instantiate_binder_with_existentials(b);
|
let b = this.instantiate_binder_with_existentials(b);
|
||||||
|
this.relate(a, b)
|
||||||
self.relate(a_replaced, b_replaced)?;
|
})?;
|
||||||
|
|
||||||
self.ambient_variance = variance;
|
self.ambient_variance = variance;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,101 +77,104 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
|
||||||
for (pred, pred_span) in
|
for (pred, pred_span) in
|
||||||
cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied()
|
cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied()
|
||||||
{
|
{
|
||||||
let predicate = infcx.instantiate_binder_with_placeholders(pred.kind());
|
infcx.enter_forall(pred.kind(), |predicate| {
|
||||||
let ty::ClauseKind::Projection(proj) = predicate else {
|
let ty::ClauseKind::Projection(proj) = predicate else {
|
||||||
continue;
|
return;
|
||||||
};
|
|
||||||
// Only check types, since those are the only things that may
|
|
||||||
// have opaques in them anyways.
|
|
||||||
let Some(proj_term) = proj.term.ty() else { continue };
|
|
||||||
|
|
||||||
// HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
|
|
||||||
if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
|
|
||||||
&& cx.tcx.parent(opaque_ty.def_id) == def_id
|
|
||||||
&& matches!(
|
|
||||||
opaque.origin,
|
|
||||||
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK: `async fn() -> Self` in traits is "ok"...
|
|
||||||
// This is not really that great, but it's similar to why the `-> Self`
|
|
||||||
// return type is well-formed in traits even when `Self` isn't sized.
|
|
||||||
if let ty::Param(param_ty) = *proj_term.kind()
|
|
||||||
&& param_ty.name == kw::SelfUpper
|
|
||||||
&& matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_))
|
|
||||||
&& opaque.in_trait
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let proj_ty =
|
|
||||||
Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.args);
|
|
||||||
// For every instance of the projection type in the bounds,
|
|
||||||
// replace them with the term we're assigning to the associated
|
|
||||||
// type in our opaque type.
|
|
||||||
let proj_replacer = &mut BottomUpFolder {
|
|
||||||
tcx: cx.tcx,
|
|
||||||
ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
|
|
||||||
lt_op: |lt| lt,
|
|
||||||
ct_op: |ct| ct,
|
|
||||||
};
|
|
||||||
// For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
|
|
||||||
// e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
|
|
||||||
// with `impl Send: OtherTrait`.
|
|
||||||
for (assoc_pred, assoc_pred_span) in cx
|
|
||||||
.tcx
|
|
||||||
.explicit_item_bounds(proj.projection_ty.def_id)
|
|
||||||
.iter_instantiated_copied(cx.tcx, proj.projection_ty.args)
|
|
||||||
{
|
|
||||||
let assoc_pred = assoc_pred.fold_with(proj_replacer);
|
|
||||||
let Ok(assoc_pred) = traits::fully_normalize(
|
|
||||||
infcx,
|
|
||||||
traits::ObligationCause::dummy(),
|
|
||||||
cx.param_env,
|
|
||||||
assoc_pred,
|
|
||||||
) else {
|
|
||||||
continue;
|
|
||||||
};
|
};
|
||||||
// If that predicate doesn't hold modulo regions (but passed during type-check),
|
// Only check types, since those are the only things that may
|
||||||
// then we must've taken advantage of the hack in `project_and_unify_types` where
|
// have opaques in them anyways.
|
||||||
// we replace opaques with inference vars. Emit a warning!
|
let Some(proj_term) = proj.term.ty() else { return };
|
||||||
if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
|
|
||||||
cx.tcx,
|
// HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
|
||||||
traits::ObligationCause::dummy(),
|
if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
|
||||||
cx.param_env,
|
&& cx.tcx.parent(opaque_ty.def_id) == def_id
|
||||||
assoc_pred,
|
&& matches!(
|
||||||
)) {
|
opaque.origin,
|
||||||
// If it's a trait bound and an opaque that doesn't satisfy it,
|
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
|
||||||
// then we can emit a suggestion to add the bound.
|
)
|
||||||
let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
|
{
|
||||||
(
|
return;
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
|
|
||||||
ty::ClauseKind::Trait(trait_pred),
|
|
||||||
) => Some(AddBound {
|
|
||||||
suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
|
|
||||||
trait_ref: trait_pred.print_modifiers_and_trait_path(),
|
|
||||||
}),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
cx.emit_span_lint(
|
|
||||||
OPAQUE_HIDDEN_INFERRED_BOUND,
|
|
||||||
pred_span,
|
|
||||||
OpaqueHiddenInferredBoundLint {
|
|
||||||
ty: Ty::new_opaque(
|
|
||||||
cx.tcx,
|
|
||||||
def_id,
|
|
||||||
ty::GenericArgs::identity_for_item(cx.tcx, def_id),
|
|
||||||
),
|
|
||||||
proj_ty: proj_term,
|
|
||||||
assoc_pred_span,
|
|
||||||
add_bound,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// HACK: `async fn() -> Self` in traits is "ok"...
|
||||||
|
// This is not really that great, but it's similar to why the `-> Self`
|
||||||
|
// return type is well-formed in traits even when `Self` isn't sized.
|
||||||
|
if let ty::Param(param_ty) = *proj_term.kind()
|
||||||
|
&& param_ty.name == kw::SelfUpper
|
||||||
|
&& matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_))
|
||||||
|
&& opaque.in_trait
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let proj_ty =
|
||||||
|
Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.args);
|
||||||
|
// For every instance of the projection type in the bounds,
|
||||||
|
// replace them with the term we're assigning to the associated
|
||||||
|
// type in our opaque type.
|
||||||
|
let proj_replacer = &mut BottomUpFolder {
|
||||||
|
tcx: cx.tcx,
|
||||||
|
ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
|
||||||
|
lt_op: |lt| lt,
|
||||||
|
ct_op: |ct| ct,
|
||||||
|
};
|
||||||
|
// For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
|
||||||
|
// e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
|
||||||
|
// with `impl Send: OtherTrait`.
|
||||||
|
for (assoc_pred, assoc_pred_span) in cx
|
||||||
|
.tcx
|
||||||
|
.explicit_item_bounds(proj.projection_ty.def_id)
|
||||||
|
.iter_instantiated_copied(cx.tcx, proj.projection_ty.args)
|
||||||
|
{
|
||||||
|
let assoc_pred = assoc_pred.fold_with(proj_replacer);
|
||||||
|
let Ok(assoc_pred) = traits::fully_normalize(
|
||||||
|
infcx,
|
||||||
|
traits::ObligationCause::dummy(),
|
||||||
|
cx.param_env,
|
||||||
|
assoc_pred,
|
||||||
|
) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If that predicate doesn't hold modulo regions (but passed during type-check),
|
||||||
|
// then we must've taken advantage of the hack in `project_and_unify_types` where
|
||||||
|
// we replace opaques with inference vars. Emit a warning!
|
||||||
|
if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
|
||||||
|
cx.tcx,
|
||||||
|
traits::ObligationCause::dummy(),
|
||||||
|
cx.param_env,
|
||||||
|
assoc_pred,
|
||||||
|
)) {
|
||||||
|
// If it's a trait bound and an opaque that doesn't satisfy it,
|
||||||
|
// then we can emit a suggestion to add the bound.
|
||||||
|
let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
|
||||||
|
(
|
||||||
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
|
||||||
|
ty::ClauseKind::Trait(trait_pred),
|
||||||
|
) => Some(AddBound {
|
||||||
|
suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
|
||||||
|
trait_ref: trait_pred.print_modifiers_and_trait_path(),
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
cx.emit_span_lint(
|
||||||
|
OPAQUE_HIDDEN_INFERRED_BOUND,
|
||||||
|
pred_span,
|
||||||
|
OpaqueHiddenInferredBoundLint {
|
||||||
|
ty: Ty::new_opaque(
|
||||||
|
cx.tcx,
|
||||||
|
def_id,
|
||||||
|
ty::GenericArgs::identity_for_item(cx.tcx, def_id),
|
||||||
|
),
|
||||||
|
proj_ty: proj_term,
|
||||||
|
assoc_pred_span,
|
||||||
|
add_bound,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1052,6 +1052,7 @@ impl<'tcx, T> Binder<'tcx, T> {
|
||||||
where
|
where
|
||||||
T: TypeVisitable<TyCtxt<'tcx>>,
|
T: TypeVisitable<TyCtxt<'tcx>>,
|
||||||
{
|
{
|
||||||
|
// `self.value` is equivalent to `self.skip_binder()`
|
||||||
if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
|
if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::solve::EvalCtxt;
|
||||||
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||||
ecx: &EvalCtxt<'_, 'tcx>,
|
ecx: &EvalCtxt<'_, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Uint(_)
|
ty::Uint(_)
|
||||||
|
@ -34,7 +34,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||||
| ty::Char => Ok(vec![]),
|
| ty::Char => Ok(vec![]),
|
||||||
|
|
||||||
// Treat `str` like it's defined as `struct str([u8]);`
|
// Treat `str` like it's defined as `struct str([u8]);`
|
||||||
ty::Str => Ok(vec![Ty::new_slice(tcx, tcx.types.u8)]),
|
ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, tcx.types.u8))]),
|
||||||
|
|
||||||
ty::Dynamic(..)
|
ty::Dynamic(..)
|
||||||
| ty::Param(..)
|
| ty::Param(..)
|
||||||
|
@ -47,46 +47,46 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
|
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
|
||||||
Ok(vec![element_ty])
|
Ok(vec![ty::Binder::dummy(element_ty)])
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
|
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]),
|
||||||
|
|
||||||
ty::Tuple(tys) => {
|
ty::Tuple(tys) => {
|
||||||
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
|
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
|
||||||
Ok(tys.iter().collect())
|
Ok(tys.iter().map(ty::Binder::dummy).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
|
ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
|
||||||
|
|
||||||
ty::CoroutineClosure(_, args) => Ok(vec![args.as_coroutine_closure().tupled_upvars_ty()]),
|
ty::CoroutineClosure(_, args) => Ok(vec![args.as_coroutine_closure().tupled_upvars_ty()]),
|
||||||
|
|
||||||
ty::Coroutine(_, args) => {
|
ty::Coroutine(_, args) => {
|
||||||
let coroutine_args = args.as_coroutine();
|
let coroutine_args = args.as_coroutine();
|
||||||
Ok(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()])
|
Ok(vec![
|
||||||
|
ty::Binder::dummy(coroutine_args.tupled_upvars_ty()),
|
||||||
|
ty::Binder::dummy(coroutine_args.witness()),
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
ty::CoroutineWitness(def_id, args) => Ok(ecx
|
||||||
.tcx()
|
.tcx()
|
||||||
.coroutine_hidden_types(def_id)
|
.coroutine_hidden_types(def_id)
|
||||||
.map(|bty| {
|
.map(|bty| replace_erased_lifetimes_with_bound_vars(tcx, bty.instantiate(tcx, args)))
|
||||||
ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars(
|
|
||||||
tcx,
|
|
||||||
bty.instantiate(tcx, args),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.collect()),
|
.collect()),
|
||||||
|
|
||||||
// For `PhantomData<T>`, we pass `T`.
|
// For `PhantomData<T>`, we pass `T`.
|
||||||
ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![args.type_at(0)]),
|
ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]),
|
||||||
|
|
||||||
ty::Adt(def, args) => Ok(def.all_fields().map(|f| f.ty(tcx, args)).collect()),
|
ty::Adt(def, args) => {
|
||||||
|
Ok(def.all_fields().map(|f| ty::Binder::dummy(f.ty(tcx, args))).collect())
|
||||||
|
}
|
||||||
|
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
|
||||||
// We can resolve the `impl Trait` to its concrete type,
|
// We can resolve the `impl Trait` to its concrete type,
|
||||||
// which enforces a DAG between the functions requiring
|
// which enforces a DAG between the functions requiring
|
||||||
// the auto trait bounds in question.
|
// the auto trait bounds in question.
|
||||||
Ok(vec![tcx.type_of(def_id).instantiate(tcx, args)])
|
Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, args))])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>(
|
||||||
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||||
ecx: &EvalCtxt<'_, 'tcx>,
|
ecx: &EvalCtxt<'_, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||||
| ty::Uint(_)
|
| ty::Uint(_)
|
||||||
|
@ -150,11 +150,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||||
bug!("unexpected type `{ty}`")
|
bug!("unexpected type `{ty}`")
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Tuple(tys) => Ok(tys.to_vec()),
|
ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()),
|
||||||
|
|
||||||
ty::Adt(def, args) => {
|
ty::Adt(def, args) => {
|
||||||
let sized_crit = def.sized_constraint(ecx.tcx());
|
let sized_crit = def.sized_constraint(ecx.tcx());
|
||||||
Ok(sized_crit.iter_instantiated(ecx.tcx(), args).collect())
|
Ok(sized_crit.iter_instantiated(ecx.tcx(), args).map(ty::Binder::dummy).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||||
pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||||
ecx: &EvalCtxt<'_, 'tcx>,
|
ecx: &EvalCtxt<'_, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]),
|
ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]),
|
||||||
|
|
||||||
|
@ -194,9 +194,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||||
bug!("unexpected type `{ty}`")
|
bug!("unexpected type `{ty}`")
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Tuple(tys) => Ok(tys.to_vec()),
|
ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()),
|
||||||
|
|
||||||
ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
|
ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
|
||||||
|
|
||||||
ty::CoroutineClosure(..) => Err(NoSolution),
|
ty::CoroutineClosure(..) => Err(NoSolution),
|
||||||
|
|
||||||
|
@ -205,7 +205,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||||
Movability::Movable => {
|
Movability::Movable => {
|
||||||
if ecx.tcx().features().coroutine_clone {
|
if ecx.tcx().features().coroutine_clone {
|
||||||
let coroutine = args.as_coroutine();
|
let coroutine = args.as_coroutine();
|
||||||
Ok(vec![coroutine.tupled_upvars_ty(), coroutine.witness()])
|
Ok(vec![
|
||||||
|
ty::Binder::dummy(coroutine.tupled_upvars_ty()),
|
||||||
|
ty::Binder::dummy(coroutine.witness()),
|
||||||
|
])
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
|
@ -216,10 +219,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||||
.tcx()
|
.tcx()
|
||||||
.coroutine_hidden_types(def_id)
|
.coroutine_hidden_types(def_id)
|
||||||
.map(|bty| {
|
.map(|bty| {
|
||||||
ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars(
|
replace_erased_lifetimes_with_bound_vars(
|
||||||
ecx.tcx(),
|
ecx.tcx(),
|
||||||
bty.instantiate(ecx.tcx(), args),
|
bty.instantiate(ecx.tcx(), args),
|
||||||
))
|
)
|
||||||
})
|
})
|
||||||
.collect()),
|
.collect()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -477,10 +477,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let kind = self.infcx.instantiate_binder_with_placeholders(kind);
|
self.infcx.enter_forall(kind, |kind| {
|
||||||
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
|
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
|
||||||
self.add_goal(GoalSource::Misc, goal);
|
self.add_goal(GoalSource::Misc, goal);
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
// FIXME(tree_universes): leaking universes
|
||||||
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,13 +803,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn instantiate_binder_with_placeholders<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
|
pub(super) fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
|
||||||
&self,
|
&self,
|
||||||
value: ty::Binder<'tcx, T>,
|
value: ty::Binder<'tcx, T>,
|
||||||
) -> T {
|
f: impl FnOnce(T) -> U,
|
||||||
self.infcx.instantiate_binder_with_placeholders(value)
|
) -> U {
|
||||||
|
self.infcx.enter_forall(value, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||||
where
|
where
|
||||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||||
|
|
|
@ -31,103 +31,109 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
|
||||||
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||||
assert!(self.next_trait_solver());
|
assert!(self.next_trait_solver());
|
||||||
|
|
||||||
let trait_goal = Goal::new(
|
// FIXME(tree_universes): leaking universes?
|
||||||
self.tcx,
|
self.enter_forall(obligation.predicate, |pred| {
|
||||||
obligation.param_env,
|
let trait_goal = Goal::new(self.tcx, obligation.param_env, pred);
|
||||||
self.instantiate_binder_with_placeholders(obligation.predicate),
|
|
||||||
);
|
|
||||||
|
|
||||||
let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| {
|
let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| {
|
||||||
let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate);
|
let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate);
|
||||||
let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal);
|
let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal);
|
||||||
let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal);
|
let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal);
|
||||||
|
|
||||||
// pseudo-winnow
|
// pseudo-winnow
|
||||||
if candidates.len() == 0 {
|
if candidates.len() == 0 {
|
||||||
return Err(SelectionError::Unimplemented);
|
return Err(SelectionError::Unimplemented);
|
||||||
} else if candidates.len() > 1 {
|
} else if candidates.len() > 1 {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < candidates.len() {
|
while i < candidates.len() {
|
||||||
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
|
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
|
||||||
candidate_should_be_dropped_in_favor_of(
|
candidate_should_be_dropped_in_favor_of(
|
||||||
ecx.tcx(),
|
ecx.tcx(),
|
||||||
&candidates[i],
|
&candidates[i],
|
||||||
&candidates[j],
|
&candidates[j],
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
if should_drop_i {
|
if should_drop_i {
|
||||||
candidates.swap_remove(i);
|
candidates.swap_remove(i);
|
||||||
} else {
|
} else {
|
||||||
i += 1;
|
i += 1;
|
||||||
if i > 1 {
|
if i > 1 {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let candidate = candidates.pop().unwrap();
|
||||||
|
let (certainty, nested_goals) = ecx
|
||||||
|
.instantiate_and_apply_query_response(
|
||||||
|
trait_goal.param_env,
|
||||||
|
orig_values,
|
||||||
|
candidate.result,
|
||||||
|
)
|
||||||
|
.map_err(|_| SelectionError::Unimplemented)?;
|
||||||
|
|
||||||
|
Ok(Some((candidate, certainty, nested_goals)))
|
||||||
|
});
|
||||||
|
|
||||||
|
let (candidate, certainty, nested_goals) = match result {
|
||||||
|
Ok(Some((candidate, certainty, nested_goals))) => {
|
||||||
|
(candidate, certainty, nested_goals)
|
||||||
|
}
|
||||||
|
Ok(None) => return Ok(None),
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
|
|
||||||
|
let nested_obligations: Vec<_> = nested_goals
|
||||||
|
.into_iter()
|
||||||
|
.map(|goal| {
|
||||||
|
Obligation::new(
|
||||||
|
self.tcx,
|
||||||
|
ObligationCause::dummy(),
|
||||||
|
goal.param_env,
|
||||||
|
goal.predicate,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let goal = self.resolve_vars_if_possible(trait_goal);
|
||||||
|
match (certainty, candidate.source) {
|
||||||
|
// Rematching the implementation will instantiate the same nested goals that
|
||||||
|
// would have caused the ambiguity, so we can still make progress here regardless.
|
||||||
|
(_, CandidateSource::Impl(def_id)) => {
|
||||||
|
rematch_impl(self, goal, def_id, nested_obligations)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an unsize goal is ambiguous, then we can manually rematch it to make
|
||||||
|
// selection progress for coercion during HIR typeck. If it is *not* ambiguous,
|
||||||
|
// but is `BuiltinImplSource::Misc`, it may have nested `Unsize` goals,
|
||||||
|
// and we need to rematch those to detect tuple unsizing and trait upcasting.
|
||||||
|
// FIXME: This will be wrong if we have param-env or where-clause bounds
|
||||||
|
// with the unsize goal -- we may need to mark those with different impl
|
||||||
|
// sources.
|
||||||
|
(Certainty::Maybe(_), CandidateSource::BuiltinImpl(src))
|
||||||
|
| (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc))
|
||||||
|
if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
|
||||||
|
{
|
||||||
|
rematch_unsize(self, goal, nested_obligations, src, certainty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Technically some builtin impls have nested obligations, but if
|
||||||
|
// `Certainty::Yes`, then they should've all been verified and don't
|
||||||
|
// need re-checking.
|
||||||
|
(Certainty::Yes, CandidateSource::BuiltinImpl(src)) => {
|
||||||
|
Ok(Some(ImplSource::Builtin(src, nested_obligations)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's fine not to do anything to rematch these, since there are no
|
||||||
|
// nested obligations.
|
||||||
|
(Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => {
|
||||||
|
Ok(Some(ImplSource::Param(nested_obligations)))
|
||||||
|
}
|
||||||
|
|
||||||
|
(Certainty::Maybe(_), _) => Ok(None),
|
||||||
}
|
}
|
||||||
|
})
|
||||||
let candidate = candidates.pop().unwrap();
|
|
||||||
let (certainty, nested_goals) = ecx
|
|
||||||
.instantiate_and_apply_query_response(
|
|
||||||
trait_goal.param_env,
|
|
||||||
orig_values,
|
|
||||||
candidate.result,
|
|
||||||
)
|
|
||||||
.map_err(|_| SelectionError::Unimplemented)?;
|
|
||||||
|
|
||||||
Ok(Some((candidate, certainty, nested_goals)))
|
|
||||||
});
|
|
||||||
|
|
||||||
let (candidate, certainty, nested_goals) = match result {
|
|
||||||
Ok(Some((candidate, certainty, nested_goals))) => (candidate, certainty, nested_goals),
|
|
||||||
Ok(None) => return Ok(None),
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
|
|
||||||
let nested_obligations: Vec<_> = nested_goals
|
|
||||||
.into_iter()
|
|
||||||
.map(|goal| {
|
|
||||||
Obligation::new(self.tcx, ObligationCause::dummy(), goal.param_env, goal.predicate)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let goal = self.resolve_vars_if_possible(trait_goal);
|
|
||||||
match (certainty, candidate.source) {
|
|
||||||
// Rematching the implementation will instantiate the same nested goals that
|
|
||||||
// would have caused the ambiguity, so we can still make progress here regardless.
|
|
||||||
(_, CandidateSource::Impl(def_id)) => {
|
|
||||||
rematch_impl(self, goal, def_id, nested_obligations)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If an unsize goal is ambiguous, then we can manually rematch it to make
|
|
||||||
// selection progress for coercion during HIR typeck. If it is *not* ambiguous,
|
|
||||||
// but is `BuiltinImplSource::Misc`, it may have nested `Unsize` goals,
|
|
||||||
// and we need to rematch those to detect tuple unsizing and trait upcasting.
|
|
||||||
// FIXME: This will be wrong if we have param-env or where-clause bounds
|
|
||||||
// with the unsize goal -- we may need to mark those with different impl
|
|
||||||
// sources.
|
|
||||||
(Certainty::Maybe(_), CandidateSource::BuiltinImpl(src))
|
|
||||||
| (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc))
|
|
||||||
if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
|
|
||||||
{
|
|
||||||
rematch_unsize(self, goal, nested_obligations, src, certainty)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Technically some builtin impls have nested obligations, but if
|
|
||||||
// `Certainty::Yes`, then they should've all been verified and don't
|
|
||||||
// need re-checking.
|
|
||||||
(Certainty::Yes, CandidateSource::BuiltinImpl(src)) => {
|
|
||||||
Ok(Some(ImplSource::Builtin(src, nested_obligations)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// It's fine not to do anything to rematch these, since there are no
|
|
||||||
// nested obligations.
|
|
||||||
(Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => {
|
|
||||||
Ok(Some(ImplSource::Param(nested_obligations)))
|
|
||||||
}
|
|
||||||
|
|
||||||
(Certainty::Maybe(_), _) => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1049,14 +1049,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
fn probe_and_evaluate_goal_for_constituent_tys(
|
fn probe_and_evaluate_goal_for_constituent_tys(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||||
constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
|
constituent_tys: impl Fn(
|
||||||
|
&EvalCtxt<'_, 'tcx>,
|
||||||
|
Ty<'tcx>,
|
||||||
|
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
self.probe_misc_candidate("constituent tys").enter(|ecx| {
|
self.probe_misc_candidate("constituent tys").enter(|ecx| {
|
||||||
ecx.add_goals(
|
ecx.add_goals(
|
||||||
GoalSource::ImplWhereBound,
|
GoalSource::ImplWhereBound,
|
||||||
constituent_tys(ecx, goal.predicate.self_ty())?
|
constituent_tys(ecx, goal.predicate.self_ty())?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ty| goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty)))
|
.map(|ty| {
|
||||||
|
// FIXME(tree_universes): leaking universes
|
||||||
|
ecx.enter_forall(ty, |ty| {
|
||||||
|
goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty))
|
||||||
|
})
|
||||||
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
);
|
);
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
|
|
@ -971,7 +971,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
let Goal { param_env, predicate } = goal.goal();
|
let Goal { param_env, predicate } = goal.goal();
|
||||||
|
|
||||||
// For bound predicates we simply call `infcx.instantiate_binder_with_placeholders`
|
// For bound predicates we simply call `infcx.enter_forall`
|
||||||
// and then prove the resulting predicate as a nested goal.
|
// and then prove the resulting predicate as a nested goal.
|
||||||
let trait_ref = match predicate.kind().no_bound_vars() {
|
let trait_ref = match predicate.kind().no_bound_vars() {
|
||||||
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
|
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
|
||||||
|
|
|
@ -21,51 +21,62 @@ pub fn recompute_applicable_impls<'tcx>(
|
||||||
|
|
||||||
let impl_may_apply = |impl_def_id| {
|
let impl_may_apply = |impl_def_id| {
|
||||||
let ocx = ObligationCtxt::new(infcx);
|
let ocx = ObligationCtxt::new(infcx);
|
||||||
let placeholder_obligation =
|
infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
|
||||||
infcx.instantiate_binder_with_placeholders(obligation.predicate);
|
let obligation_trait_ref = ocx.normalize(
|
||||||
let obligation_trait_ref =
|
&ObligationCause::dummy(),
|
||||||
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
|
param_env,
|
||||||
|
placeholder_obligation.trait_ref,
|
||||||
|
);
|
||||||
|
|
||||||
let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
|
let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
|
||||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args);
|
let impl_trait_ref =
|
||||||
let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
|
tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args);
|
||||||
|
let impl_trait_ref =
|
||||||
|
ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
|
||||||
|
|
||||||
if let Err(_) =
|
if let Err(_) =
|
||||||
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
|
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_args);
|
let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_args);
|
||||||
ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| {
|
ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| {
|
||||||
Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
|
Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
ocx.select_where_possible().is_empty()
|
ocx.select_where_possible().is_empty()
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
|
let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
|
||||||
let ocx = ObligationCtxt::new(infcx);
|
let ocx = ObligationCtxt::new(infcx);
|
||||||
let placeholder_obligation =
|
infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
|
||||||
infcx.instantiate_binder_with_placeholders(obligation.predicate);
|
let obligation_trait_ref = ocx.normalize(
|
||||||
let obligation_trait_ref =
|
&ObligationCause::dummy(),
|
||||||
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
|
param_env,
|
||||||
|
placeholder_obligation.trait_ref,
|
||||||
|
);
|
||||||
|
|
||||||
let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
|
let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
|
||||||
DUMMY_SP,
|
DUMMY_SP,
|
||||||
BoundRegionConversionTime::HigherRankedType,
|
BoundRegionConversionTime::HigherRankedType,
|
||||||
poly_trait_predicate,
|
poly_trait_predicate,
|
||||||
);
|
);
|
||||||
let param_env_trait_ref =
|
let param_env_trait_ref =
|
||||||
ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
|
ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
|
||||||
|
|
||||||
if let Err(_) =
|
if let Err(_) = ocx.eq(
|
||||||
ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, param_env_trait_ref)
|
&ObligationCause::dummy(),
|
||||||
{
|
param_env,
|
||||||
return false;
|
obligation_trait_ref,
|
||||||
}
|
param_env_trait_ref,
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ocx.select_where_possible().is_empty()
|
ocx.select_where_possible().is_empty()
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ambiguities = Vec::new();
|
let mut ambiguities = Vec::new();
|
||||||
|
|
|
@ -64,39 +64,44 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
) -> Option<(DefId, GenericArgsRef<'tcx>)> {
|
) -> Option<(DefId, GenericArgsRef<'tcx>)> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let param_env = obligation.param_env;
|
let param_env = obligation.param_env;
|
||||||
let trait_ref = self.instantiate_binder_with_placeholders(trait_ref);
|
self.enter_forall(trait_ref, |trait_ref| {
|
||||||
let trait_self_ty = trait_ref.self_ty();
|
let trait_self_ty = trait_ref.self_ty();
|
||||||
|
|
||||||
let mut self_match_impls = vec![];
|
let mut self_match_impls = vec![];
|
||||||
let mut fuzzy_match_impls = vec![];
|
let mut fuzzy_match_impls = vec![];
|
||||||
|
|
||||||
self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
|
self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
|
||||||
let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id);
|
let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id);
|
||||||
let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args);
|
let impl_trait_ref =
|
||||||
|
tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args);
|
||||||
|
|
||||||
let impl_self_ty = impl_trait_ref.self_ty();
|
let impl_self_ty = impl_trait_ref.self_ty();
|
||||||
|
|
||||||
if self.can_eq(param_env, trait_self_ty, impl_self_ty) {
|
if self.can_eq(param_env, trait_self_ty, impl_self_ty) {
|
||||||
self_match_impls.push((def_id, impl_args));
|
self_match_impls.push((def_id, impl_args));
|
||||||
|
|
||||||
if iter::zip(trait_ref.args.types().skip(1), impl_trait_ref.args.types().skip(1))
|
if iter::zip(
|
||||||
|
trait_ref.args.types().skip(1),
|
||||||
|
impl_trait_ref.args.types().skip(1),
|
||||||
|
)
|
||||||
.all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
|
.all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
|
||||||
{
|
{
|
||||||
fuzzy_match_impls.push((def_id, impl_args));
|
fuzzy_match_impls.push((def_id, impl_args));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
let impl_def_id_and_args = if self_match_impls.len() == 1 {
|
let impl_def_id_and_args = if self_match_impls.len() == 1 {
|
||||||
self_match_impls[0]
|
self_match_impls[0]
|
||||||
} else if fuzzy_match_impls.len() == 1 {
|
} else if fuzzy_match_impls.len() == 1 {
|
||||||
fuzzy_match_impls[0]
|
fuzzy_match_impls[0]
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
tcx.has_attr(impl_def_id_and_args.0, sym::rustc_on_unimplemented)
|
tcx.has_attr(impl_def_id_and_args.0, sym::rustc_on_unimplemented)
|
||||||
.then_some(impl_def_id_and_args)
|
.then_some(impl_def_id_and_args)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to set on_unimplemented's `ItemContext`
|
/// Used to set on_unimplemented's `ItemContext`
|
||||||
|
|
|
@ -1248,52 +1248,55 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
|
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
|
||||||
let ty = self.instantiate_binder_with_placeholders(self_ty);
|
self.enter_forall(self_ty, |ty: Ty<'_>| {
|
||||||
let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else {
|
let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
|
let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
|
||||||
let ty::Param(param) = inner_ty.kind() else { return false };
|
let ty::Param(param) = inner_ty.kind() else { return false };
|
||||||
let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
|
let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
|
||||||
obligation.cause.code()
|
obligation.cause.code()
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let arg_node = self.tcx.hir_node(*arg_hir_id);
|
let arg_node = self.tcx.hir_node(*arg_hir_id);
|
||||||
let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else { return false };
|
let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
|
let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
|
||||||
let has_clone = |ty| {
|
let has_clone = |ty| {
|
||||||
self.type_implements_trait(clone_trait, [ty], obligation.param_env)
|
self.type_implements_trait(clone_trait, [ty], obligation.param_env)
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),
|
trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),
|
||||||
);
|
|
||||||
|
|
||||||
if self.predicate_may_hold(&new_obligation) && has_clone(ty) {
|
|
||||||
if !has_clone(param.to_ty(self.tcx)) {
|
|
||||||
suggest_constraining_type_param(
|
|
||||||
self.tcx,
|
|
||||||
generics,
|
|
||||||
err,
|
|
||||||
param.name.as_str(),
|
|
||||||
"Clone",
|
|
||||||
Some(clone_trait),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
err.span_suggestion_verbose(
|
|
||||||
obligation.cause.span.shrink_to_hi(),
|
|
||||||
"consider using clone here",
|
|
||||||
".clone()",
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
);
|
||||||
return true;
|
|
||||||
}
|
if self.predicate_may_hold(&new_obligation) && has_clone(ty) {
|
||||||
false
|
if !has_clone(param.to_ty(self.tcx)) {
|
||||||
|
suggest_constraining_type_param(
|
||||||
|
self.tcx,
|
||||||
|
generics,
|
||||||
|
err,
|
||||||
|
param.name.as_str(),
|
||||||
|
"Clone",
|
||||||
|
Some(clone_trait),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
obligation.cause.span.shrink_to_hi(),
|
||||||
|
"consider using clone here",
|
||||||
|
".clone()".to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts information about a callable type for diagnostics. This is a
|
/// Extracts information about a callable type for diagnostics. This is a
|
||||||
|
@ -4038,26 +4041,27 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
if let Some(where_pred) = where_pred.as_trait_clause()
|
if let Some(where_pred) = where_pred.as_trait_clause()
|
||||||
&& let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
|
&& let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
|
||||||
{
|
{
|
||||||
let where_pred = self.instantiate_binder_with_placeholders(where_pred);
|
self.enter_forall(where_pred, |where_pred| {
|
||||||
let failed_pred = self.instantiate_binder_with_fresh_vars(
|
let failed_pred = self.instantiate_binder_with_fresh_vars(
|
||||||
expr.span,
|
expr.span,
|
||||||
BoundRegionConversionTime::FnCall,
|
BoundRegionConversionTime::FnCall,
|
||||||
failed_pred,
|
failed_pred,
|
||||||
);
|
);
|
||||||
|
|
||||||
let zipped = iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args);
|
let zipped =
|
||||||
for (expected, actual) in zipped {
|
iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args);
|
||||||
self.probe(|_| {
|
for (expected, actual) in zipped {
|
||||||
match self.at(&ObligationCause::misc(expr.span, body_id), param_env).eq(
|
self.probe(|_| {
|
||||||
DefineOpaqueTypes::No,
|
match self
|
||||||
expected,
|
.at(&ObligationCause::misc(expr.span, body_id), param_env)
|
||||||
actual,
|
.eq(DefineOpaqueTypes::No, expected, actual)
|
||||||
) {
|
{
|
||||||
Ok(_) => (), // We ignore nested obligations here for now.
|
Ok(_) => (), // We ignore nested obligations here for now.
|
||||||
Err(err) => type_diffs.push(err),
|
Err(err) => type_diffs.push(err),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
} else if let Some(where_pred) = where_pred.as_projection_clause()
|
} else if let Some(where_pred) = where_pred.as_projection_clause()
|
||||||
&& let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
|
&& let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
|
||||||
&& let Some(found) = failed_pred.skip_binder().term.ty()
|
&& let Some(found) = failed_pred.skip_binder().term.ty()
|
||||||
|
@ -4615,14 +4619,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
{
|
{
|
||||||
self.probe(|_| {
|
self.probe(|_| {
|
||||||
let ocx = ObligationCtxt::new(self);
|
let ocx = ObligationCtxt::new(self);
|
||||||
let pred = self.instantiate_binder_with_placeholders(pred);
|
self.enter_forall(pred, |pred| {
|
||||||
let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred);
|
let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred);
|
||||||
ocx.register_obligation(Obligation::new(
|
// FIXME(tree_universes): universe leakage
|
||||||
self.tcx,
|
ocx.register_obligation(Obligation::new(
|
||||||
ObligationCause::dummy(),
|
self.tcx,
|
||||||
param_env,
|
ObligationCause::dummy(),
|
||||||
pred,
|
param_env,
|
||||||
));
|
pred,
|
||||||
|
));
|
||||||
|
});
|
||||||
if !ocx.select_where_possible().is_empty() {
|
if !ocx.select_where_possible().is_empty() {
|
||||||
// encountered errors.
|
// encountered errors.
|
||||||
return;
|
return;
|
||||||
|
@ -4769,13 +4775,13 @@ fn hint_missing_borrow<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let found_args = match found.kind() {
|
let found_args = match found.kind() {
|
||||||
ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(),
|
ty::FnPtr(f) => infcx.enter_forall(*f, |f| f.inputs().iter()),
|
||||||
kind => {
|
kind => {
|
||||||
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
|
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let expected_args = match expected.kind() {
|
let expected_args = match expected.kind() {
|
||||||
ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(),
|
ty::FnPtr(f) => infcx.enter_forall(*f, |f| f.inputs().iter()),
|
||||||
kind => {
|
kind => {
|
||||||
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
|
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1307,12 +1307,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
let mut pred = obligation.predicate.to_opt_poly_trait_pred();
|
let mut pred = obligation.predicate.to_opt_poly_trait_pred();
|
||||||
while let Some((next_code, next_pred)) = code.parent() {
|
while let Some((next_code, next_pred)) = code.parent() {
|
||||||
if let Some(pred) = pred {
|
if let Some(pred) = pred {
|
||||||
let pred = self.instantiate_binder_with_placeholders(pred);
|
self.enter_forall(pred, |pred| {
|
||||||
diag.note(format!(
|
diag.note(format!(
|
||||||
"`{}` must implement `{}`, but it does not",
|
"`{}` must implement `{}`, but it does not",
|
||||||
pred.self_ty(),
|
pred.self_ty(),
|
||||||
pred.print_modifiers_and_trait_path()
|
pred.print_modifiers_and_trait_path()
|
||||||
));
|
));
|
||||||
|
})
|
||||||
}
|
}
|
||||||
code = next_code;
|
code = next_code;
|
||||||
pred = next_pred;
|
pred = next_pred;
|
||||||
|
@ -2017,70 +2018,79 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
if let [single] = &impl_candidates {
|
if let [single] = &impl_candidates {
|
||||||
if self.probe(|_| {
|
if self.probe(|_| {
|
||||||
let ocx = ObligationCtxt::new(self);
|
let ocx = ObligationCtxt::new(self);
|
||||||
let obligation_trait_ref = self.instantiate_binder_with_placeholders(trait_ref);
|
|
||||||
let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
|
|
||||||
let impl_trait_ref = ocx.normalize(
|
|
||||||
&ObligationCause::dummy(),
|
|
||||||
param_env,
|
|
||||||
ty::EarlyBinder::bind(single.trait_ref).instantiate(self.tcx, impl_args),
|
|
||||||
);
|
|
||||||
|
|
||||||
ocx.register_obligations(
|
self.enter_forall(trait_ref, |obligation_trait_ref| {
|
||||||
self.tcx
|
let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
|
||||||
.predicates_of(single.impl_def_id)
|
let impl_trait_ref = ocx.normalize(
|
||||||
.instantiate(self.tcx, impl_args)
|
&ObligationCause::dummy(),
|
||||||
.into_iter()
|
param_env,
|
||||||
.map(|(clause, _)| {
|
ty::EarlyBinder::bind(single.trait_ref).instantiate(self.tcx, impl_args),
|
||||||
Obligation::new(self.tcx, ObligationCause::dummy(), param_env, clause)
|
);
|
||||||
}),
|
|
||||||
);
|
|
||||||
if !ocx.select_where_possible().is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut terrs = vec![];
|
ocx.register_obligations(
|
||||||
for (obligation_arg, impl_arg) in
|
self.tcx
|
||||||
std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
|
.predicates_of(single.impl_def_id)
|
||||||
{
|
.instantiate(self.tcx, impl_args)
|
||||||
if let Err(terr) =
|
.into_iter()
|
||||||
ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg)
|
.map(|(clause, _)| {
|
||||||
{
|
Obligation::new(
|
||||||
terrs.push(terr);
|
self.tcx,
|
||||||
}
|
ObligationCause::dummy(),
|
||||||
|
param_env,
|
||||||
|
clause,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
);
|
||||||
if !ocx.select_where_possible().is_empty() {
|
if !ocx.select_where_possible().is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Literally nothing unified, just give up.
|
let mut terrs = vec![];
|
||||||
if terrs.len() == impl_trait_ref.args.len() {
|
for (obligation_arg, impl_arg) in
|
||||||
return false;
|
std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
|
||||||
}
|
{
|
||||||
|
// FIXME(tree_universes): universe leakage
|
||||||
|
if let Err(terr) =
|
||||||
|
ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg)
|
||||||
|
{
|
||||||
|
terrs.push(terr);
|
||||||
|
}
|
||||||
|
if !ocx.select_where_possible().is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let cand =
|
// Literally nothing unified, just give up.
|
||||||
self.resolve_vars_if_possible(impl_trait_ref).fold_with(&mut BottomUpFolder {
|
if terrs.len() == impl_trait_ref.args.len() {
|
||||||
tcx: self.tcx,
|
return false;
|
||||||
ty_op: |ty| ty,
|
}
|
||||||
lt_op: |lt| lt,
|
|
||||||
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
|
|
||||||
});
|
|
||||||
err.highlighted_help(vec![
|
|
||||||
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
|
|
||||||
StringPart::highlighted("is"),
|
|
||||||
StringPart::normal(" implemented for `"),
|
|
||||||
StringPart::highlighted(cand.self_ty().to_string()),
|
|
||||||
StringPart::normal("`"),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
|
let cand = self.resolve_vars_if_possible(impl_trait_ref).fold_with(
|
||||||
let exp_found = self.resolve_vars_if_possible(*exp_found);
|
&mut BottomUpFolder {
|
||||||
err.help(format!(
|
tcx: self.tcx,
|
||||||
"for that trait implementation, expected `{}`, found `{}`",
|
ty_op: |ty| ty,
|
||||||
exp_found.expected, exp_found.found
|
lt_op: |lt| lt,
|
||||||
));
|
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
|
||||||
}
|
},
|
||||||
|
);
|
||||||
|
err.highlighted_help(vec![
|
||||||
|
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
|
||||||
|
StringPart::highlighted("is"),
|
||||||
|
StringPart::normal(" implemented for `"),
|
||||||
|
StringPart::highlighted(cand.self_ty().to_string()),
|
||||||
|
StringPart::normal("`"),
|
||||||
|
]);
|
||||||
|
|
||||||
true
|
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
|
||||||
|
let exp_found = self.resolve_vars_if_possible(*exp_found);
|
||||||
|
err.help(format!(
|
||||||
|
"for that trait implementation, expected `{}`, found `{}`",
|
||||||
|
exp_found.expected, exp_found.found
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
})
|
||||||
}) {
|
}) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ pub enum RegionKind<I: Interner> {
|
||||||
/// Should not exist outside of type inference.
|
/// Should not exist outside of type inference.
|
||||||
///
|
///
|
||||||
/// Used when instantiating a `forall` binder via
|
/// Used when instantiating a `forall` binder via
|
||||||
/// `infcx.instantiate_binder_with_placeholders`.
|
/// `infcx.enter_forall` and `infcx.instantiate_binder_with_placeholders`.
|
||||||
RePlaceholder(I::PlaceholderRegion),
|
RePlaceholder(I::PlaceholderRegion),
|
||||||
|
|
||||||
/// Erased region, used by trait selection, in MIR and during codegen.
|
/// Erased region, used by trait selection, in MIR and during codegen.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue