mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 14:31:55 +00:00
fix: Unexpected trait bound not satisfied in HRTB
This commit is contained in:
parent
21f6839352
commit
d164448038
@ -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() {
|
||||
|
75
tests/ui/traits/issue-103563.rs
Normal file
75
tests/ui/traits/issue-103563.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user