diff options
| author | bors <bors@rust-lang.org> | 2023-06-19 10:38:04 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-06-19 10:38:04 +0000 |
| commit | 18a6d911caba59605eb03db1452848a85d2e5879 (patch) | |
| tree | 61c7c0454979c3a78c1773f6aad057b6383bed69 | |
| parent | 3c9e0705ba0c1c845fe7cdbd0bdf4a914f49cc8e (diff) | |
| parent | 3a6ce74c07889e691b3c3848c89dee15e026733c (diff) | |
| download | rust-18a6d911caba59605eb03db1452848a85d2e5879.tar.gz rust-18a6d911caba59605eb03db1452848a85d2e5879.zip | |
Auto merge of #112351 - BoxyUwU:proof_tree_generation, r=lcnr
new solver proof tree generation
Adds a new `-Z` flag `-Zdump-solver-proof-tree` which causes us to generate proof trees for each call to `infcx.evaluate_root_goal`. Currently these just get `debug!`'d out rather than put in a file.
Callers of `infcx.evaluate_root_goal` get the proof tree returned to them and can force one to be generated by passing in `GenerateProofTree::Yes`. Currently we do not disable the global cache or do anything about the provisional cache when generating proof trees is enabled, this is optimal for debugging but not so much for diagnostics.
Personally I think the exact formatting of proof trees here is not ideal but it's easy to change after this PR lands and would like to avoid bikeshedding the exact way we output this before we even have any of the logic merged to get all the information out of the solver.
This PR is best reviewed with whitespace changes hidden, there is also probably no point going commit by commit
r? `@lcnr`
Below is the proof tree output for the `AliasRelate(TAIT, sub, Alias)` case in rust-lang/trait-system-refactor-initiative#25 from the following command:
``RUSTC_LOG="rustc_trait_selection::solve::inspect::dump=debug" RUSTFLAGS="-Ztrait-solver=next -Zverbose -Zdump-solver-proof-tree" cargo +stage1 check``
<details><summary><strong>Proof tree</strong></summary>
<p>
```
DEBUG rustc_trait_selection::solve::inspect::dump tree=GOAL: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), [])), Subtype, Term::Ty(<?8t as std::iter::IntoIterator>::IntoIter)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), [])), Subtype, Term::Ty(<^1_0 as std::iter::IntoIterator>::IntoIter)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), [])), Subtype, Term::Ty(<?0t as std::iter::IntoIterator>::IntoIter)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [] }, PrivateZst)) }
CANDIDATE normalizes-to: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}) }, Term::Ty(<^1_0 as std::iter::IntoIterator>::IntoIter)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}) }, Term::Ty(<?0t as std::iter::IntoIterator>::IntoIter)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::IntoIter as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<^1_0 as std::iter::IntoIterator>::IntoIter as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::IntoIter as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }
NORMALIZING SELF TY FOR ASSEMBLY:
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE constituent tys: Err(NoSolution)
CANDIDATE assumption: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::IntoIter as std::iter::Iterator>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<^1_0 as std::iter::IntoIterator>::IntoIter as std::iter::Iterator>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::IntoIter as std::iter::Iterator>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }
NORMALIZING SELF TY FOR ASSEMBLY:
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE assumption: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<?0t as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<^1_0 as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<?0t as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
NORMALIZES-TO HACK GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<?0t as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<^1_0 as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, <^0 as std::iter::IntoIterator>::Item] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<?0t as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }
NORMALIZING SELF TY FOR ASSEMBLY:
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?2t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?2t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE assumption: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, <^0 as std::iter::IntoIterator>::Item] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, <^0 as std::iter::IntoIterator>::Item] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), [])), Equate, Term::Ty(<?0t as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), [])), Equate, Term::Ty(<^1_0 as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), [])), Equate, Term::Ty(<?0t as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }
CANDIDATE normalizes-to: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}) }, Term::Ty(<?0t as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}) }, Term::Ty(<^1_0 as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}) }, Term::Ty(<?0t as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::Item as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<^1_0 as std::iter::IntoIterator>::Item as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::Item as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::Item)] }, PrivateZst)) }
NORMALIZING SELF TY FOR ASSEMBLY:
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::Item)] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE constituent tys: Err(NoSolution)
CANDIDATE assumption: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::Item as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<^1_0 as std::iter::IntoIterator>::Item as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
REVISION 1
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}) }, Term::Ty(<?0t as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}) }, Term::Ty(<^1_0 as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE normalizes-to: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
NORMALIZES-TO HACK GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE substs relate: Err(NoSolution)
CANDIDATE bidir normalizes-to: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}) }, Term::Ty(<?0t as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}) }, Term::Ty(<^1_0 as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::Item)] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
NORMALIZES-TO HACK GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
REVISION 1
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}) }, Term::Ty(<?0t as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}) }, Term::Ty(<^1_0 as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7203 ~ core[b962]::iter::traits::collect::IntoIterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
REVISION 1
NORMALIZES-TO HACK GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<?0t as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(?2t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<^1_0 as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, <^0 as std::iter::IntoIterator>::Item] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<?0t as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::Item)] }, PrivateZst)) }
NORMALIZING SELF TY FOR ASSEMBLY:
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?2t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::Item)] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?2t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE assumption: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, <^0 as std::iter::IntoIterator>::Item] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, <^0 as std::iter::IntoIterator>::Item] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), [])), Equate, Term::Ty(<?0t as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), [])), Equate, Term::Ty(<^1_0 as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), [])), Equate, Term::Ty(<?0t as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(AliasRelate(Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), [])), Equate, Term::Ty(<^1_0 as std::iter::IntoIterator>::Item)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
REVISION 1
GOAL: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::IntoIter as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<^1_0 as std::iter::IntoIterator>::IntoIter as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::IntoIter as std::marker::Sized>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::Item)] }, PrivateZst)) }
NORMALIZING SELF TY FOR ASSEMBLY:
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE constituent tys: Err(NoSolution)
CANDIDATE assumption: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::IntoIter as std::iter::Iterator>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<^1_0 as std::iter::IntoIterator>::IntoIter as std::iter::Iterator>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(TraitPredicate(<<?0t as std::iter::IntoIterator>::IntoIter as std::iter::Iterator>, polarity:Positive), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::Item)] }, PrivateZst)) }
NORMALIZING SELF TY FOR ASSEMBLY:
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE assumption: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Yes)
REVISION 0
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<?0t as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [<^1_0 as std::iter::IntoIterator>::IntoIter], def_id: DefId(2:7319 ~ core[b962]::iter::traits::iterator::Iterator::Item) }, Term::Ty(Opaque(DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
REVISION 1
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}) }, Term::Ty(<^1_0 as std::iter::IntoIterator>::IntoIter)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE normalizes-to: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(Opaque(DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(Opaque(DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
NORMALIZES-TO HACK GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
CANDIDATE substs relate: Err(NoSolution)
CANDIDATE bidir normalizes-to: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}) }, Term::Ty(<^1_0 as std::iter::IntoIterator>::IntoIter)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?2t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(Opaque(DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
REVISION 0: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
INSTANTIATED: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(Opaque(DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <?0t as std::iter::IntoIterator>::Item)] }, PrivateZst)) }
TRY_EVALUATE_ADDED_GOALS: Ok(Maybe(Ambiguity))
REVISION 0
NORMALIZES-TO HACK GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(^1_1)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0, ^1] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] })
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
REVISION 1
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}) }, Term::Ty(?1t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [], def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}) }, Term::Ty(<^1_0 as std::iter::IntoIterator>::IntoIter)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
GOAL: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [?0t], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(?2t)), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }
CANONICALIZED: Canonical { value: QueryInput { goal: Goal { predicate: Binder(ProjectionPredicate(AliasTy { substs: [^1_0], def_id: DefId(2:7204 ~ core[b962]::iter::traits::collect::IntoIterator::IntoIter) }, Term::Ty(Opaque(DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), []))), []), param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst } }, anchor: Bind(DefId(0:6 ~ playground_proof_tree[b494]::a)), predefined_opaques_in_body: PredefinedOpaques(Interned(PredefinedOpaquesData { opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }
GLOBAL CACHE HIT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
RESULT: Ok(Canonical { value: Response { certainty: Maybe(Ambiguity), var_values: CanonicalVarValues { var_values: [^0] }, external_constraints: ExternalConstraints(Interned(ExternalConstraintsData { region_constraints: QueryRegionConstraints { outlives: [], member_constraints: [] }, opaque_types: [(OpaqueTypeKey { def_id: DefId(0:8 ~ playground_proof_tree[b494]::Tait::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::IntoIter), (OpaqueTypeKey { def_id: DefId(0:9 ~ playground_proof_tree[b494]::Tait::{opaque#0}::{opaque#0}), substs: [] }, <^0 as std::iter::IntoIterator>::Item)] }, PrivateZst)) }, max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] })
```
</p>
</details>
16 files changed, 1299 insertions, 543 deletions
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 492b7228488..73959038582 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -981,7 +981,7 @@ pub enum CodegenObligationError { FulfillmentError, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum DefiningAnchor { /// `DefId` of the item. Bind(LocalDefId), @@ -991,3 +991,9 @@ pub enum DefiningAnchor { /// Used to catch type mismatch errors when handling opaque types. Error, } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] +pub enum IsNormalizesToHack { + Yes, + No, +} diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index eae5a280e11..60a38747fdf 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -92,7 +92,7 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; -#[derive(Copy, Clone, Debug, HashStable, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Hash, HashStable, PartialEq, Eq)] pub struct NoSolution; impl<'tcx> From<TypeError<'tcx>> for NoSolution { diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 2c5b64a59cd..af482a88960 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -11,6 +11,8 @@ use crate::ty::{ TypeVisitor, }; +pub mod inspect; + pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>; /// A goal is a statement, i.e. `predicate`, we want to prove @@ -18,7 +20,7 @@ pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>; /// /// Most of the time the `param_env` contains the `where`-bounds of the function /// we're currently typechecking while the `predicate` is some trait bound. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct Goal<'tcx, P> { pub predicate: P, pub param_env: ty::ParamEnv<'tcx>, @@ -39,7 +41,7 @@ impl<'tcx, P> Goal<'tcx, P> { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct Response<'tcx> { pub certainty: Certainty, pub var_values: CanonicalVarValues<'tcx>, @@ -47,7 +49,7 @@ pub struct Response<'tcx> { pub external_constraints: ExternalConstraints<'tcx>, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum Certainty { Yes, Maybe(MaybeCause), @@ -86,7 +88,7 @@ impl Certainty { } /// Why we failed to evaluate a goal. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum MaybeCause { /// We failed due to ambiguity. This ambiguity can either /// be a true ambiguity, i.e. there are multiple different answers, @@ -96,7 +98,7 @@ pub enum MaybeCause { Overflow, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct QueryInput<'tcx, T> { pub goal: Goal<'tcx, T>, pub anchor: DefiningAnchor, @@ -104,12 +106,12 @@ pub struct QueryInput<'tcx, T> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] pub struct PredefinedOpaquesData<'tcx> { pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>); impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { @@ -132,7 +134,7 @@ pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>; /// solver, merge the two responses again. pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>; -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { @@ -144,7 +146,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. pub region_constraints: QueryRegionConstraints<'tcx>, diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs new file mode 100644 index 00000000000..3cdf1ebbd05 --- /dev/null +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -0,0 +1,79 @@ +use super::{CanonicalInput, Certainty, Goal, NoSolution, QueryInput, QueryResult}; +use crate::{traits::IsNormalizesToHack, ty}; +use format::ProofTreeFormatter; +use std::fmt::{Debug, Write}; + +mod format; + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub enum CacheHit { + Provisional, + Global, +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct GoalEvaluation<'tcx> { + pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, + pub canonicalized_goal: CanonicalInput<'tcx>, + + pub kind: GoalEvaluationKind<'tcx>, + pub is_normalizes_to_hack: IsNormalizesToHack, + pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, + + pub result: QueryResult<'tcx>, +} +#[derive(Eq, PartialEq, Hash, HashStable)] +pub enum GoalEvaluationKind<'tcx> { + CacheHit(CacheHit), + Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> }, +} +impl Debug for GoalEvaluation<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_goal_evaluation(self) + } +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct AddedGoalsEvaluation<'tcx> { + pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>, + pub result: Result<Certainty, NoSolution>, +} +impl Debug for AddedGoalsEvaluation<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_nested_goal_evaluation(self) + } +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct GoalEvaluationStep<'tcx> { + pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, + + pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<GoalCandidate<'tcx>>, + + pub result: QueryResult<'tcx>, +} +impl Debug for GoalEvaluationStep<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_evaluation_step(self) + } +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct GoalCandidate<'tcx> { + pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<GoalCandidate<'tcx>>, + pub kind: CandidateKind<'tcx>, +} +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub enum CandidateKind<'tcx> { + /// Probe entered when normalizing the self ty during candidate assembly + NormalizedSelfTyAssembly, + /// A normal candidate for proving a goal + Candidate { name: String, result: QueryResult<'tcx> }, +} +impl Debug for GoalCandidate<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_candidate(self) + } +} diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs new file mode 100644 index 00000000000..2ee625674fa --- /dev/null +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -0,0 +1,131 @@ +use super::*; + +pub(super) struct ProofTreeFormatter<'a, 'b> { + pub(super) f: &'a mut (dyn Write + 'b), + pub(super) on_newline: bool, +} + +impl Write for ProofTreeFormatter<'_, '_> { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + for line in s.split_inclusive("\n") { + if self.on_newline { + self.f.write_str(" ")?; + } + self.on_newline = line.ends_with("\n"); + self.f.write_str(line)?; + } + + Ok(()) + } +} + +impl ProofTreeFormatter<'_, '_> { + fn nested(&mut self) -> ProofTreeFormatter<'_, '_> { + ProofTreeFormatter { f: self, on_newline: true } + } + + pub(super) fn format_goal_evaluation(&mut self, goal: &GoalEvaluation<'_>) -> std::fmt::Result { + let f = &mut *self.f; + + let goal_text = match goal.is_normalizes_to_hack { + IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL", + IsNormalizesToHack::No => "GOAL", + }; + + writeln!(f, "{}: {:?}", goal_text, goal.uncanonicalized_goal,)?; + writeln!(f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?; + + match &goal.kind { + GoalEvaluationKind::CacheHit(CacheHit::Global) => { + writeln!(f, "GLOBAL CACHE HIT: {:?}", goal.result) + } + GoalEvaluationKind::CacheHit(CacheHit::Provisional) => { + writeln!(f, "PROVISIONAL CACHE HIT: {:?}", goal.result) + } + GoalEvaluationKind::Uncached { revisions } => { + for (n, step) in revisions.iter().enumerate() { + let f = &mut *self.f; + writeln!(f, "REVISION {n}: {:?}", step.result)?; + let mut f = self.nested(); + f.format_evaluation_step(step)?; + } + + let f = &mut *self.f; + writeln!(f, "RESULT: {:?}", goal.result) + } + }?; + + if goal.returned_goals.len() > 0 { + let f = &mut *self.f; + writeln!(f, "NESTED GOALS ADDED TO CALLER: [")?; + let mut f = self.nested(); + for goal in goal.returned_goals.iter() { + writeln!(f, "ADDED GOAL: {:?},", goal)?; + } + writeln!(self.f, "]")?; + } + + Ok(()) + } + + pub(super) fn format_evaluation_step( + &mut self, + evaluation_step: &GoalEvaluationStep<'_>, + ) -> std::fmt::Result { + let f = &mut *self.f; + writeln!(f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?; + + for candidate in &evaluation_step.candidates { + let mut f = self.nested(); + f.format_candidate(candidate)?; + } + for nested_goal_evaluation in &evaluation_step.nested_goal_evaluations { + let mut f = self.nested(); + f.format_nested_goal_evaluation(nested_goal_evaluation)?; + } + + Ok(()) + } + + pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result { + let f = &mut *self.f; + + match &candidate.kind { + CandidateKind::NormalizedSelfTyAssembly => { + writeln!(f, "NORMALIZING SELF TY FOR ASSEMBLY:") + } + CandidateKind::Candidate { name, result } => { + writeln!(f, "CANDIDATE {}: {:?}", name, result) + } + }?; + + let mut f = self.nested(); + for candidate in &candidate.candidates { + f.format_candidate(candidate)?; + } + for nested_evaluations in &candidate.nested_goal_evaluations { + f.format_nested_goal_evaluation(nested_evaluations)?; + } + + Ok(()) + } + + pub(super) fn format_nested_goal_evaluation( + &mut self, + nested_goal_evaluation: &AddedGoalsEvaluation<'_>, + ) -> std::fmt::Result { + let f = &mut *self.f; + writeln!(f, "TRY_EVALUATE_ADDED_GOALS: {:?}", nested_goal_evaluation.result)?; + + for (n, revision) in nested_goal_evaluation.evaluations.iter().enumerate() { + let f = &mut *self.f; + writeln!(f, "REVISION {n}")?; + let mut f = self.nested(); + for goal_evaluation in revision { + f.format_goal_evaluation(goal_evaluation)?; + } + } + + Ok(()) + } +} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 3d9f0a4e268..edf95949d32 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1436,6 +1436,8 @@ options! { "output statistics about monomorphization collection"), dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED], "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"), + dump_solver_proof_tree: bool = (false, parse_bool, [UNTRACKED], + "dump a proof tree for every goal evaluated by the new trait solver"), dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED], "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), dylib_lto: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 66a4d36a1e5..1ceb77e9193 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -1,5 +1,6 @@ use super::{EvalCtxt, SolverMode}; use rustc_infer::traits::query::NoSolution; +use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_middle::ty; @@ -109,10 +110,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { direction: ty::AliasRelationDirection, invert: Invert, ) -> QueryResult<'tcx> { - self.probe(|ecx| { - ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + self.probe( + |ecx| { + ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "normalizes-to".into(), result: *r }, + ) } fn normalizes_to_inner( @@ -153,18 +157,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { alias_rhs: ty::AliasTy<'tcx>, direction: ty::AliasRelationDirection, ) -> QueryResult<'tcx> { - self.probe(|ecx| { - match direction { - ty::AliasRelationDirection::Equate => { - ecx.eq(param_env, alias_lhs, alias_rhs)?; - } - ty::AliasRelationDirection::Subtype => { - ecx.sub(param_env, alias_lhs, alias_rhs)?; + self.probe( + |ecx| { + match direction { + ty::AliasRelationDirection::Equate => { + ecx.eq(param_env, alias_lhs, alias_rhs)?; + } + ty::AliasRelationDirection::Subtype => { + ecx.sub(param_env, alias_lhs, alias_rhs)?; + } } - } - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "substs relate".into(), result: *r }, + ) } fn assemble_bidirectional_normalizes_to_candidate( @@ -174,22 +181,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { rhs: ty::Term<'tcx>, direction: ty::AliasRelationDirection, ) -> QueryResult<'tcx> { - self.probe(|ecx| { - ecx.normalizes_to_inner( - param_env, - lhs.to_alias_ty(ecx.tcx()).unwrap(), - rhs, - direction, - Invert::No, - )?; - ecx.normalizes_to_inner( - param_env, - rhs.to_alias_ty(ecx.tcx()).unwrap(), - lhs, - direction, - Invert::Yes, - )?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + self.probe( + |ecx| { + ecx.normalizes_to_inner( + param_env, + lhs.to_alias_ty(ecx.tcx()).unwrap(), + rhs, + direction, + Invert::No, + )?; + ecx.normalizes_to_inner( + param_env, + rhs.to_alias_ty(ecx.tcx()).unwrap(), + lhs, + direction, + Invert::Yes, + )?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "bidir normalizes-to".into(), result: *r }, + ) } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 543611daae8..d9bc8d3b1eb 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::elaborate; use rustc_infer::traits::Reveal; +use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult}; use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::TypeFoldable; @@ -336,37 +337,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return }; - let normalized_self_candidates: Result<_, NoSolution> = self.probe(|ecx| { - ecx.with_incremented_depth( - |ecx| { - let result = ecx.evaluate_added_goals_and_make_canonical_response( - Certainty::Maybe(MaybeCause::Overflow), - )?; - Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }]) - }, - |ecx| { - let normalized_ty = ecx.next_ty_infer(); - let normalizes_to_goal = goal.with( - tcx, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty, - term: normalized_ty.into(), - }), - ); - ecx.add_goal(normalizes_to_goal); - let _ = ecx.try_evaluate_added_goals().inspect_err(|_| { - debug!("self type normalization failed"); - })?; - let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); - debug!(?normalized_ty, "self type normalized"); - // NOTE: Alternatively we could call `evaluate_goal` here and only - // have a `Normalized` candidate. This doesn't work as long as we - // use `CandidateSource` in winnowing. - let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - Ok(ecx.assemble_and_evaluate_candidates(goal)) - }, - ) - }); + let normalized_self_candidates: Result<_, NoSolution> = self.probe( + |ecx| { + ecx.with_incremented_depth( + |ecx| { + let result = ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::Maybe(MaybeCause::Overflow), + )?; + Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }]) + }, + |ecx| { + let normalized_ty = ecx.next_ty_infer(); + let normalizes_to_goal = goal.with( + tcx, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty, + term: normalized_ty.into(), + }), + ); + ecx.add_goal(normalizes_to_goal); + let _ = ecx.try_evaluate_added_goals().inspect_err(|_| { + debug!("self type normalization failed"); + })?; + let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); + debug!(?normalized_ty, "self type normalized"); + // NOTE: Alternatively we could call `evaluate_goal` here and only + // have a `Normalized` candidate. This doesn't work as long as we + // use `CandidateSource` in winnowing. + let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); + Ok(ecx.assemble_and_evaluate_candidates(goal)) + }, + ) + }, + |_| CandidateKind::NormalizedSelfTyAssembly, + ); if let Ok(normalized_self_candidates) = normalized_self_candidates { candidates.extend(normalized_self_candidates); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 8625958ff5a..4258f9f6bd2 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -9,11 +9,12 @@ use rustc_infer::infer::{ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::traits::solve::inspect::{self, CandidateKind}; use rustc_middle::traits::solve::{ CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques, PredefinedOpaquesData, QueryResult, }; -use rustc_middle::traits::DefiningAnchor; +use rustc_middle::traits::{DefiningAnchor, IsNormalizesToHack}; use rustc_middle::ty::{ self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -23,6 +24,7 @@ use std::ops::ControlFlow; use crate::traits::specialization_graph; +use super::inspect::ProofTreeBuilder; use super::search_graph::{self, OverflowHandler}; use super::SolverMode; use super::{search_graph::SearchGraph, Goal}; @@ -73,12 +75,8 @@ pub struct EvalCtxt<'a, 'tcx> { // ambiguous goals. Instead, a probe needs to be introduced somewhere in the // evaluation code. tainted: Result<(), NoSolution>, -} -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub(super) enum IsNormalizesToHack { - Yes, - No, + inspect: ProofTreeBuilder<'tcx>, } #[derive(Debug, Clone)] @@ -110,6 +108,12 @@ impl NestedGoals<'_> { } } +#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] +pub enum GenerateProofTree { + Yes, + No, +} + pub trait InferCtxtEvalExt<'tcx> { /// Evaluates a goal from **outside** of the trait solver. /// @@ -118,7 +122,11 @@ pub trait InferCtxtEvalExt<'tcx> { fn evaluate_root_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>; + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>, + Option<inspect::GoalEvaluation<'tcx>>, + ); } impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { @@ -126,7 +134,11 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { fn evaluate_root_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>, + Option<inspect::GoalEvaluation<'tcx>>, + ) { let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode); @@ -143,16 +155,26 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { var_values: CanonicalVarValues::dummy(), nested_goals: NestedGoals::new(), tainted: Ok(()), + inspect: (self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree + || matches!(generate_proof_tree, GenerateProofTree::Yes)) + .then(ProofTreeBuilder::new_root) + .unwrap_or_else(ProofTreeBuilder::new_noop), }; let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal); + let tree = ecx.inspect.finalize(); + if let Some(tree) = &tree { + // module to allow more granular RUSTC_LOG filtering to just proof tree output + super::inspect::dump::print_tree(tree); + } + assert!( ecx.nested_goals.is_empty(), "root `EvalCtxt` should not have any goals added to it" ); assert!(search_graph.is_empty()); - result + (result, tree) } } @@ -170,58 +192,72 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're /// outside of it. - #[instrument(level = "debug", skip(tcx, search_graph), ret)] + #[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)] fn evaluate_canonical_goal( tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph<'tcx>, canonical_input: CanonicalInput<'tcx>, + mut goal_evaluation: &mut ProofTreeBuilder<'tcx>, ) -> QueryResult<'tcx> { + goal_evaluation.canonicalized_goal(canonical_input); + // Deal with overflow, caching, and coinduction. // // The actual solver logic happens in `ecx.compute_goal`. - search_graph.with_new_goal(tcx, canonical_input, |search_graph| { - let intercrate = match search_graph.solver_mode() { - SolverMode::Normal => false, - SolverMode::Coherence => true, - }; - let (ref infcx, input, var_values) = tcx - .infer_ctxt() - .intercrate(intercrate) - .with_next_trait_solver(true) - .with_opaque_type_inference(canonical_input.value.anchor) - .build_with_canonical(DUMMY_SP, &canonical_input); - - let mut ecx = EvalCtxt { - infcx, - var_values, - predefined_opaques_in_body: input.predefined_opaques_in_body, - max_input_universe: canonical_input.max_universe, - search_graph, - nested_goals: NestedGoals::new(), - tainted: Ok(()), - }; - - for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { - ecx.insert_hidden_type(key, input.goal.param_env, ty) - .expect("failed to prepopulate opaque types"); - } + search_graph.with_new_goal( + tcx, + canonical_input, + goal_evaluation, + |search_graph, goal_evaluation| { + let intercrate = match search_graph.solver_mode() { + SolverMode::Normal => false, + SolverMode::Coherence => true, + }; + let (ref infcx, input, var_values) = tcx + .infer_ctxt() + .intercrate(intercrate) + .with_next_trait_solver(true) + .with_opaque_type_inference(canonical_input.value.anchor) + .build_with_canonical(DUMMY_SP, &canonical_input); + + let mut ecx = EvalCtxt { + infcx, + var_values, + predefined_opaques_in_body: input.predefined_opaques_in_body, + max_input_universe: canonical_input.max_universe, + search_graph, + nested_goals: NestedGoals::new(), + tainted: Ok(()), + inspect: goal_evaluation.new_goal_evaluation_step(input), + }; + + for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { + ecx.insert_hidden_type(key, input.goal.param_env, ty) + .expect("failed to prepopulate opaque types"); + } - if !ecx.nested_goals.is_empty() { - panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals); - } + if !ecx.nested_goals.is_empty() { + panic!( + "prepopulating opaque types shouldn't add goals: {:?}", + ecx.nested_goals + ); + } - let result = ecx.compute_goal(input.goal); + let result = ecx.compute_goal(input.goal); + ecx.inspect.query_result(result); + goal_evaluation.goal_evaluation_step(ecx.inspect); - // When creating a query response we clone the opaque type constraints - // instead of taking them. This would cause an ICE here, since we have - // assertions against dropping an `InferCtxt` without taking opaques. - // FIXME: Once we remove support for the old impl we can remove this. - if input.anchor != DefiningAnchor::Error { - let _ = infcx.take_opaque_types(); - } + // When creating a query response we clone the opaque type constraints + // instead of taking them. This would cause an ICE here, since we have + // assertions against dropping an `InferCtxt` without taking opaques. + // FIXME: Once we remove support for the old impl we can remove this. + if input.anchor != DefiningAnchor::Error { + let _ = infcx.take_opaque_types(); + } - result - }) + result + }, + ) } /// Recursively evaluates `goal`, returning whether any inference vars have @@ -232,16 +268,37 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); - let canonical_response = - EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; + let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, is_normalizes_to_hack); + let canonical_response = EvalCtxt::evaluate_canonical_goal( + self.tcx(), + self.search_graph, + canonical_goal, + &mut goal_evaluation, + ); + goal_evaluation.query_result(canonical_response); + let canonical_response = match canonical_response { + Err(e) => { + self.inspect.goal_evaluation(goal_evaluation); + return Err(e); + } + Ok(response) => response, + }; let has_changed = !canonical_response.value.var_values.is_identity() || !canonical_response.value.external_constraints.opaque_types.is_empty(); - let (certainty, nested_goals) = self.instantiate_and_apply_query_response( + let (certainty, nested_goals) = match self.instantiate_and_apply_query_response( goal.param_env, orig_values, canonical_response, - )?; + ) { + Err(e) => { + self.inspect.goal_evaluation(goal_evaluation); + return Err(e); + } + Ok(response) => response, + }; + goal_evaluation.returned_goals(&nested_goals); + self.inspect.goal_evaluation(goal_evaluation); if !has_changed && !nested_goals.is_empty() { bug!("an unchanged goal shouldn't have any side-effects on instantiation"); @@ -261,8 +318,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { { debug!("rerunning goal to check result is stable"); let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); - let new_canonical_response = - EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; + let new_canonical_response = EvalCtxt::evaluate_canonical_goal( + self.tcx(), + self.search_graph, + canonical_goal, + // FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal` + &mut ProofTreeBuilder::new_noop(), + )?; // We only check for modulo regions as we convert all regions in // the input to new existentials, even if they're expected to be // `'static` or a placeholder region. @@ -353,12 +415,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // the certainty of all the goals. #[instrument(level = "debug", skip(self))] pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> { + let inspect = self.inspect.new_evaluate_added_goals(); + let inspect = core::mem::replace(&mut self.inspect, inspect); + let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); let mut new_goals = NestedGoals::new(); let response = self.repeat_while_none( |_| Ok(Certainty::Maybe(MaybeCause::Overflow)), |this| { + this.inspect.evaluate_added_goals_loop_start(); + let mut has_changed = Err(Certainty::Yes); if let Some(goal) = goals.normalizes_to_hack_goal.take() { @@ -447,17 +514,28 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }, ); + self.inspect.eval_added_goals_result(response); + if response.is_err() { self.tainted = Err(NoSolution); } + let goal_evaluations = std::mem::replace(&mut self.inspect, inspect); + self.inspect.added_goals_evaluation(goal_evaluations); + self.nested_goals = goals; response } } impl<'tcx> EvalCtxt<'_, 'tcx> { - pub(super) fn probe<T>(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T { + /// `probe_kind` is only called when proof tree building is enabled so it can be + /// as expensive as necessary to output the desired information. + pub(super) fn probe<T>( + &mut self, + f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T, + probe_kind: impl FnOnce(&T) -> CandidateKind<'tcx>, + ) -> T { let mut ecx = EvalCtxt { infcx: self.infcx, var_values: self.var_values, @@ -466,8 +544,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { search_graph: self.search_graph, nested_goals: self.nested_goals.clone(), tainted: self.tainted, + inspect: self.inspect.new_goal_candidate(), }; - self.infcx.probe(|_| f(&mut ecx)) + let r = self.infcx.probe(|_| f(&mut ecx)); + if !self.inspect.is_noop() { + let cand_kind = probe_kind(&r); + ecx.inspect.candidate_kind(cand_kind); + self.inspect.goal_candidate(ecx.inspect); + } + r } pub(super) fn tcx(&self) -> TyCtxt<'tcx> { @@ -781,14 +866,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if candidate_key.def_id != key.def_id { continue; } - values.extend(self.probe(|ecx| { - for (a, b) in std::iter::zip(candidate_key.substs, key.substs) { - ecx.eq(param_env, a, b)?; - } - ecx.eq(param_env, candidate_ty, ty)?; - ecx.add_item_bounds_for_hidden_type(candidate_key, param_env, candidate_ty); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - })); + values.extend(self.probe( + |ecx| { + for (a, b) in std::iter::zip(candidate_key.substs, key.substs) { + ecx.eq(param_env, a, b)?; + } + ecx.eq(param_env, candidate_ty, ty)?; + ecx.add_item_bounds_for_hidden_type(candidate_key, param_env, candidate_ty); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "opaque type storage".into(), result: *r }, + )); } values } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 65c8d9c8f69..0e671144a29 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -10,6 +10,7 @@ use rustc_infer::traits::{ use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use super::eval_ctxt::GenerateProofTree; use super::{Certainty, InferCtxtEvalExt}; /// A trait engine using the new trait solver. @@ -46,8 +47,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { self.obligations .drain(..) .map(|obligation| { - let code = - infcx.probe(|_| match infcx.evaluate_root_goal(obligation.clone().into()) { + let code = infcx.probe(|_| { + match infcx + .evaluate_root_goal(obligation.clone().into(), GenerateProofTree::No) + .0 + { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => { FulfillmentErrorCode::CodeAmbiguity { overflow: false } } @@ -60,7 +64,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { Err(_) => { bug!("did not expect selection error when collecting ambiguity errors") } - }); + } + }); FulfillmentError { obligation: obligation.clone(), @@ -81,61 +86,62 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - let (changed, certainty, nested_goals) = match infcx.evaluate_root_goal(goal) { - Ok(result) => result, - Err(NoSolution) => { - errors.push(FulfillmentError { - obligation: obligation.clone(), - code: match goal.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(_)) => { - FulfillmentErrorCode::CodeProjectionError( - // FIXME: This could be a `Sorts` if the term is a type - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::AliasRelate(_, _, _) => { - FulfillmentErrorCode::CodeProjectionError( - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(true, a, b); - FulfillmentErrorCode::CodeSubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(false, a, b); - FulfillmentErrorCode::CodeSubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Clause(_) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(_, _, _) - | ty::PredicateKind::Ambiguous => { - FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ) - } - ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(_) => { - bug!("unexpected goal: {goal:?}") - } - }, - root_obligation: obligation, - }); - continue; - } - }; + let (changed, certainty, nested_goals) = + match infcx.evaluate_root_goal(goal, GenerateProofTree::No).0 { + Ok(result) => result, + Err(NoSolution) => { + errors.push(FulfillmentError { + obligation: obligation.clone(), + code: match goal.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::Clause::Projection(_)) => { + FulfillmentErrorCode::CodeProjectionError( + // FIXME: This could be a `Sorts` if the term is a type + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::AliasRelate(_, _, _) => { + FulfillmentErrorCode::CodeProjectionError( + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::Subtype(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(true, a, b); + FulfillmentErrorCode::CodeSubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Coerce(pred) => { + let (a, b) = infcx.instantiate_binder_with_placeholders( + goal.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(false, a, b); + FulfillmentErrorCode::CodeSubtypeError( + expected_found, + TypeError::Sorts(expected_found), + ) + } + ty::PredicateKind::Clause(_) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::ClosureKind(_, _, _) + | ty::PredicateKind::Ambiguous => { + FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ) + } + ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(_) => { + bug!("unexpected goal: {goal:?}") + } + }, + root_obligation: obligation, + }); + continue; + } + }; // Push any nested goals that we get from unifying our canonical response // with our obligation onto the fulfillment context. self.obligations.extend(nested_goals.into_iter().map(|goal| { diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs new file mode 100644 index 00000000000..c3dea5f790a --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -0,0 +1,367 @@ +use rustc_middle::{ + traits::{ + query::NoSolution, + solve::{ + inspect::{self, CacheHit, CandidateKind}, + CanonicalInput, Certainty, Goal, QueryInput, QueryResult, + }, + IsNormalizesToHack, + }, + ty, +}; + +pub mod dump; + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub struct WipGoalEvaluation<'tcx> { + pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, + pub canonicalized_goal: Option<CanonicalInput<'tcx>>, + + pub evaluation_steps: Vec<WipGoalEvaluationStep<'tcx>>, + + pub cache_hit: Option<CacheHit>, + pub is_normalizes_to_hack: IsNormalizesToHack, + pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, + + pub result: Option<QueryResult<'tcx>>, +} +impl<'tcx> WipGoalEvaluation<'tcx> { + pub fn finalize(self) -> inspect::GoalEvaluation<'tcx> { + inspect::GoalEvaluation { + uncanonicalized_goal: self.uncanonicalized_goal, + canonicalized_goal: self.canonicalized_goal.unwrap(), + kind: match self.cache_hit { + Some(hit) => inspect::GoalEvaluationKind::CacheHit(hit), + None => inspect::GoalEvaluationKind::Uncached { + revisions: self + .evaluation_steps + .into_iter() + .map(WipGoalEvaluationStep::finalize) + .collect(), + }, + }, + is_normalizes_to_hack: self.is_normalizes_to_hack, + returned_goals: self.returned_goals, + result: self.result.unwrap(), + } + } +} + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub struct WipAddedGoalsEvaluation<'tcx> { + pub evaluations: Vec<Vec<WipGoalEvaluation<'tcx>>>, + pub result: Option<Result<Certainty, NoSolution>>, +} +impl<'tcx> WipAddedGoalsEvaluation<'tcx> { + pub fn finalize(self) -> inspect::AddedGoalsEvaluation<'tcx> { + inspect::AddedGoalsEvaluation { + evaluations: self + .evaluations + .into_iter() + .map(|evaluations| { + evaluations.into_iter().map(WipGoalEvaluation::finalize).collect() + }) + .collect(), + result: self.result.unwrap(), + } + } +} + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub struct WipGoalEvaluationStep<'tcx> { + pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, + + pub nested_goal_evaluations: Vec<WipAddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<WipGoalCandidate<'tcx>>, + + pub result: Option<QueryResult<'tcx>>, +} +impl<'tcx> WipGoalEvaluationStep<'tcx> { + pub fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> { + inspect::GoalEvaluationStep { + instantiated_goal: self.instantiated_goal, + nested_goal_evaluations: self + .nested_goal_evaluations + .into_iter() + .map(WipAddedGoalsEvaluation::finalize) + .collect(), + candidates: self.candidates.into_iter().map(WipGoalCandidate::finalize).collect(), + result: self.result.unwrap(), + } + } +} + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub struct WipGoalCandidate<'tcx> { + pub nested_goal_evaluations: Vec<WipAddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<WipGoalCandidate<'tcx>>, + pub kind: Option<CandidateKind<'tcx>>, +} +impl<'tcx> WipGoalCandidate<'tcx> { + pub fn finalize(self) -> inspect::GoalCandidate<'tcx> { + inspect::GoalCandidate { + nested_goal_evaluations: self + .nested_goal_evaluations + .into_iter() + .map(WipAddedGoalsEvaluation::finalize) + .collect(), + candidates: self.candidates.into_iter().map(WipGoalCandidate::finalize).collect(), + kind: self.kind.unwrap(), + } + } +} + +#[derive(Debug)] +pub enum DebugSolver<'tcx> { + Root, + GoalEvaluation(WipGoalEvaluation<'tcx>), + AddedGoalsEvaluation(WipAddedGoalsEvaluation<'tcx>), + GoalEvaluationStep(WipGoalEvaluationStep<'tcx>), + GoalCandidate(WipGoalCandidate<'tcx>), +} + +pub struct ProofTreeBuilder<'tcx>(Option<Box<DebugSolver<'tcx>>>); +impl<'tcx> ProofTreeBuilder<'tcx> { + pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> { + match *(self.0?) { + DebugSolver::GoalEvaluation(wip_goal_evaluation) => { + Some(wip_goal_evaluation.finalize()) + } + root => unreachable!("unexpected proof tree builder root node: {:?}", root), + } + } + + pub fn new_root() -> ProofTreeBuilder<'tcx> { + Self(Some(Box::new(DebugSolver::Root))) + } + + pub fn new_noop() -> ProofTreeBuilder<'tcx> { + Self(None) + } + + pub fn is_noop(&self) -> bool { + self.0.is_none() + } + + pub fn new_goal_evaluation( + &mut self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + is_normalizes_to_hack: IsNormalizesToHack, + ) -> ProofTreeBuilder<'tcx> { + if self.0.is_none() { + return ProofTreeBuilder(None); + } + + Self(Some(Box::new(DebugSolver::GoalEvaluation(WipGoalEvaluation { + uncanonicalized_goal: goal, + canonicalized_goal: None, + evaluation_steps: vec![], + is_normalizes_to_hack, + cache_hit: None, + returned_goals: vec![], + result: None, + })))) + } + pub fn canonicalized_goal(&mut self, canonical_goal: CanonicalInput<'tcx>) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match this { + DebugSolver::GoalEvaluation(goal_evaluation) => { + assert!(goal_evaluation.canonicalized_goal.is_none()); + goal_evaluation.canonicalized_goal = Some(canonical_goal) + } + _ => unreachable!(), + } + } + pub fn cache_hit(&mut self, cache_hit: CacheHit) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match this { + DebugSolver::GoalEvaluation(goal_evaluation) => { + goal_evaluation.cache_hit = Some(cache_hit) + } + _ => unreachable!(), + }; + } + pub fn returned_goals(&mut self, goals: &[Goal<'tcx, ty::Predicate<'tcx>>]) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match this { + DebugSolver::GoalEvaluation(evaluation) => { + assert!(evaluation.returned_goals.is_empty()); + evaluation.returned_goals.extend(goals); + } + _ => unreachable!(), + } + } + pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match (this, *goal_evaluation.0.unwrap()) { + ( + DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { evaluations, .. }), + DebugSolver::GoalEvaluation(goal_evaluation), + ) => evaluations.last_mut().unwrap().push(goal_evaluation), + (this @ DebugSolver::Root, goal_evaluation) => *this = goal_evaluation, + _ => unreachable!(), + } + } + + pub fn new_goal_evaluation_step( + &mut self, + instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, + ) -> ProofTreeBuilder<'tcx> { + if self.0.is_none() { + return Self(None); + } + + Self(Some(Box::new(DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { + instantiated_goal, + nested_goal_evaluations: vec![], + candidates: vec![], + result: None, + })))) + } + pub fn goal_evaluation_step(&mut self, goal_eval_step: ProofTreeBuilder<'tcx>) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match (this, *goal_eval_step.0.unwrap()) { + (DebugSolver::GoalEvaluation(goal_eval), DebugSolver::GoalEvaluationStep(step)) => { + goal_eval.evaluation_steps.push(step); + } + _ => unreachable!(), + } + } + + pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> { + if self.0.is_none() { + return Self(None); + } + + Self(Some(Box::new(DebugSolver::GoalCandidate(WipGoalCandidate { + nested_goal_evaluations: vec![], + candidates: vec![], + kind: None, + })))) + } + pub fn candidate_kind(&mut self, kind: CandidateKind<'tcx>) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match this { + DebugSolver::GoalCandidate(WipGoalCandidate { kind: old_kind @ None, .. }) => { + *old_kind = Some(kind) + } + _ => unreachable!(), + } + } + pub fn goal_candidate(&mut self, candidate: ProofTreeBuilder<'tcx>) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match (this, *candidate.0.unwrap()) { + ( + DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. }) + | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { candidates, .. }), + DebugSolver::GoalCandidate(candidate), + ) => candidates.push(candidate), + _ => unreachable!(), + } + } + + pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> { + if self.0.is_none() { + return Self(None); + } + + Self(Some(Box::new(DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { + evaluations: vec![], + result: None, + })))) + } + pub fn evaluate_added_goals_loop_start(&mut self) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match this { + DebugSolver::AddedGoalsEvaluation(this) => { + this.evaluations.push(vec![]); + } + _ => unreachable!(), + } + } + pub fn eval_added_goals_result(&mut self, result: Result<Certainty, NoSolution>) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match this { + DebugSolver::AddedGoalsEvaluation(this) => { + assert!(this.result.is_none()); + this.result = Some(result); + } + _ => unreachable!(), + } + } + pub fn added_goals_evaluation(&mut self, goals_evaluation: ProofTreeBuilder<'tcx>) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match (this, *goals_evaluation.0.unwrap()) { + ( + DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { + nested_goal_evaluations, + .. + }) + | DebugSolver::GoalCandidate(WipGoalCandidate { nested_goal_evaluations, .. }), + DebugSolver::AddedGoalsEvaluation(added_goals_evaluation), + ) => nested_goal_evaluations.push(added_goals_evaluation), + _ => unreachable!(), + } + } + + pub fn query_result(&mut self, result: QueryResult<'tcx>) { + let this = match self.0.as_mut() { + None => return, + Some(this) => &mut **this, + }; + + match this { + DebugSolver::GoalEvaluation(goal_evaluation) => { + assert!(goal_evaluation.result.is_none()); + goal_evaluation.result = Some(result); + } + DebugSolver::Root + | DebugSolver::AddedGoalsEvaluation(_) + | DebugSolver::GoalCandidate(_) => unreachable!(), + DebugSolver::GoalEvaluationStep(evaluation_step) => { + assert!(evaluation_step.result.is_none()); + evaluation_step.result = Some(result); + } + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/dump.rs b/compiler/rustc_trait_selection/src/solve/inspect/dump.rs new file mode 100644 index 00000000000..b755ee86215 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/inspect/dump.rs @@ -0,0 +1,5 @@ +use rustc_middle::traits::solve::inspect::GoalEvaluation; + +pub fn print_tree(tree: &GoalEvaluation<'_>) { + debug!(?tree); +} diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index a30a14df80b..49fecedc0ca 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -25,6 +25,7 @@ mod assembly; mod canonicalize; mod eval_ctxt; mod fulfill; +pub mod inspect; mod opaques; mod project_goals; mod search_graph; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index e9600968f48..b99c3927862 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -9,6 +9,7 @@ use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; +use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::ProjectionPredicate; @@ -109,21 +110,30 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { - if let Some(projection_pred) = assumption.as_projection_clause() - && projection_pred.projection_def_id() == goal.predicate.def_id() - { - ecx.probe(|ecx| { - let assumption_projection_pred = - ecx.instantiate_binder_with_infer(projection_pred); - ecx.eq( - goal.param_env, - goal.predicate.projection_ty, - assumption_projection_pred.projection_ty, - )?; - ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term) - .expect("expected goal term to be fully unconstrained"); - then(ecx) - }) + if let Some(projection_pred) = assumption.as_projection_clause() { + if projection_pred.projection_def_id() == goal.predicate.def_id() { + ecx.probe( + |ecx| { + let assumption_projection_pred = + ecx.instantiate_binder_with_infer(projection_pred); + ecx.eq( + goal.param_env, + goal.predicate.projection_ty, + assumption_projection_pred.projection_ty, + )?; + ecx.eq( + goal.param_env, + goal.predicate.term, + assumption_projection_pred.term, + ) + .expect("expected goal term to be fully unconstrained"); + then(ecx) + }, + |r| CandidateKind::Candidate { name: "assumption".into(), result: *r }, + ) + } else { + Err(NoSolution) + } } else { Err(NoSolution) } @@ -143,87 +153,90 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { return Err(NoSolution); } - ecx.probe(|ecx| { - let impl_substs = ecx.fresh_substs_for_item(impl_def_id); - let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - - ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; - - let where_clause_bounds = tcx - .predicates_of(impl_def_id) - .instantiate(tcx, impl_substs) - .predicates - .into_iter() - .map(|pred| goal.with(tcx, pred)); - ecx.add_goals(where_clause_bounds); - - // In case the associated item is hidden due to specialization, we have to - // return ambiguity this would otherwise be incomplete, resulting in - // unsoundness during coherence (#105782). - let Some(assoc_def) = fetch_eligible_assoc_item_def( - ecx, - goal.param_env, - goal_trait_ref, - goal.predicate.def_id(), - impl_def_id - )? else { - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); - }; + ecx.probe( + |ecx| { + let impl_substs = ecx.fresh_substs_for_item(impl_def_id); + let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); + + ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; + + let where_clause_bounds = tcx + .predicates_of(impl_def_id) + .instantiate(tcx, impl_substs) + .predicates + .into_iter() + .map(|pred| goal.with(tcx, pred)); + ecx.add_goals(where_clause_bounds); + + // In case the associated item is hidden due to specialization, we have to + // return ambiguity this would otherwise be incomplete, resulting in + // unsoundness during coherence (#105782). + let Some(assoc_def) = fetch_eligible_assoc_item_def( + ecx, + goal.param_env, + goal_trait_ref, + goal.predicate.def_id(), + impl_def_id + )? else { + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + }; + + if !assoc_def.item.defaultness(tcx).has_value() { + let guar = tcx.sess.delay_span_bug( + tcx.def_span(assoc_def.item.def_id), + "missing value for assoc item in impl", + ); + let error_term = match assoc_def.item.kind { + ty::AssocKind::Const => tcx + .const_error( + tcx.type_of(goal.predicate.def_id()) + .subst(tcx, goal.predicate.projection_ty.substs), + guar, + ) + .into(), + ty::AssocKind::Type => tcx.ty_error(guar).into(), + ty::AssocKind::Fn => unreachable!(), + }; + ecx.eq(goal.param_env, goal.predicate.term, error_term) + .expect("expected goal term to be fully unconstrained"); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } - if !assoc_def.item.defaultness(tcx).has_value() { - let guar = tcx.sess.delay_span_bug( - tcx.def_span(assoc_def.item.def_id), - "missing value for assoc item in impl", + // Getting the right substitutions here is complex, e.g. given: + // - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>` + // - the applicable impl `impl<T> Trait<i32> for Vec<T>` + // - and the impl which defines `Assoc` being `impl<T, U> Trait<U> for Vec<T>` + // + // We first rebase the goal substs onto the impl, going from `[Vec<u32>, i32, u64]` + // to `[u32, u64]`. + // + // And then map these substs to the substs of the defining impl of `Assoc`, going + // from `[u32, u64]` to `[u32, i32, u64]`. + let impl_substs_with_gat = goal.predicate.projection_ty.substs.rebase_onto( + tcx, + goal_trait_ref.def_id, + impl_substs, + ); + let substs = ecx.translate_substs( + goal.param_env, + impl_def_id, + impl_substs_with_gat, + assoc_def.defining_node, ); - let error_term = match assoc_def.item.kind { - ty::AssocKind::Const => tcx - .const_error( - tcx.type_of(goal.predicate.def_id()) - .subst(tcx, goal.predicate.projection_ty.substs), - guar, - ) - .into(), - ty::AssocKind::Type => tcx.ty_error(guar).into(), - ty::AssocKind::Fn => unreachable!(), - }; - ecx.eq(goal.param_env, goal.predicate.term, error_term) - .expect("expected goal term to be fully unconstrained"); - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - } - // Getting the right substitutions here is complex, e.g. given: - // - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>` - // - the applicable impl `impl<T> Trait<i32> for Vec<T>` - // - and the impl which defines `Assoc` being `impl<T, U> Trait<U> for Vec<T>` - // - // We first rebase the goal substs onto the impl, going from `[Vec<u32>, i32, u64]` - // to `[u32, u64]`. - // - // And then map these substs to the substs of the defining impl of `Assoc`, going - // from `[u32, u64]` to `[u32, i32, u64]`. - let impl_substs_with_gat = goal.predicate.projection_ty.substs.rebase_onto( - tcx, - goal_trait_ref.def_id, - impl_substs, - ); - let substs = ecx.translate_substs( - goal.param_env, - impl_def_id, - impl_substs_with_gat, - assoc_def.defining_node, - ); - - // Finally we construct the actual value of the associated type. - let term = match assoc_def.item.kind { - ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), - ty::AssocKind::Const => bug!("associated const projection is not supported yet"), - ty::AssocKind::Fn => unreachable!("we should never project to a fn"), - }; + // Finally we construct the actual value of the associated type. + let term = match assoc_def.item.kind { + ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), + ty::AssocKind::Const => bug!("associated const projection is not supported yet"), + ty::AssocKind::Fn => unreachable!("we should never project to a fn"), + }; - ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs)) - .expect("expected goal term to be fully unconstrained"); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs)) + .expect("expected goal term to be fully unconstrained"); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "impl".into(), result: *r }, + ) } fn consider_auto_trait_candidate( @@ -318,53 +331,69 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - ecx.probe(|ecx| { - let metadata_ty = match goal.predicate.self_ty().kind() { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Array(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(..) - | ty::Closure(..) - | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::GeneratorWitnessMIR(..) - | ty::Never - | ty::Foreign(..) => tcx.types.unit, - - ty::Error(e) => tcx.ty_error(*e), - - ty::Str | ty::Slice(_) => tcx.types.usize, - - ty::Dynamic(_, _, _) => { - let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); - tcx.type_of(dyn_metadata) - .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) - } + ecx.probe( + |ecx| { + let metadata_ty = match goal.predicate.self_ty().kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Array(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Closure(..) + | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Never + | ty::Foreign(..) => tcx.types.unit, + + ty::Error(e) => tcx.ty_error(*e), + + ty::Str | ty::Slice(_) => tcx.types.usize, + + ty::Dynamic(_, _, _) => { + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + tcx.type_of(dyn_metadata) + .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) + } - ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { - // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. - let sized_predicate = ty::TraitRef::from_lang_item( - tcx, - LangItem::Sized, - DUMMY_SP, - [ty::GenericArg::from(goal.predicate.self_ty())], - ); - ecx.add_goal(goal.with(tcx, sized_predicate)); - tcx.types.unit - } + ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { + // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. + let sized_predicate = ty::TraitRef::from_lang_item( + tcx, + LangItem::Sized, + DUMMY_SP, + [ty::GenericArg::from(goal.predicate.self_ty())], + ); + ecx.add_goal(goal.with(tcx, sized_predicate)); + tcx.types.unit + } + + ty::Adt(def, substs) if def.is_struct() => { + match def.non_enum_variant().fields.raw.last() { + None => tcx.types.unit, + Some(field_def) => { + let self_ty = field_def.ty(tcx, substs); + ecx.add_goal(goal.with( + tcx, + ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), + )); + return ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::Yes, + ); + } + } + } + ty::Adt(_, _) => tcx.types.unit, - ty::Adt(def, substs) if def.is_struct() => { - match def.non_enum_variant().fields.raw.last() { + ty::Tuple(elements) => match elements.last() { None => tcx.types.unit, - Some(field_def) => { - let self_ty = field_def.ty(tcx, substs); + Some(&self_ty) => { ecx.add_goal(goal.with( tcx, ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), @@ -372,35 +401,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { return ecx .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } - } - } - ty::Adt(_, _) => tcx.types.unit, - - ty::Tuple(elements) => match elements.last() { - None => tcx.types.unit, - Some(&self_ty) => { - ecx.add_goal(goal.with( - tcx, - ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), - )); - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - } - }, - - ty::Infer( - ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), - ) - | ty::Bound(..) => bug!( - "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", - goal.predicate.self_ty() - ), - }; + }, + + ty::Infer( + ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), + ) + | ty::Bound(..) => bug!( + "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", + goal.predicate.self_ty() + ), + }; - ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into()) - .expect("expected goal term to be fully unconstrained"); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into()) + .expect("expected goal term to be fully unconstrained"); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "builtin pointee".into(), result: *r }, + ) } fn consider_builtin_future_candidate( @@ -535,11 +552,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ), }; - ecx.probe(|ecx| { - ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into()) - .expect("expected goal term to be fully unconstrained"); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.probe( + |ecx| { + ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into()) + .expect("expected goal term to be fully unconstrained"); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "builtin discriminant kind".into(), result: *r }, + ) } fn consider_builtin_destruct_candidate( diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 19e4b23009a..d167ee46b39 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -2,6 +2,7 @@ mod cache; mod overflow; pub(super) use overflow::OverflowHandler; +use rustc_middle::traits::solve::inspect::CacheHit; use self::cache::ProvisionalEntry; use cache::ProvisionalCache; @@ -12,6 +13,7 @@ use rustc_middle::traits::solve::{CanonicalInput, Certainty, MaybeCause, QueryRe use rustc_middle::ty::TyCtxt; use std::{collections::hash_map::Entry, mem}; +use super::inspect::ProofTreeBuilder; use super::SolverMode; rustc_index::newtype_index! { @@ -88,11 +90,12 @@ impl<'tcx> SearchGraph<'tcx> { /// Tries putting the new goal on the stack, returning an error if it is already cached. /// /// This correctly updates the provisional cache if there is a cycle. - #[instrument(level = "debug", skip(self, tcx), ret)] + #[instrument(level = "debug", skip(self, tcx, inspect), ret)] fn try_push_stack( &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput<'tcx>, + inspect: &mut ProofTreeBuilder<'tcx>, ) -> Result<(), QueryResult<'tcx>> { // Look at the provisional cache to check for cycles. let cache = &mut self.provisional_cache; @@ -119,6 +122,8 @@ impl<'tcx> SearchGraph<'tcx> { // Finally we can return either the provisional response for that goal if we have a // coinductive cycle or an ambiguous result if the cycle is inductive. Entry::Occupied(entry_index) => { + inspect.cache_hit(CacheHit::Provisional); + let entry_index = *entry_index.get(); let stack_depth = cache.depth(entry_index); @@ -205,16 +210,18 @@ impl<'tcx> SearchGraph<'tcx> { &mut self, tcx: TyCtxt<'tcx>, canonical_input: CanonicalInput<'tcx>, - mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>, + inspect: &mut ProofTreeBuilder<'tcx>, + mut loop_body: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { if self.should_use_global_cache() { if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_input, tcx) { debug!(?canonical_input, ?result, "cache hit"); + inspect.cache_hit(CacheHit::Global); return result; } } - match self.try_push_stack(tcx, canonical_input) { + match self.try_push_stack(tcx, canonical_input, inspect) { Ok(()) => {} // Our goal is already on the stack, eager return. Err(response) => return response, @@ -231,7 +238,7 @@ impl<'tcx> SearchGraph<'tcx> { result }, |this| { - let result = loop_body(this); + let result = loop_body(this, inspect); this.try_finalize_goal(canonical_input, result).then(|| result) }, ) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 279fc1229d4..d9f24455a81 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,6 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, Movability}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::supertraits; +use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; @@ -61,21 +62,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }, }; - ecx.probe(|ecx| { - let impl_substs = ecx.fresh_substs_for_item(impl_def_id); - let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - - ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; - let where_clause_bounds = tcx - .predicates_of(impl_def_id) - .instantiate(tcx, impl_substs) - .predicates - .into_iter() - .map(|pred| goal.with(tcx, pred)); - ecx.add_goals(where_clause_bounds); - - ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) - }) + ecx.probe( + |ecx| { + let impl_substs = ecx.fresh_substs_for_item(impl_def_id); + let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); + + ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; + let where_clause_bounds = tcx + .predicates_of(impl_def_id) + .instantiate(tcx, impl_substs) + .predicates + .into_iter() + .map(|pred| goal.with(tcx, pred)); + ecx.add_goals(where_clause_bounds); + + ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) + }, + |r| CandidateKind::Candidate { name: "impl".into(), result: *r }, + ) } fn probe_and_match_goal_against_assumption( @@ -84,21 +88,26 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { assumption: ty::Binder<'tcx, ty::Clause<'tcx>>, then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { - if let Some(trait_clause) = assumption.as_trait_clause() - && trait_clause.def_id() == goal.predicate.def_id() - && trait_clause.polarity() == goal.predicate.polarity - { - // FIXME: Constness - ecx.probe(|ecx| { - let assumption_trait_pred = - ecx.instantiate_binder_with_infer(trait_clause); - ecx.eq( - goal.param_env, - goal.predicate.trait_ref, - assumption_trait_pred.trait_ref, - )?; - then(ecx) - }) + if let Some(trait_clause) = assumption.as_trait_clause() { + if trait_clause.def_id() == goal.predicate.def_id() + && trait_clause.polarity() == goal.predicate.polarity + { + // FIXME: Constness + ecx.probe( + |ecx| { + let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause); + ecx.eq( + goal.param_env, + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, + )?; + then(ecx) + }, + |r| CandidateKind::Candidate { name: "assumption".into(), result: *r }, + ) + } else { + Err(NoSolution) + } } else { Err(NoSolution) } @@ -132,13 +141,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let tcx = ecx.tcx(); - ecx.probe(|ecx| { - let nested_obligations = tcx - .predicates_of(goal.predicate.def_id()) - .instantiate(tcx, goal.predicate.trait_ref.substs); - ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p))); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.probe( + |ecx| { + let nested_obligations = tcx + .predicates_of(goal.predicate.def_id()) + .instantiate(tcx, goal.predicate.trait_ref.substs); + ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p))); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "trait alias".into(), result: *r }, + ) } fn consider_builtin_sized_candidate( @@ -344,109 +356,116 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if b_ty.is_ty_var() { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } - ecx.probe(|ecx| { - match (a_ty.kind(), b_ty.kind()) { - // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b` - (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => { - // Dyn upcasting is handled separately, since due to upcasting, - // when there are two supertraits that differ by substs, we - // may return more than one query response. - Err(NoSolution) - } - // `T` -> `dyn Trait` unsizing - (_, &ty::Dynamic(data, region, ty::Dyn)) => { - // Can only unsize to an object-safe type - if data - .principal_def_id() - .is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) - { - return Err(NoSolution); + ecx.probe( + |ecx| { + match (a_ty.kind(), b_ty.kind()) { + // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b` + (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => { + // Dyn upcasting is handled separately, since due to upcasting, + // when there are two supertraits that differ by substs, we + // may return more than one query response. + Err(NoSolution) } - - let Some(sized_def_id) = tcx.lang_items().sized_trait() else { + // `T` -> `dyn Trait` unsizing + (_, &ty::Dynamic(data, region, ty::Dyn)) => { + // Can only unsize to an object-safe type + if data + .principal_def_id() + .is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) + { + return Err(NoSolution); + } + + let Some(sized_def_id) = tcx.lang_items().sized_trait() else { return Err(NoSolution); }; - // Check that the type implements all of the predicates of the def-id. - // (i.e. the principal, all of the associated types match, and any auto traits) - ecx.add_goals( - data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), - ); - // The type must be Sized to be unsized. - ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty]))); - // The type must outlive the lifetime of the `dyn` we're unsizing into. - ecx.add_goal( - goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // `[T; n]` -> `[T]` unsizing - (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { - // We just require that the element type stays the same - ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` - (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) - if a_def.is_struct() && a_def.did() == b_def.did() => - { - let unsizing_params = tcx.unsizing_params_for_adt(a_def.did()); - // We must be unsizing some type parameters. This also implies - // that the struct has a tail field. - if unsizing_params.is_empty() { - return Err(NoSolution); + // Check that the type implements all of the predicates of the def-id. + // (i.e. the principal, all of the associated types match, and any auto traits) + ecx.add_goals( + data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + ); + // The type must be Sized to be unsized. + ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty]))); + // The type must outlive the lifetime of the `dyn` we're unsizing into. + ecx.add_goal( + goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - - let tail_field = a_def - .non_enum_variant() - .fields - .raw - .last() - .expect("expected unsized ADT to have a tail field"); - let tail_field_ty = tcx.type_of(tail_field.did); - - let a_tail_ty = tail_field_ty.subst(tcx, a_substs); - let b_tail_ty = tail_field_ty.subst(tcx, b_substs); - - // Substitute just the unsizing params from B into A. The type after - // this substitution must be equal to B. This is so we don't unsize - // unrelated type parameters. - let new_a_substs = - tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| { - if unsizing_params.contains(i as u32) { b_substs[i] } else { a } - })); - let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs); - - // Finally, we require that `TailA: Unsize<TailB>` for the tail field - // types. - ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; - ecx.add_goal(goal.with( - tcx, - ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), - )); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>` - (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) - if a_tys.len() == b_tys.len() && !a_tys.is_empty() => - { - let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); - let b_last_ty = b_tys.last().unwrap(); - - // Substitute just the tail field of B., and require that they're equal. - let unsized_a_ty = - tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied()); - ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; - - // Similar to ADTs, require that the rest of the fields are equal. - ecx.add_goal(goal.with( - tcx, - ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]), - )); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + // `[T; n]` -> `[T]` unsizing + (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { + // We just require that the element type stays the same + ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` + (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) + if a_def.is_struct() && a_def.did() == b_def.did() => + { + let unsizing_params = tcx.unsizing_params_for_adt(a_def.did()); + // We must be unsizing some type parameters. This also implies + // that the struct has a tail field. + if unsizing_params.is_empty() { + return Err(NoSolution); + } + + let tail_field = a_def + .non_enum_variant() + .fields + .raw + .last() + .expect("expected unsized ADT to have a tail field"); + let tail_field_ty = tcx.type_of(tail_field.did); + + let a_tail_ty = tail_field_ty.subst(tcx, a_substs); + let b_tail_ty = tail_field_ty.subst(tcx, b_substs); + + // Substitute just the unsizing params from B into A. The type after + // this substitution must be equal to B. This is so we don't unsize + // unrelated type parameters. + let new_a_substs = + tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| { + if unsizing_params.contains(i as u32) { b_substs[i] } else { a } + })); + let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs); + + // Finally, we require that `TailA: Unsize<TailB>` for the tail field + // types. + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + ecx.add_goal(goal.with( + tcx, + ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>` + (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) + if a_tys.len() == b_tys.len() && !a_tys.is_empty() => + { + let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); + let b_last_ty = b_tys.last().unwrap(); + + // Substitute just the tail field of B., and require that they're equal. + let unsized_a_ty = + tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied()); + ecx.eq(goal.param_env, unsized_a_ty, b_ty)?; + + // Similar to ADTs, require that the rest of the fields are equal. + ecx.add_goal(goal.with( + tcx, + ty::TraitRef::new( + tcx, + goal.predicate.def_id(), + [*a_last_ty, *b_last_ty], + ), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + _ => Err(NoSolution), } - _ => Err(NoSolution), - } - }) + }, + |r| CandidateKind::Candidate { name: "builtin unsize".into(), result: *r }, + ) } fn consider_builtin_dyn_upcast_candidates( @@ -476,32 +495,38 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| { - ecx.probe(|ecx| -> Result<_, NoSolution> { - // Require that all of the trait predicates from A match B, except for - // the auto traits. We do this by constructing a new A type with B's - // auto traits, and equating these types. - let new_a_data = principal - .into_iter() - .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)) - .chain(a_data.iter().filter(|a| { - matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_)) - })) - .chain( - b_data - .auto_traits() - .map(ty::ExistentialPredicate::AutoTrait) - .map(ty::Binder::dummy), + ecx.probe( + |ecx| -> Result<_, NoSolution> { + // Require that all of the trait predicates from A match B, except for + // the auto traits. We do this by constructing a new A type with B's + // auto traits, and equating these types. + let new_a_data = principal + .into_iter() + .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)) + .chain(a_data.iter().filter(|a| { + matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_)) + })) + .chain( + b_data + .auto_traits() + .map(ty::ExistentialPredicate::AutoTrait) + .map(ty::Binder::dummy), + ); + let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data); + let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn); + + // We also require that A's lifetime outlives B's lifetime. + ecx.eq(goal.param_env, new_a_ty, b_ty)?; + ecx.add_goal( + goal.with( + tcx, + ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), + ), ); - let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data); - let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn); - - // We also require that A's lifetime outlives B's lifetime. - ecx.eq(goal.param_env, new_a_ty, b_ty)?; - ecx.add_goal( - goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))), - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "upcast dyn to principle".into(), result: *r }, + ) }; let mut responses = vec![]; @@ -698,20 +723,23 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>, ) -> QueryResult<'tcx> { - self.probe(|ecx| { - ecx.add_goals( - constituent_tys(ecx, goal.predicate.self_ty())? - .into_iter() - .map(|ty| { - goal.with( - ecx.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)), - ) - }) - .collect::<Vec<_>>(), - ); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) + self.probe( + |ecx| { + ecx.add_goals( + constituent_tys(ecx, goal.predicate.self_ty())? + .into_iter() + .map(|ty| { + goal.with( + ecx.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)), + ) + }) + .collect::<Vec<_>>(), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + |r| CandidateKind::Candidate { name: "constituent tys".into(), result: *r }, + ) } #[instrument(level = "debug", skip(self))] |
