fix: Unexpected trait bound not satisfied in HRTB

This commit is contained in:
yifei 2023-01-19 00:38:09 +08:00
parent 21f6839352
commit d164448038
2 changed files with 121 additions and 1 deletions

View File

@ -27,6 +27,7 @@ use super::{
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::project::try_normalize_with_depth_to;
use crate::traits::project::ProjectAndUnifyResult;
use crate::traits::project::ProjectionCacheKeyExt;
use crate::traits::ProjectionCacheKey;
@ -1017,7 +1018,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Ok(cycle_result);
}
let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
let (result, dep_node) = self.in_task(|this| {
let mut result = this.evaluate_stack(&stack)?;
// fix issue #103563, we don't normalize
// nested obligations which produced by `TraitDef` candidate
// (i.e. using bounds on assoc items as assumptions).
// because we don't have enough information to
// normalize these obligations before evaluating.
// so we will try to normalize the obligation and evaluate again.
// we will replace it with new solver in the future.
if EvaluationResult::EvaluatedToErr == result
&& fresh_trait_pred.has_projections()
&& fresh_trait_pred.is_global()
{
let mut nested_obligations = Vec::new();
let predicate = try_normalize_with_depth_to(
this,
param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.predicate,
&mut nested_obligations,
);
if predicate != obligation.predicate {
let mut nested_result = EvaluationResult::EvaluatedToOk;
for obligation in nested_obligations {
nested_result = cmp::max(
this.evaluate_predicate_recursively(stack.list(), obligation)?,
nested_result,
);
}
if nested_result.must_apply_modulo_regions() {
let obligation = obligation.with(this.tcx(), predicate);
result = cmp::max(
nested_result,
this.evaluate_trait_predicate_recursively(stack.list(), obligation)?,
);
}
}
}
Ok::<_, OverflowError>(result)
});
let result = result?;
if !result.must_apply_modulo_regions() {

View File

@ -0,0 +1,75 @@
// build-pass
fn main() {
let mut log_service = LogService { inner: Inner };
log_service.call(());
}
pub trait Service<Request> {
type Response;
fn call(&mut self, req: Request) -> Self::Response;
}
pub struct LogService<S> {
inner: S,
}
impl<T, U, S> Service<T> for LogService<S>
where
S: Service<T, Response = U>,
U: Extension + 'static,
for<'a> U::Item<'a>: std::fmt::Debug,
{
type Response = S::Response;
fn call(&mut self, req: T) -> Self::Response {
self.inner.call(req)
}
}
pub struct Inner;
impl Service<()> for Inner {
type Response = Resp;
fn call(&mut self, req: ()) -> Self::Response {
Resp::A(req)
}
}
pub trait Extension {
type Item<'a>;
fn touch<F>(self, f: F) -> Self
where
for<'a> F: Fn(Self::Item<'a>);
}
pub enum Resp {
A(()),
}
impl Extension for Resp {
type Item<'a> = RespItem<'a>;
fn touch<F>(self, _f: F) -> Self
where
for<'a> F: Fn(Self::Item<'a>),
{
match self {
Self::A(a) => Self::A(a),
}
}
}
pub enum RespItem<'a> {
A(&'a ()),
}
impl<'a> std::fmt::Debug for RespItem<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::A(arg0) => f.debug_tuple("A").field(arg0).finish(),
}
}
}