Auto merge of #131422 - GnomedDev:smallvec-predicate-obligations, r=compiler-errors

Use `ThinVec` for PredicateObligation storage

~~I noticed while profiling clippy on a project that a large amount of time is being spent allocating `Vec`s for `PredicateObligation`, and the `Vec`s are often quite small. This is an attempt to optimise this by using SmallVec to avoid heap allocations for these common small Vecs.~~

This PR turns all the `Vec<PredicateObligation>` into a single type alias while avoiding referring to `Vec` around it, then swaps the type over to `ThinVec<PredicateObligation>` and fixes the fallout. This also contains an implementation of `ThinVec::extract_if`, copied from `Vec::extract_if` and currently being upstreamed to https://github.com/Gankra/thin-vec/pull/66.

This leads to a small (0.2-0.7%) performance gain in the latest perf run.
This commit is contained in:
bors 2024-10-16 04:06:14 +00:00
commit 9618da7c99
43 changed files with 414 additions and 255 deletions

View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "addr2line" name = "addr2line"
@ -3857,6 +3857,7 @@ dependencies = [
"rustc_target", "rustc_target",
"rustc_type_ir", "rustc_type_ir",
"smallvec", "smallvec",
"thin-vec",
"tracing", "tracing",
] ]
@ -4496,6 +4497,7 @@ dependencies = [
"rustc_transmute", "rustc_transmute",
"rustc_type_ir", "rustc_type_ir",
"smallvec", "smallvec",
"thin-vec",
"tracing", "tracing",
] ]
@ -4567,6 +4569,7 @@ dependencies = [
"rustc_span", "rustc_span",
"rustc_type_ir_macros", "rustc_type_ir_macros",
"smallvec", "smallvec",
"thin-vec",
"tracing", "tracing",
] ]

View File

@ -18,6 +18,7 @@ use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::{ use rustc_infer::infer::{
BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin,
}; };
use rustc_infer::traits::PredicateObligations;
use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*; use rustc_middle::mir::*;
@ -40,7 +41,6 @@ use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::{DUMMY_SP, Span}; use rustc_span::{DUMMY_SP, Span};
use rustc_target::abi::{FIRST_VARIANT, FieldIdx}; use rustc_target::abi::{FIRST_VARIANT, FieldIdx};
use rustc_trait_selection::traits::PredicateObligation;
use rustc_trait_selection::traits::query::type_op::custom::{ use rustc_trait_selection::traits::query::type_op::custom::{
CustomTypeOp, scrape_region_constraints, CustomTypeOp, scrape_region_constraints,
}; };
@ -2940,7 +2940,7 @@ impl NormalizeLocation for Location {
pub(super) struct InstantiateOpaqueType<'tcx> { pub(super) struct InstantiateOpaqueType<'tcx> {
pub base_universe: Option<ty::UniverseIndex>, pub base_universe: Option<ty::UniverseIndex>,
pub region_constraints: Option<RegionConstraintData<'tcx>>, pub region_constraints: Option<RegionConstraintData<'tcx>>,
pub obligations: Vec<PredicateObligation<'tcx>>, pub obligations: PredicateObligations<'tcx>,
} }
impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {

View File

@ -76,6 +76,7 @@ pub mod svh;
pub mod sync; pub mod sync;
pub mod tagged_ptr; pub mod tagged_ptr;
pub mod temp_dir; pub mod temp_dir;
pub mod thinvec;
pub mod transitive_relation; pub mod transitive_relation;
pub mod unhash; pub mod unhash;
pub mod unord; pub mod unord;

View File

@ -75,6 +75,7 @@ use std::fmt::Debug;
use std::hash; use std::hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use thin_vec::ThinVec;
use tracing::debug; use tracing::debug;
use crate::fx::{FxHashMap, FxHashSet}; use crate::fx::{FxHashMap, FxHashSet};
@ -141,7 +142,7 @@ pub trait ObligationProcessor {
#[derive(Debug)] #[derive(Debug)]
pub enum ProcessResult<O, E> { pub enum ProcessResult<O, E> {
Unchanged, Unchanged,
Changed(Vec<O>), Changed(ThinVec<O>),
Error(E), Error(E),
} }
@ -402,9 +403,10 @@ impl<O: ForestObligation> ObligationForest<O> {
} }
/// Returns the set of obligations that are in a pending state. /// Returns the set of obligations that are in a pending state.
pub fn map_pending_obligations<P, F>(&self, f: F) -> Vec<P> pub fn map_pending_obligations<P, F, R>(&self, f: F) -> R
where where
F: Fn(&O) -> P, F: Fn(&O) -> P,
R: FromIterator<P>,
{ {
self.nodes self.nodes
.iter() .iter()

View File

@ -1,5 +1,7 @@
use std::fmt; use std::fmt;
use thin_vec::thin_vec;
use super::*; use super::*;
impl<'a> super::ForestObligation for &'a str { impl<'a> super::ForestObligation for &'a str {
@ -101,9 +103,9 @@ fn push_pop() {
// |-> A.3 // |-> A.3
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), "A" => ProcessResult::Changed(thin_vec!["A.1", "A.2", "A.3"]),
"B" => ProcessResult::Error("B is for broken"), "B" => ProcessResult::Error("B is for broken"),
"C" => ProcessResult::Changed(vec![]), "C" => ProcessResult::Changed(thin_vec![]),
"A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -123,8 +125,8 @@ fn push_pop() {
|obligation| match *obligation { |obligation| match *obligation {
"A.1" => ProcessResult::Unchanged, "A.1" => ProcessResult::Unchanged,
"A.2" => ProcessResult::Unchanged, "A.2" => ProcessResult::Unchanged,
"A.3" => ProcessResult::Changed(vec!["A.3.i"]), "A.3" => ProcessResult::Changed(thin_vec!["A.3.i"]),
"D" => ProcessResult::Changed(vec!["D.1", "D.2"]), "D" => ProcessResult::Changed(thin_vec!["D.1", "D.2"]),
"A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged, "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -139,11 +141,11 @@ fn push_pop() {
// |-> D.2 |-> D.2.i // |-> D.2 |-> D.2.i
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A.1" => ProcessResult::Changed(vec![]), "A.1" => ProcessResult::Changed(thin_vec![]),
"A.2" => ProcessResult::Error("A is for apple"), "A.2" => ProcessResult::Error("A is for apple"),
"A.3.i" => ProcessResult::Changed(vec![]), "A.3.i" => ProcessResult::Changed(thin_vec![]),
"D.1" => ProcessResult::Changed(vec!["D.1.i"]), "D.1" => ProcessResult::Changed(thin_vec!["D.1.i"]),
"D.2" => ProcessResult::Changed(vec!["D.2.i"]), "D.2" => ProcessResult::Changed(thin_vec!["D.2.i"]),
"D.1.i" | "D.2.i" => ProcessResult::Unchanged, "D.1.i" | "D.2.i" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -158,7 +160,7 @@ fn push_pop() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"D.1.i" => ProcessResult::Error("D is for dumb"), "D.1.i" => ProcessResult::Error("D is for dumb"),
"D.2.i" => ProcessResult::Changed(vec![]), "D.2.i" => ProcessResult::Changed(thin_vec![]),
_ => panic!("unexpected obligation {:?}", obligation), _ => panic!("unexpected obligation {:?}", obligation),
}, },
|_| {}, |_| {},
@ -184,10 +186,10 @@ fn success_in_grandchildren() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), "A" => ProcessResult::Changed(thin_vec!["A.1", "A.2", "A.3"]),
"A.1" => ProcessResult::Changed(vec![]), "A.1" => ProcessResult::Changed(thin_vec![]),
"A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]), "A.2" => ProcessResult::Changed(thin_vec!["A.2.i", "A.2.ii"]),
"A.3" => ProcessResult::Changed(vec![]), "A.3" => ProcessResult::Changed(thin_vec![]),
"A.2.i" | "A.2.ii" => ProcessResult::Unchanged, "A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -201,7 +203,7 @@ fn success_in_grandchildren() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A.2.i" => ProcessResult::Unchanged, "A.2.i" => ProcessResult::Unchanged,
"A.2.ii" => ProcessResult::Changed(vec![]), "A.2.ii" => ProcessResult::Changed(thin_vec![]),
_ => unreachable!(), _ => unreachable!(),
}, },
|_| {}, |_| {},
@ -211,7 +213,7 @@ fn success_in_grandchildren() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]), "A.2.i" => ProcessResult::Changed(thin_vec!["A.2.i.a"]),
"A.2.i.a" => ProcessResult::Unchanged, "A.2.i.a" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -222,7 +224,7 @@ fn success_in_grandchildren() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A.2.i.a" => ProcessResult::Changed(vec![]), "A.2.i.a" => ProcessResult::Changed(thin_vec![]),
_ => unreachable!(), _ => unreachable!(),
}, },
|_| {}, |_| {},
@ -247,7 +249,7 @@ fn to_errors_no_throw() {
forest.register_obligation("A"); forest.register_obligation("A");
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), "A" => ProcessResult::Changed(thin_vec!["A.1", "A.2", "A.3"]),
"A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -269,7 +271,7 @@ fn diamond() {
forest.register_obligation("A"); forest.register_obligation("A");
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["A.1", "A.2"]), "A" => ProcessResult::Changed(thin_vec!["A.1", "A.2"]),
"A.1" | "A.2" => ProcessResult::Unchanged, "A.1" | "A.2" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -280,8 +282,8 @@ fn diamond() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A.1" => ProcessResult::Changed(vec!["D"]), "A.1" => ProcessResult::Changed(thin_vec!["D"]),
"A.2" => ProcessResult::Changed(vec!["D"]), "A.2" => ProcessResult::Changed(thin_vec!["D"]),
"D" => ProcessResult::Unchanged, "D" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -295,7 +297,7 @@ fn diamond() {
|obligation| match *obligation { |obligation| match *obligation {
"D" => { "D" => {
d_count += 1; d_count += 1;
ProcessResult::Changed(vec![]) ProcessResult::Changed(thin_vec![])
} }
_ => unreachable!(), _ => unreachable!(),
}, },
@ -313,7 +315,7 @@ fn diamond() {
forest.register_obligation("A'"); forest.register_obligation("A'");
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]), "A'" => ProcessResult::Changed(thin_vec!["A'.1", "A'.2"]),
"A'.1" | "A'.2" => ProcessResult::Unchanged, "A'.1" | "A'.2" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -324,8 +326,8 @@ fn diamond() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A'.1" => ProcessResult::Changed(vec!["D'", "A'"]), "A'.1" => ProcessResult::Changed(thin_vec!["D'", "A'"]),
"A'.2" => ProcessResult::Changed(vec!["D'"]), "A'.2" => ProcessResult::Changed(thin_vec!["D'"]),
"D'" | "A'" => ProcessResult::Unchanged, "D'" | "A'" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -366,7 +368,7 @@ fn done_dependency() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]), "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(thin_vec![]),
_ => unreachable!(), _ => unreachable!(),
}, },
|_| {}, |_| {},
@ -379,7 +381,9 @@ fn done_dependency() {
forest.register_obligation("(A,B,C): Sized"); forest.register_obligation("(A,B,C): Sized");
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"(A,B,C): Sized" => ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]), "(A,B,C): Sized" => {
ProcessResult::Changed(thin_vec!["A: Sized", "B: Sized", "C: Sized"])
}
_ => unreachable!(), _ => unreachable!(),
}, },
|_| {}, |_| {},
@ -399,10 +403,10 @@ fn orphan() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["D", "E"]), "A" => ProcessResult::Changed(thin_vec!["D", "E"]),
"B" => ProcessResult::Unchanged, "B" => ProcessResult::Unchanged,
"C1" => ProcessResult::Changed(vec![]), "C1" => ProcessResult::Changed(thin_vec![]),
"C2" => ProcessResult::Changed(vec![]), "C2" => ProcessResult::Changed(thin_vec![]),
"D" | "E" => ProcessResult::Unchanged, "D" | "E" => ProcessResult::Unchanged,
_ => unreachable!(), _ => unreachable!(),
}, },
@ -416,7 +420,7 @@ fn orphan() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"D" | "E" => ProcessResult::Unchanged, "D" | "E" => ProcessResult::Unchanged,
"B" => ProcessResult::Changed(vec!["D"]), "B" => ProcessResult::Changed(thin_vec!["D"]),
_ => unreachable!(), _ => unreachable!(),
}, },
|_| {}, |_| {},
@ -459,7 +463,7 @@ fn simultaneous_register_and_error() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A" => ProcessResult::Error("An error"), "A" => ProcessResult::Error("An error"),
"B" => ProcessResult::Changed(vec!["A"]), "B" => ProcessResult::Changed(thin_vec!["A"]),
_ => unreachable!(), _ => unreachable!(),
}, },
|_| {}, |_| {},
@ -474,7 +478,7 @@ fn simultaneous_register_and_error() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation { |obligation| match *obligation {
"A" => ProcessResult::Error("An error"), "A" => ProcessResult::Error("An error"),
"B" => ProcessResult::Changed(vec!["A"]), "B" => ProcessResult::Changed(thin_vec!["A"]),
_ => unreachable!(), _ => unreachable!(),
}, },
|_| {}, |_| {},

View File

@ -0,0 +1,92 @@
//! This is a copy-paste of `Vec::extract_if` for `ThinVec`.
//!
//! FIXME: <https://github.com/Gankra/thin-vec/pull/66> is merged, this can be removed.
use std::{ptr, slice};
use thin_vec::ThinVec;
/// An iterator for [`ThinVec`] which uses a closure to determine if an element should be removed.
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ExtractIf<'a, T, F> {
vec: &'a mut ThinVec<T>,
/// The index of the item that will be inspected by the next call to `next`.
idx: usize,
/// The number of items that have been drained (removed) thus far.
del: usize,
/// The original length of `vec` prior to draining.
old_len: usize,
/// The filter test predicate.
pred: F,
}
impl<'a, T, F> ExtractIf<'a, T, F>
where
F: FnMut(&mut T) -> bool,
{
pub fn new(vec: &'a mut ThinVec<T>, filter: F) -> Self {
let old_len = vec.len();
// Guard against us getting leaked (leak amplification)
unsafe {
vec.set_len(0);
}
ExtractIf { vec, idx: 0, del: 0, old_len, pred: filter }
}
}
impl<T, F> Iterator for ExtractIf<'_, T, F>
where
F: FnMut(&mut T) -> bool,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
while self.idx < self.old_len {
let i = self.idx;
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
let drained = (self.pred)(&mut v[i]);
// Update the index *after* the predicate is called. If the index
// is updated prior and the predicate panics, the element at this
// index would be leaked.
self.idx += 1;
if drained {
self.del += 1;
return Some(ptr::read(&v[i]));
} else if self.del > 0 {
let del = self.del;
let src: *const T = &v[i];
let dst: *mut T = &mut v[i - del];
ptr::copy_nonoverlapping(src, dst, 1);
}
}
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.old_len - self.idx))
}
}
impl<A, F> Drop for ExtractIf<'_, A, F> {
fn drop(&mut self) {
unsafe {
if self.idx < self.old_len && self.del > 0 {
// This is a pretty messed up state, and there isn't really an
// obviously right thing to do. We don't want to keep trying
// to execute `pred`, so we just backshift all the unprocessed
// elements and tell the vec that they still exist. The backshift
// is required to prevent a double-drop of the last successfully
// drained item prior to a panic in the predicate.
let ptr = self.vec.as_mut_ptr();
let src = ptr.add(self.idx);
let dst = src.sub(self.del);
let tail_len = self.old_len - self.idx;
src.copy_to(dst, tail_len);
}
self.vec.set_len(self.old_len - self.del);
}
}
}

View File

@ -1,4 +1,5 @@
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::PredicateObligations;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::Limit; use rustc_session::Limit;
use rustc_span::Span; use rustc_span::Span;
@ -23,7 +24,7 @@ struct AutoderefSnapshot<'tcx> {
reached_recursion_limit: bool, reached_recursion_limit: bool,
steps: Vec<(Ty<'tcx>, AutoderefKind)>, steps: Vec<(Ty<'tcx>, AutoderefKind)>,
cur_ty: Ty<'tcx>, cur_ty: Ty<'tcx>,
obligations: Vec<traits::PredicateObligation<'tcx>>, obligations: PredicateObligations<'tcx>,
} }
pub struct Autoderef<'a, 'tcx> { pub struct Autoderef<'a, 'tcx> {
@ -119,7 +120,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
state: AutoderefSnapshot { state: AutoderefSnapshot {
steps: vec![], steps: vec![],
cur_ty: infcx.resolve_vars_if_possible(base_ty), cur_ty: infcx.resolve_vars_if_possible(base_ty),
obligations: vec![], obligations: PredicateObligations::new(),
at_start: true, at_start: true,
reached_recursion_limit: false, reached_recursion_limit: false,
}, },
@ -165,7 +166,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
pub fn structurally_normalize( pub fn structurally_normalize(
&self, &self,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> { ) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> {
let ocx = ObligationCtxt::new(self.infcx); let ocx = ObligationCtxt::new(self.infcx);
let Ok(normalized_ty) = ocx.structurally_normalize( let Ok(normalized_ty) = ocx.structurally_normalize(
&traits::ObligationCause::misc(self.span, self.body_id), &traits::ObligationCause::misc(self.span, self.body_id),
@ -204,11 +205,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
self.state.steps.len() self.state.steps.len()
} }
pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> { pub fn into_obligations(self) -> PredicateObligations<'tcx> {
self.state.obligations self.state.obligations
} }
pub fn current_obligations(&self) -> Vec<traits::PredicateObligation<'tcx>> { pub fn current_obligations(&self) -> PredicateObligations<'tcx> {
self.state.obligations.clone() self.state.obligations.clone()
} }

View File

@ -5,6 +5,7 @@ use std::iter;
use itertools::Itertools; use itertools::Itertools;
use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind}; use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind};
use rustc_infer::infer::InferOk; use rustc_infer::infer::InferOk;
use rustc_infer::traits::PredicateObligations;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_span::Span; use rustc_span::Span;
@ -36,10 +37,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> { ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
let steps = autoderef.steps(); let steps = autoderef.steps();
if steps.is_empty() { if steps.is_empty() {
return InferOk { obligations: vec![], value: vec![] }; return InferOk { obligations: PredicateObligations::new(), value: vec![] };
} }
let mut obligations = vec![]; let mut obligations = PredicateObligations::new();
let targets = let targets =
steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false))); steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false)));
let steps: Vec<_> = steps let steps: Vec<_> = steps

View File

@ -8,7 +8,7 @@ use rustc_hir as hir;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::ObligationCauseCode; use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
@ -805,7 +805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// [c1]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341089706 // [c1]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341089706
// [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796 // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796
self.commit_if_ok(|_| { self.commit_if_ok(|_| {
let mut all_obligations = vec![]; let mut all_obligations = PredicateObligations::new();
let supplied_sig = self.instantiate_binder_with_fresh_vars( let supplied_sig = self.instantiate_binder_with_fresh_vars(
self.tcx.def_span(expr_def_id), self.tcx.def_span(expr_def_id),
BoundRegionConversionTime::FnCall, BoundRegionConversionTime::FnCall,

View File

@ -46,6 +46,7 @@ use rustc_infer::infer::relate::RelateResult;
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::{ use rustc_infer::traits::{
IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation, IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation,
PredicateObligations,
}; };
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::span_bug; use rustc_middle::span_bug;
@ -120,7 +121,7 @@ fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'
fn success<'tcx>( fn success<'tcx>(
adj: Vec<Adjustment<'tcx>>, adj: Vec<Adjustment<'tcx>>,
target: Ty<'tcx>, target: Ty<'tcx>,
obligations: Vec<traits::PredicateObligation<'tcx>>, obligations: PredicateObligations<'tcx>,
) -> CoerceResult<'tcx> { ) -> CoerceResult<'tcx> {
Ok(InferOk { value: (adj, target), obligations }) Ok(InferOk { value: (adj, target), obligations })
} }
@ -184,7 +185,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Coercing from `!` to any type is allowed: // Coercing from `!` to any type is allowed:
if a.is_never() { if a.is_never() {
if self.coerce_never { if self.coerce_never {
return success(simple(Adjust::NeverToAny)(b), b, vec![]); return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new());
} else { } else {
// Otherwise the only coercion we can do is unification. // Otherwise the only coercion we can do is unification.
return self.unify_and(a, b, identity); return self.unify_and(a, b, identity);
@ -278,7 +279,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Two unresolved type variables: create a `Coerce` predicate. // Two unresolved type variables: create a `Coerce` predicate.
let target_ty = if self.use_lub { self.next_ty_var(self.cause.span) } else { b }; let target_ty = if self.use_lub { self.next_ty_var(self.cause.span) } else { b };
let mut obligations = Vec::with_capacity(2); let mut obligations = PredicateObligations::with_capacity(2);
for &source_ty in &[a, b] { for &source_ty in &[a, b] {
if source_ty != target_ty { if source_ty != target_ty {
obligations.push(Obligation::new( obligations.push(Obligation::new(
@ -744,7 +745,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Check the obligations of the cast -- for example, when casting // Check the obligations of the cast -- for example, when casting
// `usize` to `dyn* Clone + 'static`: // `usize` to `dyn* Clone + 'static`:
let mut obligations: Vec<_> = predicates let obligations = predicates
.iter() .iter()
.map(|predicate| { .map(|predicate| {
// For each existential predicate (e.g., `?Self: Clone`) instantiate // For each existential predicate (e.g., `?Self: Clone`) instantiate
@ -764,21 +765,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
ty::OutlivesPredicate(a, b_region), ty::OutlivesPredicate(a, b_region),
))), ))),
), ),
// Enforce that the type is `usize`/pointer-sized.
Obligation::new(
self.tcx,
self.cause.clone(),
self.param_env,
ty::TraitRef::new(
self.tcx,
self.tcx
.require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)),
[a],
),
),
]) ])
.collect(); .collect();
// Enforce that the type is `usize`/pointer-sized.
obligations.push(Obligation::new(
self.tcx,
self.cause.clone(),
self.param_env,
ty::TraitRef::new(
self.tcx,
self.tcx.require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)),
[a],
),
));
Ok(InferOk { Ok(InferOk {
value: ( value: (
vec![Adjustment { kind: Adjust::Pointer(PointerCoercion::DynStar), target: b }], vec![Adjustment { kind: Adjust::Pointer(PointerCoercion::DynStar), target: b }],

View File

@ -1,6 +1,6 @@
//! A utility module to inspect currently ambiguous obligations in the current context. //! A utility module to inspect currently ambiguous obligations in the current context.
use rustc_infer::traits::{self, ObligationCause}; use rustc_infer::traits::{self, ObligationCause, PredicateObligations};
use rustc_middle::traits::solve::Goal; use rustc_middle::traits::solve::Goal;
use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_span::Span; use rustc_span::Span;
@ -15,10 +15,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Returns a list of all obligations whose self type has been unified /// Returns a list of all obligations whose self type has been unified
/// with the unconstrained type `self_ty`. /// with the unconstrained type `self_ty`.
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub(crate) fn obligations_for_self_ty( pub(crate) fn obligations_for_self_ty(&self, self_ty: ty::TyVid) -> PredicateObligations<'tcx> {
&self,
self_ty: ty::TyVid,
) -> Vec<traits::PredicateObligation<'tcx>> {
if self.next_trait_solver() { if self.next_trait_solver() {
self.obligations_for_self_ty_next(self_ty) self.obligations_for_self_ty_next(self_ty)
} else { } else {
@ -75,10 +72,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn obligations_for_self_ty_next( pub(crate) fn obligations_for_self_ty_next(
&self, &self,
self_ty: ty::TyVid, self_ty: ty::TyVid,
) -> Vec<traits::PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
let obligations = self.fulfillment_cx.borrow().pending_obligations(); let obligations = self.fulfillment_cx.borrow().pending_obligations();
debug!(?obligations); debug!(?obligations);
let mut obligations_for_self_ty = vec![]; let mut obligations_for_self_ty = PredicateObligations::new();
for obligation in obligations { for obligation in obligations {
let mut visitor = NestedObligationsForSelfTy { let mut visitor = NestedObligationsForSelfTy {
fcx: self, fcx: self,
@ -103,7 +100,7 @@ struct NestedObligationsForSelfTy<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>, fcx: &'a FnCtxt<'a, 'tcx>,
self_ty: ty::TyVid, self_ty: ty::TyVid,
root_cause: &'a ObligationCause<'tcx>, root_cause: &'a ObligationCause<'tcx>,
obligations_for_self_ty: &'a mut Vec<traits::PredicateObligation<'tcx>>, obligations_for_self_ty: &'a mut PredicateObligations<'tcx>,
} }
impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> { impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {

View File

@ -12,6 +12,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk}; use rustc_infer::infer::{self, InferOk};
use rustc_infer::traits::PredicateObligations;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{ use rustc_middle::ty::{
@ -414,7 +415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
let mut obligations = vec![]; let mut obligations = PredicateObligations::new();
// FIXME(effects): revisit when binops get `#[const_trait]` // FIXME(effects): revisit when binops get `#[const_trait]`

View File

@ -21,5 +21,6 @@ rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" } rustc_target = { path = "../rustc_target" }
rustc_type_ir = { path = "../rustc_type_ir" } rustc_type_ir = { path = "../rustc_type_ir" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"
tracing = "0.1" tracing = "0.1"
# tidy-alphabetical-end # tidy-alphabetical-end

View File

@ -28,7 +28,8 @@ use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult};
use crate::traits::query::NoSolution; use crate::traits::query::NoSolution;
use crate::traits::{ use crate::traits::{
Obligation, ObligationCause, PredicateObligation, ScrubbedTraitError, TraitEngine, Obligation, ObligationCause, PredicateObligation, PredicateObligations, ScrubbedTraitError,
TraitEngine,
}; };
impl<'tcx> InferCtxt<'tcx> { impl<'tcx> InferCtxt<'tcx> {
@ -493,7 +494,7 @@ impl<'tcx> InferCtxt<'tcx> {
), ),
}; };
let mut obligations = vec![]; let mut obligations = PredicateObligations::new();
// Carry all newly resolved opaque types to the caller's scope // Carry all newly resolved opaque types to the caller's scope
for &(a, b) in &query_response.value.opaque_types { for &(a, b) in &query_response.value.opaque_types {
@ -598,7 +599,7 @@ impl<'tcx> InferCtxt<'tcx> {
variables1: &OriginalQueryValues<'tcx>, variables1: &OriginalQueryValues<'tcx>,
variables2: impl Fn(BoundVar) -> GenericArg<'tcx>, variables2: impl Fn(BoundVar) -> GenericArg<'tcx>,
) -> InferResult<'tcx, ()> { ) -> InferResult<'tcx, ()> {
let mut obligations = vec![]; let mut obligations = PredicateObligations::new();
for (index, value1) in variables1.var_values.iter().enumerate() { for (index, value1) in variables1.var_values.iter().enumerate() {
let value2 = variables2(BoundVar::new(index)); let value2 = variables2(BoundVar::new(index));

View File

@ -50,7 +50,9 @@ use tracing::{debug, instrument};
use type_variable::TypeVariableOrigin; use type_variable::TypeVariableOrigin;
use crate::infer::region_constraints::UndoLog; use crate::infer::region_constraints::UndoLog;
use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; use crate::traits::{
self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine,
};
pub mod at; pub mod at;
pub mod canonical; pub mod canonical;
@ -68,7 +70,7 @@ pub(crate) mod snapshot;
mod type_variable; mod type_variable;
/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper /// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper
/// around `Vec<PredicateObligation<'tcx>>`, but it has one important property: /// around `PredicateObligations<'tcx>`, but it has one important property:
/// because `InferOk` is marked with `#[must_use]`, if you have a method /// because `InferOk` is marked with `#[must_use]`, if you have a method
/// `InferCtxt::f` that returns `InferResult<'tcx, ()>` and you call it with /// `InferCtxt::f` that returns `InferResult<'tcx, ()>` and you call it with
/// `infcx.f()?;` you'll get a warning about the obligations being discarded /// `infcx.f()?;` you'll get a warning about the obligations being discarded
@ -78,7 +80,7 @@ mod type_variable;
#[derive(Debug)] #[derive(Debug)]
pub struct InferOk<'tcx, T> { pub struct InferOk<'tcx, T> {
pub value: T, pub value: T,
pub obligations: Vec<PredicateObligation<'tcx>>, pub obligations: PredicateObligations<'tcx>,
} }
pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>; pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
@ -658,7 +660,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
} }
impl<'tcx> InferOk<'tcx, ()> { impl<'tcx> InferOk<'tcx, ()> {
pub fn into_obligations(self) -> Vec<PredicateObligation<'tcx>> { pub fn into_obligations(self) -> PredicateObligations<'tcx> {
self.obligations self.obligations
} }
} }

View File

@ -16,7 +16,7 @@ use tracing::{debug, instrument};
use super::DefineOpaqueTypes; use super::DefineOpaqueTypes;
use crate::errors::OpaqueHiddenTypeDiag; use crate::errors::OpaqueHiddenTypeDiag;
use crate::infer::{InferCtxt, InferOk}; use crate::infer::{InferCtxt, InferOk};
use crate::traits::{self, Obligation}; use crate::traits::{self, Obligation, PredicateObligations};
mod table; mod table;
@ -46,14 +46,14 @@ impl<'tcx> InferCtxt<'tcx> {
) -> InferOk<'tcx, T> { ) -> InferOk<'tcx, T> {
// We handle opaque types differently in the new solver. // We handle opaque types differently in the new solver.
if self.next_trait_solver() { if self.next_trait_solver() {
return InferOk { value, obligations: vec![] }; return InferOk { value, obligations: PredicateObligations::new() };
} }
if !value.has_opaque_types() { if !value.has_opaque_types() {
return InferOk { value, obligations: vec![] }; return InferOk { value, obligations: PredicateObligations::new() };
} }
let mut obligations = vec![]; let mut obligations = PredicateObligations::new();
let value = value.fold_with(&mut BottomUpFolder { let value = value.fold_with(&mut BottomUpFolder {
tcx: self.tcx, tcx: self.tcx,
lt_op: |lt| lt, lt_op: |lt| lt,

View File

@ -2,7 +2,7 @@ use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use super::InferCtxt; use super::InferCtxt;
use crate::traits::{Obligation, PredicateObligation}; use crate::traits::{Obligation, PredicateObligations};
impl<'tcx> InferCtxt<'tcx> { impl<'tcx> InferCtxt<'tcx> {
/// Instead of normalizing an associated type projection, /// Instead of normalizing an associated type projection,
@ -17,7 +17,7 @@ impl<'tcx> InferCtxt<'tcx> {
projection_ty: ty::AliasTy<'tcx>, projection_ty: ty::AliasTy<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
recursion_depth: usize, recursion_depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>, obligations: &mut PredicateObligations<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
debug_assert!(!self.next_trait_solver()); debug_assert!(!self.next_trait_solver());
let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id)); let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));

View File

@ -27,7 +27,7 @@ use tracing::{debug, instrument};
use super::StructurallyRelateAliases; use super::StructurallyRelateAliases;
use super::combine::PredicateEmittingRelation; use super::combine::PredicateEmittingRelation;
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace}; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace};
use crate::traits::{Obligation, PredicateObligation}; use crate::traits::{Obligation, PredicateObligations};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub(crate) enum LatticeOpKind { pub(crate) enum LatticeOpKind {
@ -52,7 +52,7 @@ pub(crate) struct LatticeOp<'infcx, 'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
// Mutable fields // Mutable fields
kind: LatticeOpKind, kind: LatticeOpKind,
obligations: Vec<PredicateObligation<'tcx>>, obligations: PredicateObligations<'tcx>,
} }
impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> { impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> {
@ -62,10 +62,10 @@ impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
kind: LatticeOpKind, kind: LatticeOpKind,
) -> LatticeOp<'infcx, 'tcx> { ) -> LatticeOp<'infcx, 'tcx> {
LatticeOp { infcx, trace, param_env, kind, obligations: vec![] } LatticeOp { infcx, trace, param_env, kind, obligations: PredicateObligations::new() }
} }
pub(crate) fn into_obligations(self) -> Vec<PredicateObligation<'tcx>> { pub(crate) fn into_obligations(self) -> PredicateObligations<'tcx> {
self.obligations self.obligations
} }
} }

View File

@ -11,7 +11,7 @@ use tracing::{debug, instrument};
use crate::infer::BoundRegionConversionTime::HigherRankedType; use crate::infer::BoundRegionConversionTime::HigherRankedType;
use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace}; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace};
use crate::traits::{Obligation, PredicateObligation}; use crate::traits::{Obligation, PredicateObligations};
/// Enforce that `a` is equal to or a subtype of `b`. /// Enforce that `a` is equal to or a subtype of `b`.
pub(crate) struct TypeRelating<'infcx, 'tcx> { pub(crate) struct TypeRelating<'infcx, 'tcx> {
@ -24,7 +24,7 @@ pub(crate) struct TypeRelating<'infcx, 'tcx> {
// Mutable fields. // Mutable fields.
ambient_variance: ty::Variance, ambient_variance: ty::Variance,
obligations: Vec<PredicateObligation<'tcx>>, obligations: PredicateObligations<'tcx>,
/// The cache only tracks the `ambient_variance` as it's the /// The cache only tracks the `ambient_variance` as it's the
/// only field which is mutable and which meaningfully changes /// only field which is mutable and which meaningfully changes
/// the result when relating types. /// the result when relating types.
@ -65,12 +65,12 @@ impl<'infcx, 'tcx> TypeRelating<'infcx, 'tcx> {
param_env, param_env,
define_opaque_types, define_opaque_types,
ambient_variance, ambient_variance,
obligations: vec![], obligations: PredicateObligations::new(),
cache: Default::default(), cache: Default::default(),
} }
} }
pub(crate) fn into_obligations(self) -> Vec<PredicateObligation<'tcx>> { pub(crate) fn into_obligations(self) -> PredicateObligations<'tcx> {
self.obligations self.obligations
} }
} }

View File

@ -3,7 +3,7 @@ use std::fmt::Debug;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, Ty, Upcast}; use rustc_middle::ty::{self, Ty, Upcast};
use super::{ObligationCause, PredicateObligation}; use super::{ObligationCause, PredicateObligation, PredicateObligations};
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use crate::traits::Obligation; use crate::traits::Obligation;
@ -20,7 +20,7 @@ pub enum ScrubbedTraitError<'tcx> {
/// An ambiguity. This goal may hold if further inference is done. /// An ambiguity. This goal may hold if further inference is done.
Ambiguity, Ambiguity,
/// An old-solver-style cycle error, which will fatal. /// An old-solver-style cycle error, which will fatal.
Cycle(Vec<PredicateObligation<'tcx>>), Cycle(PredicateObligations<'tcx>),
} }
impl<'tcx> ScrubbedTraitError<'tcx> { impl<'tcx> ScrubbedTraitError<'tcx> {
@ -62,7 +62,7 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
fn register_predicate_obligations( fn register_predicate_obligations(
&mut self, &mut self,
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>, obligations: PredicateObligations<'tcx>,
) { ) {
for obligation in obligations { for obligation in obligations {
self.register_predicate_obligation(infcx, obligation); self.register_predicate_obligation(infcx, obligation);
@ -84,7 +84,7 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
self.collect_remaining_errors(infcx) self.collect_remaining_errors(infcx)
} }
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>; fn pending_obligations(&self) -> PredicateObligations<'tcx>;
/// Among all pending obligations, collect those are stalled on a inference variable which has /// Among all pending obligations, collect those are stalled on a inference variable which has
/// changed since the last call to `select_where_possible`. Those obligations are marked as /// changed since the last call to `select_where_possible`. Those obligations are marked as
@ -92,7 +92,7 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
fn drain_unstalled_obligations( fn drain_unstalled_obligations(
&mut self, &mut self,
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
) -> Vec<PredicateObligation<'tcx>>; ) -> PredicateObligations<'tcx>;
} }
pub trait FromSolverError<'tcx, E>: Debug + 'tcx { pub trait FromSolverError<'tcx, E>: Debug + 'tcx {

View File

@ -17,6 +17,7 @@ use rustc_middle::traits::solve::Certainty;
pub use rustc_middle::traits::*; pub use rustc_middle::traits::*;
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_span::Span; use rustc_span::Span;
use thin_vec::ThinVec;
pub use self::ImplSource::*; pub use self::ImplSource::*;
pub use self::SelectionError::*; pub use self::SelectionError::*;
@ -84,6 +85,8 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::TraitPredicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::TraitPredicate<'tcx>>;
pub type PolyTraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; pub type PolyTraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
pub type PredicateObligations<'tcx> = ThinVec<PredicateObligation<'tcx>>;
impl<'tcx> PredicateObligation<'tcx> { impl<'tcx> PredicateObligation<'tcx> {
/// Flips the polarity of the inner predicate. /// Flips the polarity of the inner predicate.
/// ///

View File

@ -6,7 +6,7 @@ use rustc_middle::traits::EvaluationResult;
use rustc_middle::ty; use rustc_middle::ty;
use tracing::{debug, info}; use tracing::{debug, info};
use super::PredicateObligation; use super::PredicateObligations;
use crate::infer::snapshot::undo_log::InferCtxtUndoLogs; use crate::infer::snapshot::undo_log::InferCtxtUndoLogs;
pub(crate) type UndoLog<'tcx> = pub(crate) type UndoLog<'tcx> =
@ -20,7 +20,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
#[derive(Clone)] #[derive(Clone)]
pub struct Normalized<'tcx, T> { pub struct Normalized<'tcx, T> {
pub value: T, pub value: T,
pub obligations: Vec<PredicateObligation<'tcx>>, pub obligations: PredicateObligations<'tcx>,
} }
pub type NormalizedTerm<'tcx> = Normalized<'tcx, ty::Term<'tcx>>; pub type NormalizedTerm<'tcx> = Normalized<'tcx, ty::Term<'tcx>>;
@ -191,7 +191,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
let mut ty = ty.clone(); let mut ty = ty.clone();
if result.must_apply_considering_regions() { if result.must_apply_considering_regions() {
ty.obligations = vec![]; ty.obligations = PredicateObligations::new();
} }
map.insert(key, ProjectionCacheEntry::NormalizedTerm { map.insert(key, ProjectionCacheEntry::NormalizedTerm {
ty, ty,

View File

@ -25,6 +25,7 @@ use rustc_span::{DUMMY_SP, Span};
// FIXME: Remove this import and import via `solve::` // FIXME: Remove this import and import via `solve::`
pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal}; pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal};
use smallvec::{SmallVec, smallvec}; use smallvec::{SmallVec, smallvec};
use thin_vec::ThinVec;
pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
use crate::mir::ConstraintCategory; use crate::mir::ConstraintCategory;
@ -625,14 +626,14 @@ pub enum ImplSource<'tcx, N> {
/// for some type parameter. The `Vec<N>` represents the /// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if /// obligations incurred from normalizing the where-clause (if
/// any). /// any).
Param(Vec<N>), Param(ThinVec<N>),
/// Successful resolution for a builtin impl. /// Successful resolution for a builtin impl.
Builtin(BuiltinImplSource, Vec<N>), Builtin(BuiltinImplSource, ThinVec<N>),
} }
impl<'tcx, N> ImplSource<'tcx, N> { impl<'tcx, N> ImplSource<'tcx, N> {
pub fn nested_obligations(self) -> Vec<N> { pub fn nested_obligations(self) -> ThinVec<N> {
match self { match self {
ImplSource::UserDefined(i) => i.nested, ImplSource::UserDefined(i) => i.nested,
ImplSource::Param(n) | ImplSource::Builtin(_, n) => n, ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
@ -686,7 +687,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
pub struct ImplSourceUserDefinedData<'tcx, N> { pub struct ImplSourceUserDefinedData<'tcx, N> {
pub impl_def_id: DefId, pub impl_def_id: DefId,
pub args: GenericArgsRef<'tcx>, pub args: GenericArgsRef<'tcx>,
pub nested: Vec<N>, pub nested: ThinVec<N>,
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]

View File

@ -26,5 +26,6 @@ rustc_target = { path = "../rustc_target" }
rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
rustc_type_ir = { path = "../rustc_type_ir" } rustc_type_ir = { path = "../rustc_type_ir" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2"
tracing = "0.1" tracing = "0.1"
# tidy-alphabetical-end # tidy-alphabetical-end

View File

@ -2,7 +2,7 @@ use std::ops::Deref;
use rustc_errors::DiagCtxtHandle; use rustc_errors::DiagCtxtHandle;
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::PredicateObligation; use rustc_infer::traits::PredicateObligations;
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
@ -28,8 +28,7 @@ pub struct TypeErrCtxt<'a, 'tcx> {
pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>, pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
pub autoderef_steps: pub autoderef_steps: Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, PredicateObligations<'tcx>)> + 'a>,
Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
} }
#[extension(pub trait InferCtxtErrorExt<'tcx>)] #[extension(pub trait InferCtxtErrorExt<'tcx>)]
@ -45,7 +44,7 @@ impl<'tcx> InferCtxt<'tcx> {
normalize_fn_sig: Box::new(|fn_sig| fn_sig), normalize_fn_sig: Box::new(|fn_sig| fn_sig),
autoderef_steps: Box::new(|ty| { autoderef_steps: Box::new(|ty| {
debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck"); debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck");
vec![(ty, vec![])] vec![(ty, PredicateObligations::new())]
}), }),
} }
} }

View File

@ -2,12 +2,13 @@ use std::marker::PhantomData;
use std::mem; use std::mem;
use std::ops::ControlFlow; use std::ops::ControlFlow;
use rustc_data_structures::thinvec::ExtractIf;
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
use rustc_infer::traits::{ use rustc_infer::traits::{
self, FromSolverError, MismatchedProjectionTypes, Obligation, ObligationCause, self, FromSolverError, MismatchedProjectionTypes, Obligation, ObligationCause,
ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine, ObligationCauseCode, PredicateObligation, PredicateObligations, SelectionError, TraitEngine,
}; };
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
@ -49,8 +50,8 @@ struct ObligationStorage<'tcx> {
/// We cannot eagerly return these as error so we instead store them here /// We cannot eagerly return these as error so we instead store them here
/// to avoid recomputing them each time `select_where_possible` is called. /// to avoid recomputing them each time `select_where_possible` is called.
/// This also allows us to return the correct `FulfillmentError` for them. /// This also allows us to return the correct `FulfillmentError` for them.
overflowed: Vec<PredicateObligation<'tcx>>, overflowed: PredicateObligations<'tcx>,
pending: Vec<PredicateObligation<'tcx>>, pending: PredicateObligations<'tcx>,
} }
impl<'tcx> ObligationStorage<'tcx> { impl<'tcx> ObligationStorage<'tcx> {
@ -58,13 +59,13 @@ impl<'tcx> ObligationStorage<'tcx> {
self.pending.push(obligation); self.pending.push(obligation);
} }
fn clone_pending(&self) -> Vec<PredicateObligation<'tcx>> { fn clone_pending(&self) -> PredicateObligations<'tcx> {
let mut obligations = self.pending.clone(); let mut obligations = self.pending.clone();
obligations.extend(self.overflowed.iter().cloned()); obligations.extend(self.overflowed.iter().cloned());
obligations obligations
} }
fn take_pending(&mut self) -> Vec<PredicateObligation<'tcx>> { fn take_pending(&mut self) -> PredicateObligations<'tcx> {
let mut obligations = mem::take(&mut self.pending); let mut obligations = mem::take(&mut self.pending);
obligations.append(&mut self.overflowed); obligations.append(&mut self.overflowed);
obligations obligations
@ -81,7 +82,8 @@ impl<'tcx> ObligationStorage<'tcx> {
// we get all obligations involved in the overflow. We pretty much check: if // we get all obligations involved in the overflow. We pretty much check: if
// we were to do another step of `select_where_possible`, which goals would // we were to do another step of `select_where_possible`, which goals would
// change. // change.
self.overflowed.extend(self.pending.extract_if(|o| { // FIXME: <https://github.com/Gankra/thin-vec/pull/66> is merged, this can be removed.
self.overflowed.extend(ExtractIf::new(&mut self.pending, |o| {
let goal = o.clone().into(); let goal = o.clone().into();
let result = <&SolverDelegate<'tcx>>::from(infcx) let result = <&SolverDelegate<'tcx>>::from(infcx)
.evaluate_root_goal(goal, GenerateProofTree::No) .evaluate_root_goal(goal, GenerateProofTree::No)
@ -197,14 +199,11 @@ where
errors errors
} }
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { fn pending_obligations(&self) -> PredicateObligations<'tcx> {
self.obligations.clone_pending() self.obligations.clone_pending()
} }
fn drain_unstalled_obligations( fn drain_unstalled_obligations(&mut self, _: &InferCtxt<'tcx>) -> PredicateObligations<'tcx> {
&mut self,
_: &InferCtxt<'tcx>,
) -> Vec<PredicateObligation<'tcx>> {
self.obligations.take_pending() self.obligations.take_pending()
} }
} }

View File

@ -11,6 +11,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::PredicateObligations;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
@ -279,7 +280,7 @@ fn equate_impl_headers<'tcx>(
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
impl1: &ty::ImplHeader<'tcx>, impl1: &ty::ImplHeader<'tcx>,
impl2: &ty::ImplHeader<'tcx>, impl2: &ty::ImplHeader<'tcx>,
) -> Option<Vec<PredicateObligation<'tcx>>> { ) -> Option<PredicateObligations<'tcx>> {
let result = let result =
match (impl1.trait_ref, impl2.trait_ref) { match (impl1.trait_ref, impl2.trait_ref) {
(Some(impl1_ref), Some(impl2_ref)) => infcx (Some(impl1_ref), Some(impl2_ref)) => infcx
@ -491,7 +492,7 @@ fn plug_infer_with_placeholders<'tcx>(
else { else {
bug!("we always expect to be able to plug an infer var with placeholder") bug!("we always expect to be able to plug an infer var with placeholder")
}; };
assert_eq!(obligations, &[]); assert_eq!(obligations.len(), 0);
} else { } else {
ty.super_visit_with(self); ty.super_visit_with(self);
} }
@ -514,7 +515,7 @@ fn plug_infer_with_placeholders<'tcx>(
else { else {
bug!("we always expect to be able to plug an infer var with placeholder") bug!("we always expect to be able to plug an infer var with placeholder")
}; };
assert_eq!(obligations, &[]); assert_eq!(obligations.len(), 0);
} else { } else {
ct.super_visit_with(self); ct.super_visit_with(self);
} }
@ -545,7 +546,7 @@ fn plug_infer_with_placeholders<'tcx>(
else { else {
bug!("we always expect to be able to plug an infer var with placeholder") bug!("we always expect to be able to plug an infer var with placeholder")
}; };
assert_eq!(obligations, &[]); assert_eq!(obligations.len(), 0);
} }
} }
} }

View File

@ -10,6 +10,7 @@ use rustc_infer::infer::canonical::{
}; };
use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace};
use rustc_infer::traits::PredicateObligations;
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::arena::ArenaAllocatable; use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::query::NoSolution;
@ -206,7 +207,7 @@ where
/// getting ignored. You can make a new `ObligationCtxt` if this /// getting ignored. You can make a new `ObligationCtxt` if this
/// needs to be done in a loop, for example. /// needs to be done in a loop, for example.
#[must_use] #[must_use]
pub fn into_pending_obligations(self) -> Vec<PredicateObligation<'tcx>> { pub fn into_pending_obligations(self) -> PredicateObligations<'tcx> {
self.engine.borrow().pending_obligations() self.engine.borrow().pending_obligations()
} }

View File

@ -6,13 +6,15 @@ use rustc_data_structures::obligation_forest::{
}; };
use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::{ use rustc_infer::traits::{
FromSolverError, PolyTraitObligation, ProjectionCacheKey, SelectionError, TraitEngine, FromSolverError, PolyTraitObligation, PredicateObligations, ProjectionCacheKey, SelectionError,
TraitEngine,
}; };
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt}; use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt};
use thin_vec::ThinVec;
use tracing::{debug, debug_span, instrument}; use tracing::{debug, debug_span, instrument};
use super::project::{self, ProjectAndUnifyResult}; use super::project::{self, ProjectAndUnifyResult};
@ -27,6 +29,8 @@ use crate::traits::normalize::normalize_with_depth_to;
use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::query::evaluate_obligation::InferCtxtExt;
pub(crate) type PendingPredicateObligations<'tcx> = ThinVec<PendingPredicateObligation<'tcx>>;
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
/// Note that we include both the `ParamEnv` and the `Predicate`, /// Note that we include both the `ParamEnv` and the `Predicate`,
/// as the `ParamEnv` can influence whether fulfillment succeeds /// as the `ParamEnv` can influence whether fulfillment succeeds
@ -161,15 +165,16 @@ where
fn drain_unstalled_obligations( fn drain_unstalled_obligations(
&mut self, &mut self,
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
) -> Vec<PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
let mut processor = DrainProcessor { removed_predicates: Vec::new(), infcx }; let mut processor =
DrainProcessor { removed_predicates: PredicateObligations::new(), infcx };
let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor); let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor);
assert!(outcome.errors.is_empty()); assert!(outcome.errors.is_empty());
return processor.removed_predicates; return processor.removed_predicates;
struct DrainProcessor<'a, 'tcx> { struct DrainProcessor<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>, infcx: &'a InferCtxt<'tcx>,
removed_predicates: Vec<PredicateObligation<'tcx>>, removed_predicates: PredicateObligations<'tcx>,
} }
impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> { impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> {
@ -190,7 +195,7 @@ where
) -> ProcessResult<PendingPredicateObligation<'tcx>, !> { ) -> ProcessResult<PendingPredicateObligation<'tcx>, !> {
assert!(self.needs_process_obligation(pending_obligation)); assert!(self.needs_process_obligation(pending_obligation));
self.removed_predicates.push(pending_obligation.obligation.clone()); self.removed_predicates.push(pending_obligation.obligation.clone());
ProcessResult::Changed(vec![]) ProcessResult::Changed(Default::default())
} }
fn process_backedge<'c, I>( fn process_backedge<'c, I>(
@ -207,7 +212,7 @@ where
} }
} }
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { fn pending_obligations(&self) -> PredicateObligations<'tcx> {
self.predicates.map_pending_obligations(|o| o.obligation.clone()) self.predicates.map_pending_obligations(|o| o.obligation.clone())
} }
} }
@ -216,7 +221,7 @@ struct FulfillProcessor<'a, 'tcx> {
selcx: SelectionContext<'a, 'tcx>, selcx: SelectionContext<'a, 'tcx>,
} }
fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> { fn mk_pending<'tcx>(os: PredicateObligations<'tcx>) -> PendingPredicateObligations<'tcx> {
os.into_iter() os.into_iter()
.map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] }) .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] })
.collect() .collect()
@ -321,7 +326,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
let infcx = self.selcx.infcx; let infcx = self.selcx.infcx;
if obligation.predicate.has_aliases() { if obligation.predicate.has_aliases() {
let mut obligations = Vec::new(); let mut obligations = PredicateObligations::new();
let predicate = normalize_with_depth_to( let predicate = normalize_with_depth_to(
&mut self.selcx, &mut self.selcx,
obligation.param_env, obligation.param_env,
@ -369,7 +374,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..) => { | ty::PredicateKind::ConstEquate(..) => {
let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder)); let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder));
ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)])) let mut obligations = PredicateObligations::with_capacity(1);
obligations.push(obligation.with(infcx.tcx, pred));
ProcessResult::Changed(mk_pending(obligations))
} }
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
ty::PredicateKind::NormalizesTo(..) => { ty::PredicateKind::NormalizesTo(..) => {
@ -395,7 +403,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)); infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
} }
ProcessResult::Changed(vec![]) ProcessResult::Changed(Default::default())
} }
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
@ -405,7 +413,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
if infcx.considering_regions { if infcx.considering_regions {
infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause); infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause);
} }
ProcessResult::Changed(vec![]) ProcessResult::Changed(Default::default())
} }
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => { ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => {
@ -422,7 +430,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
if !self.selcx.tcx().is_dyn_compatible(trait_def_id) { if !self.selcx.tcx().is_dyn_compatible(trait_def_id) {
ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented)) ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented))
} else { } else {
ProcessResult::Changed(vec![]) ProcessResult::Changed(Default::default())
} }
} }
@ -451,7 +459,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
pending_obligation.stalled_on.extend([var]); pending_obligation.stalled_on.extend([var]);
return ProcessResult::Unchanged; return ProcessResult::Unchanged;
} }
ty::ConstKind::Error(_) => return ProcessResult::Changed(vec![]), ty::ConstKind::Error(_) => {
return ProcessResult::Changed(PendingPredicateObligations::new());
}
ty::ConstKind::Value(ty, _) => ty, ty::ConstKind::Value(ty, _) => ty,
ty::ConstKind::Unevaluated(uv) => { ty::ConstKind::Unevaluated(uv) => {
infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
@ -460,7 +470,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
// `<lhs_ty as Add<rhs_ty>>::Output` when this is an `Expr` representing // `<lhs_ty as Add<rhs_ty>>::Output` when this is an `Expr` representing
// `lhs + rhs`. // `lhs + rhs`.
ty::ConstKind::Expr(_) => { ty::ConstKind::Expr(_) => {
return ProcessResult::Changed(mk_pending(vec![])); return ProcessResult::Changed(mk_pending(PredicateObligations::new()));
} }
ty::ConstKind::Placeholder(_) => { ty::ConstKind::Placeholder(_) => {
bug!("placeholder const {:?} in old solver", ct) bug!("placeholder const {:?} in old solver", ct)
@ -568,7 +578,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
obligation.param_env, obligation.param_env,
obligation.cause.span, obligation.cause.span,
) { ) {
Ok(()) => ProcessResult::Changed(vec![]), Ok(()) => ProcessResult::Changed(Default::default()),
Err(NotConstEvaluatable::MentionsInfer) => { Err(NotConstEvaluatable::MentionsInfer) => {
pending_obligation.stalled_on.clear(); pending_obligation.stalled_on.clear();
pending_obligation.stalled_on.extend( pending_obligation.stalled_on.extend(
@ -722,7 +732,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
debug!("process_child_obligations: coinductive match"); debug!("process_child_obligations: coinductive match");
Ok(()) Ok(())
} else { } else {
let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); let cycle = cycle.map(|c| c.obligation.clone()).collect();
Err(FulfillmentErrorCode::Cycle(cycle)) Err(FulfillmentErrorCode::Cycle(cycle))
} }
} }
@ -745,7 +755,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
"selecting trait at depth {} evaluated to holds", "selecting trait at depth {} evaluated to holds",
obligation.recursion_depth obligation.recursion_depth
); );
return ProcessResult::Changed(vec![]); return ProcessResult::Changed(Default::default());
} }
} }
@ -809,7 +819,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
.projection_cache() .projection_cache()
.complete(key, EvaluationResult::EvaluatedToOk); .complete(key, EvaluationResult::EvaluatedToOk);
} }
return ProcessResult::Changed(vec![]); return ProcessResult::Changed(Default::default());
} else { } else {
debug!("Does NOT hold: {:?}", obligation); debug!("Does NOT hold: {:?}", obligation);
} }
@ -826,9 +836,12 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
ProcessResult::Unchanged ProcessResult::Unchanged
} }
// Let the caller handle the recursion // Let the caller handle the recursion
ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![ ProjectAndUnifyResult::Recursive => {
project_obligation.with(tcx, project_obligation.predicate), let mut obligations = PredicateObligations::with_capacity(1);
])), obligations.push(project_obligation.with(tcx, project_obligation.predicate));
ProcessResult::Changed(mk_pending(obligations))
}
ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
ProcessResult::Error(FulfillmentErrorCode::Project(e)) ProcessResult::Error(FulfillmentErrorCode::Project(e))
} }

View File

@ -114,7 +114,7 @@ impl<'tcx> Debug for FulfillmentError<'tcx> {
pub enum FulfillmentErrorCode<'tcx> { pub enum FulfillmentErrorCode<'tcx> {
/// Inherently impossible to fulfill; this trait is implemented if and only /// Inherently impossible to fulfill; this trait is implemented if and only
/// if it is already implemented. /// if it is already implemented.
Cycle(Vec<PredicateObligation<'tcx>>), Cycle(PredicateObligations<'tcx>),
Select(SelectionError<'tcx>), Select(SelectionError<'tcx>),
Project(MismatchedProjectionTypes<'tcx>), Project(MismatchedProjectionTypes<'tcx>),
Subtype(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate Subtype(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate

View File

@ -4,7 +4,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::infer::InferOk; use rustc_infer::infer::InferOk;
use rustc_infer::infer::at::At; use rustc_infer::infer::at::At;
use rustc_infer::traits::{ use rustc_infer::traits::{
FromSolverError, Normalized, Obligation, PredicateObligation, TraitEngine, FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
}; };
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal};
@ -29,7 +29,7 @@ impl<'tcx> At<'_, 'tcx> {
/// projection may be fallible. /// projection may be fallible.
fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> { fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
if self.infcx.next_trait_solver() { if self.infcx.next_trait_solver() {
InferOk { value, obligations: Vec::new() } InferOk { value, obligations: PredicateObligations::new() }
} else { } else {
let mut selcx = SelectionContext::new(self.infcx); let mut selcx = SelectionContext::new(self.infcx);
let Normalized { value, obligations } = let Normalized { value, obligations } =
@ -83,7 +83,7 @@ pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
where where
T: TypeFoldable<TyCtxt<'tcx>>, T: TypeFoldable<TyCtxt<'tcx>>,
{ {
let mut obligations = Vec::new(); let mut obligations = PredicateObligations::new();
let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
Normalized { value, obligations } Normalized { value, obligations }
} }
@ -95,14 +95,14 @@ pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
depth: usize, depth: usize,
value: T, value: T,
obligations: &mut Vec<PredicateObligation<'tcx>>, obligations: &mut PredicateObligations<'tcx>,
) -> T ) -> T
where where
T: TypeFoldable<TyCtxt<'tcx>>, T: TypeFoldable<TyCtxt<'tcx>>,
{ {
debug!(obligations.len = obligations.len()); debug!(obligations.len = obligations.len());
let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
let result = ensure_sufficient_stack(|| normalizer.fold(value)); let result = ensure_sufficient_stack(|| AssocTypeNormalizer::fold(&mut normalizer, value));
debug!(?result, obligations.len = normalizer.obligations.len()); debug!(?result, obligations.len = normalizer.obligations.len());
debug!(?normalizer.obligations,); debug!(?normalizer.obligations,);
result result
@ -128,7 +128,7 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> {
selcx: &'a mut SelectionContext<'b, 'tcx>, selcx: &'a mut SelectionContext<'b, 'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
obligations: &'a mut Vec<PredicateObligation<'tcx>>, obligations: &'a mut PredicateObligations<'tcx>,
depth: usize, depth: usize,
universes: Vec<Option<ty::UniverseIndex>>, universes: Vec<Option<ty::UniverseIndex>>,
} }
@ -139,7 +139,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
depth: usize, depth: usize,
obligations: &'a mut Vec<PredicateObligation<'tcx>>, obligations: &'a mut PredicateObligations<'tcx>,
) -> AssocTypeNormalizer<'a, 'b, 'tcx> { ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
debug_assert!(!selcx.infcx.next_trait_solver()); debug_assert!(!selcx.infcx.next_trait_solver());
AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] } AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }

View File

@ -77,7 +77,7 @@ fn implied_outlives_bounds<'a, 'tcx>(
else { else {
return vec![]; return vec![];
}; };
assert_eq!(&obligations, &[]); assert_eq!(obligations.len(), 0);
// Because of #109628, we may have unexpected placeholders. Ignore them! // Because of #109628, we may have unexpected placeholders. Ignore them!
// FIXME(#109628): panic in this case once the issue is fixed. // FIXME(#109628): panic in this case once the issue is fixed.

View File

@ -9,7 +9,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::traits::ObligationCauseCode; use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
pub use rustc_middle::traits::Reveal; pub use rustc_middle::traits::Reveal;
use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::select::OverflowError;
use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData}; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
@ -146,7 +146,7 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
/// of the old return type, which was: /// of the old return type, which was:
/// ```ignore (not-rust) /// ```ignore (not-rust)
/// Result< /// Result<
/// Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, /// Result<Option<PredicateObligations<'tcx>>, InProgress>,
/// MismatchedProjectionTypes<'tcx>, /// MismatchedProjectionTypes<'tcx>,
/// > /// >
/// ``` /// ```
@ -155,7 +155,7 @@ pub(super) enum ProjectAndUnifyResult<'tcx> {
/// projection cannot be normalized because the required trait bound does /// projection cannot be normalized because the required trait bound does
/// not hold, this is returned, with `obligations` being a predicate that /// not hold, this is returned, with `obligations` being a predicate that
/// cannot be proven. /// cannot be proven.
Holds(Vec<PredicateObligation<'tcx>>), Holds(PredicateObligations<'tcx>),
/// The projection cannot be normalized due to ambiguity. Resolving some /// The projection cannot be normalized due to ambiguity. Resolving some
/// inference variables in the projection may fix this. /// inference variables in the projection may fix this.
FailedNormalization, FailedNormalization,
@ -231,7 +231,7 @@ fn project_and_unify_term<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionObligation<'tcx>, obligation: &ProjectionObligation<'tcx>,
) -> ProjectAndUnifyResult<'tcx> { ) -> ProjectAndUnifyResult<'tcx> {
let mut obligations = vec![]; let mut obligations = PredicateObligations::new();
let infcx = selcx.infcx; let infcx = selcx.infcx;
let normalized = match opt_normalize_projection_term( let normalized = match opt_normalize_projection_term(
@ -289,7 +289,7 @@ pub fn normalize_projection_ty<'a, 'b, 'tcx>(
projection_ty: ty::AliasTy<'tcx>, projection_ty: ty::AliasTy<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
depth: usize, depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>, obligations: &mut PredicateObligations<'tcx>,
) -> Term<'tcx> { ) -> Term<'tcx> {
opt_normalize_projection_term( opt_normalize_projection_term(
selcx, selcx,
@ -330,7 +330,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
projection_term: ty::AliasTerm<'tcx>, projection_term: ty::AliasTerm<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
depth: usize, depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>, obligations: &mut PredicateObligations<'tcx>,
) -> Result<Option<Term<'tcx>>, InProgress> { ) -> Result<Option<Term<'tcx>>, InProgress> {
let infcx = selcx.infcx; let infcx = selcx.infcx;
debug_assert!(!selcx.infcx.next_trait_solver()); debug_assert!(!selcx.infcx.next_trait_solver());
@ -452,7 +452,8 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
Ok(Some(result.value)) Ok(Some(result.value))
} }
Ok(Projected::NoProgress(projected_ty)) => { Ok(Projected::NoProgress(projected_ty)) => {
let result = Normalized { value: projected_ty, obligations: vec![] }; let result =
Normalized { value: projected_ty, obligations: PredicateObligations::new() };
if use_cache { if use_cache {
infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
} }
@ -519,13 +520,14 @@ fn normalize_to_error<'a, 'tcx>(
selcx.infcx.next_const_var(cause.span).into() selcx.infcx.next_const_var(cause.span).into()
} }
}; };
let trait_obligation = Obligation { let mut obligations = PredicateObligations::new();
obligations.push(Obligation {
cause, cause,
recursion_depth: depth, recursion_depth: depth,
param_env, param_env,
predicate: trait_ref.upcast(selcx.tcx()), predicate: trait_ref.upcast(selcx.tcx()),
}; });
Normalized { value: new_value, obligations: vec![trait_obligation] } Normalized { value: new_value, obligations }
} }
/// Confirm and normalize the given inherent projection. /// Confirm and normalize the given inherent projection.
@ -536,7 +538,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
alias_ty: ty::AliasTy<'tcx>, alias_ty: ty::AliasTy<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
depth: usize, depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>, obligations: &mut PredicateObligations<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let tcx = selcx.tcx(); let tcx = selcx.tcx();
@ -604,7 +606,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
alias_ty: ty::AliasTy<'tcx>, alias_ty: ty::AliasTy<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
depth: usize, depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>, obligations: &mut PredicateObligations<'tcx>,
) -> ty::GenericArgsRef<'tcx> { ) -> ty::GenericArgsRef<'tcx> {
let tcx = selcx.tcx(); let tcx = selcx.tcx();
@ -657,15 +659,15 @@ enum Projected<'tcx> {
struct Progress<'tcx> { struct Progress<'tcx> {
term: ty::Term<'tcx>, term: ty::Term<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>, obligations: PredicateObligations<'tcx>,
} }
impl<'tcx> Progress<'tcx> { impl<'tcx> Progress<'tcx> {
fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
Progress { term: Ty::new_error(tcx, guar).into(), obligations: vec![] } Progress { term: Ty::new_error(tcx, guar).into(), obligations: PredicateObligations::new() }
} }
fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { fn with_addl_obligations(mut self, mut obligations: PredicateObligations<'tcx>) -> Self {
self.obligations.append(&mut obligations); self.obligations.append(&mut obligations);
self self
} }
@ -1351,7 +1353,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
fn confirm_coroutine_candidate<'cx, 'tcx>( fn confirm_coroutine_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>, nested: PredicateObligations<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let ty::Coroutine(_, args) = self_ty.kind() else { let ty::Coroutine(_, args) = self_ty.kind() else {
@ -1410,7 +1412,7 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
fn confirm_future_candidate<'cx, 'tcx>( fn confirm_future_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>, nested: PredicateObligations<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let ty::Coroutine(_, args) = self_ty.kind() else { let ty::Coroutine(_, args) = self_ty.kind() else {
@ -1458,7 +1460,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
fn confirm_iterator_candidate<'cx, 'tcx>( fn confirm_iterator_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>, nested: PredicateObligations<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let ty::Coroutine(_, args) = self_ty.kind() else { let ty::Coroutine(_, args) = self_ty.kind() else {
@ -1504,7 +1506,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
fn confirm_async_iterator_candidate<'cx, 'tcx>( fn confirm_async_iterator_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>, nested: PredicateObligations<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let ty::Coroutine(_, args) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() let ty::Coroutine(_, args) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
else { else {
@ -1558,7 +1560,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
fn confirm_builtin_candidate<'cx, 'tcx>( fn confirm_builtin_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
data: Vec<PredicateObligation<'tcx>>, data: PredicateObligations<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let tcx = selcx.tcx(); let tcx = selcx.tcx();
let self_ty = obligation.predicate.self_ty(); let self_ty = obligation.predicate.self_ty();
@ -1569,17 +1571,17 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None);
assert_eq!(discriminant_def_id, item_def_id); assert_eq!(discriminant_def_id, item_def_id);
(self_ty.discriminant_ty(tcx).into(), Vec::new()) (self_ty.discriminant_ty(tcx).into(), PredicateObligations::new())
} else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) { } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) {
let destructor_def_id = tcx.associated_item_def_ids(trait_def_id)[0]; let destructor_def_id = tcx.associated_item_def_ids(trait_def_id)[0];
assert_eq!(destructor_def_id, item_def_id); assert_eq!(destructor_def_id, item_def_id);
(self_ty.async_destructor_ty(tcx).into(), Vec::new()) (self_ty.async_destructor_ty(tcx).into(), PredicateObligations::new())
} else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) {
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
assert_eq!(metadata_def_id, item_def_id); assert_eq!(metadata_def_id, item_def_id);
let mut obligations = Vec::new(); let mut obligations = PredicateObligations::new();
let normalize = |ty| { let normalize = |ty| {
normalize_with_depth_to( normalize_with_depth_to(
selcx, selcx,
@ -1627,7 +1629,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
fn confirm_fn_pointer_candidate<'cx, 'tcx>( fn confirm_fn_pointer_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>, nested: PredicateObligations<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let tcx = selcx.tcx(); let tcx = selcx.tcx();
let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
@ -1663,7 +1665,7 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
fn confirm_closure_candidate<'cx, 'tcx>( fn confirm_closure_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>, nested: PredicateObligations<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let tcx = selcx.tcx(); let tcx = selcx.tcx();
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
@ -1782,7 +1784,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
fn confirm_async_closure_candidate<'cx, 'tcx>( fn confirm_async_closure_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>, nested: PredicateObligations<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let tcx = selcx.tcx(); let tcx = selcx.tcx();
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
@ -1934,7 +1936,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>( fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>, nested: PredicateObligations<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let [ let [
// We already checked that the goal_kind >= closure_kind // We already checked that the goal_kind >= closure_kind
@ -1987,7 +1989,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
); );
let cache_projection = cache_entry.projection_term; let cache_projection = cache_entry.projection_term;
let mut nested_obligations = Vec::new(); let mut nested_obligations = PredicateObligations::new();
let obligation_projection = obligation.predicate; let obligation_projection = obligation.predicate;
let obligation_projection = ensure_sufficient_stack(|| { let obligation_projection = ensure_sufficient_stack(|| {
normalize_with_depth_to( normalize_with_depth_to(
@ -2034,7 +2036,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
); );
debug!("confirm_param_env_candidate: {}", msg); debug!("confirm_param_env_candidate: {}", msg);
let err = Ty::new_error_with_message(infcx.tcx, obligation.cause.span, msg); let err = Ty::new_error_with_message(infcx.tcx, obligation.cause.span, msg);
Progress { term: err.into(), obligations: vec![] } Progress { term: err.into(), obligations: PredicateObligations::new() }
} }
} }
} }
@ -2047,6 +2049,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
let tcx = selcx.tcx(); let tcx = selcx.tcx();
let ImplSourceUserDefinedData { impl_def_id, args, mut nested } = impl_impl_source; let ImplSourceUserDefinedData { impl_def_id, args, mut nested } = impl_impl_source;
let assoc_item_id = obligation.predicate.def_id; let assoc_item_id = obligation.predicate.def_id;
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
@ -2102,7 +2105,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
fn assoc_ty_own_obligations<'cx, 'tcx>( fn assoc_ty_own_obligations<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
nested: &mut Vec<PredicateObligation<'tcx>>, nested: &mut PredicateObligations<'tcx>,
) { ) {
let tcx = selcx.tcx(); let tcx = selcx.tcx();
let predicates = tcx let predicates = tcx

View File

@ -4,6 +4,7 @@
use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::sso::SsoHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::traits::PredicateObligations;
use rustc_macros::extension; use rustc_macros::extension;
pub use rustc_middle::traits::query::NormalizationResult; pub use rustc_middle::traits::query::NormalizationResult;
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
@ -20,8 +21,7 @@ use crate::infer::canonical::OriginalQueryValues;
use crate::infer::{InferCtxt, InferOk}; use crate::infer::{InferCtxt, InferOk};
use crate::traits::normalize::needs_normalization; use crate::traits::normalize::needs_normalization;
use crate::traits::{ use crate::traits::{
BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, PredicateObligation, BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, Reveal, ScrubbedTraitError,
Reveal, ScrubbedTraitError,
}; };
#[extension(pub trait QueryNormalizeExt<'tcx>)] #[extension(pub trait QueryNormalizeExt<'tcx>)]
@ -80,7 +80,9 @@ impl<'a, 'tcx> At<'a, 'tcx> {
match crate::solve::deeply_normalize_with_skipped_universes::<_, ScrubbedTraitError<'tcx>>( match crate::solve::deeply_normalize_with_skipped_universes::<_, ScrubbedTraitError<'tcx>>(
self, value, universes, self, value, universes,
) { ) {
Ok(value) => return Ok(Normalized { value, obligations: vec![] }), Ok(value) => {
return Ok(Normalized { value, obligations: PredicateObligations::new() });
}
Err(_errors) => { Err(_errors) => {
return Err(NoSolution); return Err(NoSolution);
} }
@ -88,14 +90,14 @@ impl<'a, 'tcx> At<'a, 'tcx> {
} }
if !needs_normalization(&value, self.param_env.reveal()) { if !needs_normalization(&value, self.param_env.reveal()) {
return Ok(Normalized { value, obligations: vec![] }); return Ok(Normalized { value, obligations: PredicateObligations::new() });
} }
let mut normalizer = QueryNormalizer { let mut normalizer = QueryNormalizer {
infcx: self.infcx, infcx: self.infcx,
cause: self.cause, cause: self.cause,
param_env: self.param_env, param_env: self.param_env,
obligations: vec![], obligations: PredicateObligations::new(),
cache: SsoHashMap::new(), cache: SsoHashMap::new(),
anon_depth: 0, anon_depth: 0,
universes, universes,
@ -164,7 +166,7 @@ struct QueryNormalizer<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>, infcx: &'a InferCtxt<'tcx>,
cause: &'a ObligationCause<'tcx>, cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>, obligations: PredicateObligations<'tcx>,
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>, cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
anon_depth: usize, anon_depth: usize,
universes: Vec<Option<ty::UniverseIndex>>, universes: Vec<Option<ty::UniverseIndex>>,

View File

@ -2,7 +2,7 @@ use std::fmt;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::canonical::Certainty; use rustc_infer::infer::canonical::Certainty;
use rustc_infer::traits::PredicateObligation; use rustc_infer::traits::PredicateObligations;
use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
@ -103,13 +103,13 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
( (
Self::QueryResponse, Self::QueryResponse,
Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>, Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
Vec<PredicateObligation<'tcx>>, PredicateObligations<'tcx>,
Certainty, Certainty,
), ),
NoSolution, NoSolution,
> { > {
if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
return Ok((result, None, vec![], Certainty::Proven)); return Ok((result, None, PredicateObligations::new(), Certainty::Proven));
} }
let mut canonical_var_values = OriginalQueryValues::default(); let mut canonical_var_values = OriginalQueryValues::default();

View File

@ -12,7 +12,9 @@ use hir::LangItem;
use hir::def_id::DefId; use hir::def_id::DefId;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation, SelectionError}; use rustc_infer::traits::{
Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError,
};
use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
@ -963,7 +965,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
0, 0,
// We're *intentionally* throwing these away, // We're *intentionally* throwing these away,
// since we don't actually use them. // since we don't actually use them.
&mut vec![], &mut PredicateObligations::new(),
) )
.as_type() .as_type()
.unwrap(); .unwrap();

View File

@ -24,7 +24,7 @@ use rustc_span::def_id::DefId;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use super::SelectionCandidate::{self, *}; use super::SelectionCandidate::{self, *};
use super::{BuiltinImplConditions, SelectionContext}; use super::{BuiltinImplConditions, PredicateObligations, SelectionContext};
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::util::{self, closure_trait_ref_and_return_type};
use crate::traits::{ use crate::traits::{
@ -85,7 +85,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// No nested obligations or confirmation process. The checks that we do in // No nested obligations or confirmation process. The checks that we do in
// candidate assembly are sufficient. // candidate assembly are sufficient.
AsyncFnKindHelperCandidate => ImplSource::Builtin(BuiltinImplSource::Misc, vec![]), AsyncFnKindHelperCandidate => {
ImplSource::Builtin(BuiltinImplSource::Misc, PredicateObligations::new())
}
CoroutineCandidate => { CoroutineCandidate => {
let vtable_coroutine = self.confirm_coroutine_candidate(obligation)?; let vtable_coroutine = self.confirm_coroutine_candidate(obligation)?;
@ -121,7 +123,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// This indicates something like `Trait + Send: Send`. In this case, we know that // This indicates something like `Trait + Send: Send`. In this case, we know that
// this holds because that's what the object type is telling us, and there's really // this holds because that's what the object type is telling us, and there's really
// no additional obligations to prove and no types in particular to unify, etc. // no additional obligations to prove and no types in particular to unify, etc.
ImplSource::Builtin(BuiltinImplSource::Misc, Vec::new()) ImplSource::Builtin(BuiltinImplSource::Misc, PredicateObligations::new())
} }
BuiltinUnsizeCandidate => self.confirm_builtin_unsize_candidate(obligation)?, BuiltinUnsizeCandidate => self.confirm_builtin_unsize_candidate(obligation)?,
@ -149,7 +151,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
idx: usize, idx: usize,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let tcx = self.tcx(); let tcx = self.tcx();
let placeholder_trait_predicate = let placeholder_trait_predicate =
@ -179,7 +181,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
HigherRankedType, HigherRankedType,
candidate, candidate,
); );
let mut obligations = Vec::new(); let mut obligations = PredicateObligations::new();
let candidate = normalize_with_depth_to( let candidate = normalize_with_depth_to(
self, self,
obligation.param_env, obligation.param_env,
@ -226,7 +228,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
param: ty::PolyTraitRef<'tcx>, param: ty::PolyTraitRef<'tcx>,
) -> Vec<PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
debug!(?obligation, ?param, "confirm_param_candidate"); debug!(?obligation, ?param, "confirm_param_candidate");
// During evaluation, we already checked that this // During evaluation, we already checked that this
@ -249,7 +251,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
has_nested: bool, has_nested: bool,
) -> Vec<PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); debug!(?obligation, ?has_nested, "confirm_builtin_candidate");
let tcx = self.tcx(); let tcx = self.tcx();
@ -279,7 +281,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested, nested,
) )
} else { } else {
vec![] PredicateObligations::new()
}; };
debug!(?obligations); debug!(?obligations);
@ -291,7 +293,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_transmutability_candidate( fn confirm_transmutability_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
use rustc_transmute::{Answer, Assume, Condition}; use rustc_transmute::{Answer, Assume, Condition};
/// Generate sub-obligations for reference-to-reference transmutations. /// Generate sub-obligations for reference-to-reference transmutations.
@ -301,7 +303,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(src_lifetime, src_ty, src_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability), (src_lifetime, src_ty, src_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
(dst_lifetime, dst_ty, dst_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability), (dst_lifetime, dst_ty, dst_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
assume: Assume, assume: Assume,
) -> Vec<PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
let make_transmute_obl = |src, dst| { let make_transmute_obl = |src, dst| {
let transmute_trait = obligation.predicate.def_id(); let transmute_trait = obligation.predicate.def_id();
let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2); let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2);
@ -347,7 +349,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Given a transmutation from `&'a (mut) Src` and `&'dst (mut) Dst`, // Given a transmutation from `&'a (mut) Src` and `&'dst (mut) Dst`,
// it is always the case that `Src` must be transmutable into `Dst`, // it is always the case that `Src` must be transmutable into `Dst`,
// and that that `'src` must outlive `'dst`. // and that that `'src` must outlive `'dst`.
let mut obls = vec![make_transmute_obl(src_ty, dst_ty)]; let mut obls = PredicateObligations::with_capacity(1);
obls.push(make_transmute_obl(src_ty, dst_ty));
if !assume.lifetimes { if !assume.lifetimes {
obls.push(make_outlives_obl(src_lifetime, dst_lifetime)); obls.push(make_outlives_obl(src_lifetime, dst_lifetime));
} }
@ -382,7 +385,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
cond: Condition<rustc_transmute::layout::rustc::Ref<'tcx>>, cond: Condition<rustc_transmute::layout::rustc::Ref<'tcx>>,
assume: Assume, assume: Assume,
) -> Vec<PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
match cond { match cond {
// FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll` // FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll`
// Not possible until the trait solver supports disjunctions of obligations // Not possible until the trait solver supports disjunctions of obligations
@ -424,7 +427,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let fully_flattened = match maybe_transmutable { let fully_flattened = match maybe_transmutable {
Answer::No(_) => Err(Unimplemented)?, Answer::No(_) => Err(Unimplemented)?,
Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, cond, assume), Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, cond, assume),
Answer::Yes => vec![], Answer::Yes => PredicateObligations::new(),
}; };
debug!(?fully_flattened); debug!(?fully_flattened);
@ -439,7 +442,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_auto_impl_candidate( fn confirm_auto_impl_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_auto_impl_candidate"); debug!(?obligation, "confirm_auto_impl_candidate");
let self_ty = obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); let self_ty = obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
@ -453,14 +456,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
trait_def_id: DefId, trait_def_id: DefId,
nested: ty::Binder<'tcx, Vec<Ty<'tcx>>>, nested: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
) -> Vec<PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
debug!(?nested, "vtable_auto_impl"); debug!(?nested, "vtable_auto_impl");
ensure_sufficient_stack(|| { ensure_sufficient_stack(|| {
let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref); let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref);
let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations( let trait_obligations = self.impl_or_trait_obligations(
&cause, &cause,
obligation.recursion_depth + 1, obligation.recursion_depth + 1,
obligation.param_env, obligation.param_env,
@ -566,7 +569,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
); );
let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty); let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty);
let mut nested = vec![]; let mut nested = PredicateObligations::new();
let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref)); let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref));
let unnormalized_upcast_trait_ref = let unnormalized_upcast_trait_ref =
@ -706,7 +709,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
fn_host_effect: ty::Const<'tcx>, fn_host_effect: ty::Const<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_fn_pointer_candidate"); debug!(?obligation, "confirm_fn_pointer_candidate");
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
@ -750,7 +753,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_trait_alias_candidate( fn confirm_trait_alias_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
) -> Vec<PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
debug!(?obligation, "confirm_trait_alias_candidate"); debug!(?obligation, "confirm_trait_alias_candidate");
let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
@ -775,7 +778,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_coroutine_candidate( fn confirm_coroutine_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
@ -805,7 +808,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_future_candidate( fn confirm_future_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
@ -835,7 +838,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_iterator_candidate( fn confirm_iterator_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
@ -865,7 +868,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_async_iterator_candidate( fn confirm_async_iterator_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
@ -896,7 +899,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_closure_candidate( fn confirm_closure_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
@ -926,13 +929,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_async_closure_candidate( fn confirm_async_closure_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
let tcx = self.tcx(); let tcx = self.tcx();
let mut nested = vec![]; let mut nested = PredicateObligations::new();
let (trait_ref, kind_ty) = match *self_ty.kind() { let (trait_ref, kind_ty) = match *self_ty.kind() {
ty::CoroutineClosure(_, args) => { ty::CoroutineClosure(_, args) => {
let args = args.as_coroutine_closure(); let args = args.as_coroutine_closure();
@ -1055,7 +1058,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self, &mut self,
obligation: TraitObligation<'tcx>, obligation: TraitObligation<'tcx>,
found_trait_ref: ty::PolyTraitRef<'tcx>, found_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span, obligation.cause.span,
HigherRankedType, HigherRankedType,
@ -1210,7 +1213,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// words, if the object type is `Foo + Send`, this would create an obligation for // words, if the object type is `Foo + Send`, this would create an obligation for
// the `Send` check.) // the `Send` check.)
// - Projection predicates // - Projection predicates
let mut nested: Vec<_> = data let mut nested: PredicateObligations<'_> = data
.iter() .iter()
.map(|predicate| predicate_to_obligation(predicate.with_self_ty(tcx, source))) .map(|predicate| predicate_to_obligation(predicate.with_self_ty(tcx, source)))
.collect(); .collect();
@ -1254,7 +1257,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tail_field = def.non_enum_variant().tail(); let tail_field = def.non_enum_variant().tail();
let tail_field_ty = tcx.type_of(tail_field.did); let tail_field_ty = tcx.type_of(tail_field.did);
let mut nested = vec![]; let mut nested = PredicateObligations::new();
// Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`, // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`,
// normalizing in the process, since `type_of` returns something directly from // normalizing in the process, since `type_of` returns something directly from
@ -1339,7 +1342,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
impl_def_id: Option<DefId>, impl_def_id: Option<DefId>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let Some(host_effect_index) = let Some(host_effect_index) =
self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
else { else {
@ -1353,7 +1356,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tcx = self.tcx(); let tcx = self.tcx();
let self_ty = obligation.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); let self_ty = obligation.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
let mut nested = vec![]; let mut nested = PredicateObligations::new();
let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
// If we have a custom `impl const Drop`, then // If we have a custom `impl const Drop`, then

View File

@ -18,7 +18,7 @@ use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::relate::TypeRelation; use rustc_infer::infer::relate::TypeRelation;
use rustc_infer::traits::TraitObligation; use rustc_infer::traits::{PredicateObligations, TraitObligation};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds}; use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds};
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
@ -1067,7 +1067,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&& fresh_trait_pred.has_aliases() && fresh_trait_pred.has_aliases()
&& fresh_trait_pred.is_global() && fresh_trait_pred.is_global()
{ {
let mut nested_obligations = Vec::new(); let mut nested_obligations = PredicateObligations::new();
let predicate = normalize_with_depth_to( let predicate = normalize_with_depth_to(
this, this,
param_env, param_env,
@ -1715,7 +1715,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> ProjectionMatchesProjection { ) -> ProjectionMatchesProjection {
debug_assert_eq!(obligation.predicate.def_id, env_predicate.projection_def_id()); debug_assert_eq!(obligation.predicate.def_id, env_predicate.projection_def_id());
let mut nested_obligations = Vec::new(); let mut nested_obligations = PredicateObligations::new();
let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars( let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span, obligation.cause.span,
BoundRegionConversionTime::HigherRankedType, BoundRegionConversionTime::HigherRankedType,
@ -2410,7 +2410,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
recursion_depth: usize, recursion_depth: usize,
trait_def_id: DefId, trait_def_id: DefId,
types: ty::Binder<'tcx, Vec<Ty<'tcx>>>, types: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
) -> Vec<PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
// Because the types were potentially derived from // Because the types were potentially derived from
// higher-ranked obligations they may reference late-bound // higher-ranked obligations they may reference late-bound
// regions. For example, `for<'a> Foo<&'a i32> : Copy` would // regions. For example, `for<'a> Foo<&'a i32> : Copy` would
@ -2552,9 +2552,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
a_region: ty::Region<'tcx>, a_region: ty::Region<'tcx>,
b_region: ty::Region<'tcx>, b_region: ty::Region<'tcx>,
) -> SelectionResult<'tcx, Vec<PredicateObligation<'tcx>>> { ) -> SelectionResult<'tcx, PredicateObligations<'tcx>> {
let tcx = self.tcx(); let tcx = self.tcx();
let mut nested = vec![]; let mut nested = PredicateObligations::new();
// We may upcast to auto traits that are either explicitly listed in // We may upcast to auto traits that are either explicitly listed in
// the object type's bounds, or implied by the principal trait ref's // the object type's bounds, or implied by the principal trait ref's
@ -2705,7 +2705,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
where_clause_trait_ref: ty::PolyTraitRef<'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, ()> { ) -> Result<PredicateObligations<'tcx>, ()> {
self.match_poly_trait_ref(obligation, where_clause_trait_ref) self.match_poly_trait_ref(obligation, where_clause_trait_ref)
} }
@ -2716,7 +2716,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, ()> { ) -> Result<PredicateObligations<'tcx>, ()> {
let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
let trait_ref = self.infcx.instantiate_binder_with_fresh_vars( let trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span, obligation.cause.span,
@ -2797,7 +2797,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
def_id: DefId, // of impl or trait def_id: DefId, // of impl or trait
args: GenericArgsRef<'tcx>, // for impl or trait args: GenericArgsRef<'tcx>, // for impl or trait
parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
) -> Vec<PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
let tcx = self.tcx(); let tcx = self.tcx();
// To allow for one-pass evaluation of the nested obligation, // To allow for one-pass evaluation of the nested obligation,
@ -2817,7 +2817,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
let predicates = tcx.predicates_of(def_id); let predicates = tcx.predicates_of(def_id);
assert_eq!(predicates.parent, None); assert_eq!(predicates.parent, None);
let predicates = predicates.instantiate_own(tcx, args); let predicates = predicates.instantiate_own(tcx, args);
let mut obligations = Vec::with_capacity(predicates.len()); let mut obligations = PredicateObligations::with_capacity(predicates.len());
for (index, (predicate, span)) in predicates.into_iter().enumerate() { for (index, (predicate, span)) in predicates.into_iter().enumerate() {
let cause = if tcx.is_lang_item(parent_trait_pred.def_id(), LangItem::CoerceUnsized) { let cause = if tcx.is_lang_item(parent_trait_pred.def_id(), LangItem::CoerceUnsized) {
cause.clone() cause.clone()

View File

@ -2,7 +2,7 @@ use std::iter;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::traits::ObligationCauseCode; use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable,
@ -27,7 +27,7 @@ pub fn obligations<'tcx>(
recursion_depth: usize, recursion_depth: usize,
arg: GenericArg<'tcx>, arg: GenericArg<'tcx>,
span: Span, span: Span,
) -> Option<Vec<traits::PredicateObligation<'tcx>>> { ) -> Option<PredicateObligations<'tcx>> {
// Handle the "livelock" case (see comment above) by bailing out if necessary. // Handle the "livelock" case (see comment above) by bailing out if necessary.
let arg = match arg.unpack() { let arg = match arg.unpack() {
GenericArgKind::Type(ty) => { GenericArgKind::Type(ty) => {
@ -61,11 +61,18 @@ pub fn obligations<'tcx>(
.into() .into()
} }
// There is nothing we have to do for lifetimes. // There is nothing we have to do for lifetimes.
GenericArgKind::Lifetime(..) => return Some(Vec::new()), GenericArgKind::Lifetime(..) => return Some(PredicateObligations::new()),
}; };
let mut wf = let mut wf = WfPredicates {
WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None }; infcx,
param_env,
body_id,
span,
out: PredicateObligations::new(),
recursion_depth,
item: None,
};
wf.compute(arg); wf.compute(arg);
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
@ -82,7 +89,7 @@ pub fn unnormalized_obligations<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
arg: GenericArg<'tcx>, arg: GenericArg<'tcx>,
) -> Option<Vec<traits::PredicateObligation<'tcx>>> { ) -> Option<PredicateObligations<'tcx>> {
debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg)); debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
// However, if `arg` IS an unresolved inference variable, returns `None`, // However, if `arg` IS an unresolved inference variable, returns `None`,
@ -93,7 +100,7 @@ pub fn unnormalized_obligations<'tcx>(
} }
if let ty::GenericArgKind::Lifetime(..) = arg.unpack() { if let ty::GenericArgKind::Lifetime(..) = arg.unpack() {
return Some(vec![]); return Some(PredicateObligations::new());
} }
let mut wf = WfPredicates { let mut wf = WfPredicates {
@ -101,7 +108,7 @@ pub fn unnormalized_obligations<'tcx>(
param_env, param_env,
body_id: CRATE_DEF_ID, body_id: CRATE_DEF_ID,
span: DUMMY_SP, span: DUMMY_SP,
out: vec![], out: PredicateObligations::new(),
recursion_depth: 0, recursion_depth: 0,
item: None, item: None,
}; };
@ -120,13 +127,13 @@ pub fn trait_obligations<'tcx>(
trait_pred: ty::TraitPredicate<'tcx>, trait_pred: ty::TraitPredicate<'tcx>,
span: Span, span: Span,
item: &'tcx hir::Item<'tcx>, item: &'tcx hir::Item<'tcx>,
) -> Vec<traits::PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
let mut wf = WfPredicates { let mut wf = WfPredicates {
infcx, infcx,
param_env, param_env,
body_id, body_id,
span, span,
out: vec![], out: PredicateObligations::new(),
recursion_depth: 0, recursion_depth: 0,
item: Some(item), item: Some(item),
}; };
@ -147,13 +154,13 @@ pub fn clause_obligations<'tcx>(
body_id: LocalDefId, body_id: LocalDefId,
clause: ty::Clause<'tcx>, clause: ty::Clause<'tcx>,
span: Span, span: Span,
) -> Vec<traits::PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
let mut wf = WfPredicates { let mut wf = WfPredicates {
infcx, infcx,
param_env, param_env,
body_id, body_id,
span, span,
out: vec![], out: PredicateObligations::new(),
recursion_depth: 0, recursion_depth: 0,
item: None, item: None,
}; };
@ -192,7 +199,7 @@ struct WfPredicates<'a, 'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
body_id: LocalDefId, body_id: LocalDefId,
span: Span, span: Span,
out: Vec<traits::PredicateObligation<'tcx>>, out: PredicateObligations<'tcx>,
recursion_depth: usize, recursion_depth: usize,
item: Option<&'tcx hir::Item<'tcx>>, item: Option<&'tcx hir::Item<'tcx>>,
} }
@ -323,7 +330,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
traits::ObligationCause::new(self.span, self.body_id, code) traits::ObligationCause::new(self.span, self.body_id, code)
} }
fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> { fn normalize(self, infcx: &InferCtxt<'tcx>) -> PredicateObligations<'tcx> {
// Do not normalize `wf` obligations with the new solver. // Do not normalize `wf` obligations with the new solver.
// //
// The current deep normalization routine with the new solver does not // The current deep normalization routine with the new solver does not
@ -336,7 +343,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
let cause = self.cause(ObligationCauseCode::WellFormed(None)); let cause = self.cause(ObligationCauseCode::WellFormed(None));
let param_env = self.param_env; let param_env = self.param_env;
let mut obligations = Vec::with_capacity(self.out.len()); let mut obligations = PredicateObligations::with_capacity(self.out.len());
for mut obligation in self.out { for mut obligation in self.out {
assert!(!obligation.has_escaping_bound_vars()); assert!(!obligation.has_escaping_bound_vars());
let mut selcx = traits::SelectionContext::new(infcx); let mut selcx = traits::SelectionContext::new(infcx);
@ -553,7 +560,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
&mut self, &mut self,
def_id: DefId, def_id: DefId,
args: GenericArgsRef<'tcx>, args: GenericArgsRef<'tcx>,
) -> Vec<traits::PredicateObligation<'tcx>> { ) -> PredicateObligations<'tcx> {
let predicates = self.tcx().predicates_of(def_id); let predicates = self.tcx().predicates_of(def_id);
let mut origins = vec![def_id; predicates.predicates.len()]; let mut origins = vec![def_id; predicates.predicates.len()];
let mut head = predicates; let mut head = predicates;

View File

@ -1,5 +1,6 @@
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::traits::PredicateObligations;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@ -30,7 +31,7 @@ fn normalize_canonicalized_projection_ty<'tcx>(
debug_assert!(!ocx.infcx.next_trait_solver()); debug_assert!(!ocx.infcx.next_trait_solver());
let selcx = &mut SelectionContext::new(ocx.infcx); let selcx = &mut SelectionContext::new(ocx.infcx);
let cause = ObligationCause::dummy(); let cause = ObligationCause::dummy();
let mut obligations = vec![]; let mut obligations = PredicateObligations::new();
let answer = let answer =
traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations); traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations);
ocx.register_obligations(obligations); ocx.register_obligations(obligations);
@ -99,7 +100,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>(
|ocx, ParamEnvAnd { param_env, value: goal }| { |ocx, ParamEnvAnd { param_env, value: goal }| {
let selcx = &mut SelectionContext::new(ocx.infcx); let selcx = &mut SelectionContext::new(ocx.infcx);
let cause = ObligationCause::dummy(); let cause = ObligationCause::dummy();
let mut obligations = vec![]; let mut obligations = PredicateObligations::new();
let answer = traits::normalize_inherent_projection( let answer = traits::normalize_inherent_projection(
selcx, selcx,
param_env, param_env,

View File

@ -17,6 +17,7 @@ rustc_serialize = { path = "../rustc_serialize", optional = true }
rustc_span = { path = "../rustc_span", optional = true } rustc_span = { path = "../rustc_span", optional = true }
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
smallvec = { version = "1.8.1", default-features = false } smallvec = { version = "1.8.1", default-features = false }
thin-vec = "0.2.12"
tracing = "0.1" tracing = "0.1"
# tidy-alphabetical-end # tidy-alphabetical-end
@ -30,7 +31,7 @@ nightly = [
"smallvec/may_dangle", "smallvec/may_dangle",
"smallvec/union", "smallvec/union",
"rustc_index/nightly", "rustc_index/nightly",
"rustc_ast_ir/nightly" "rustc_ast_ir/nightly",
] ]
[lints.rust] [lints.rust]

View File

@ -48,6 +48,7 @@
use std::mem; use std::mem;
use rustc_index::{Idx, IndexVec}; use rustc_index::{Idx, IndexVec};
use thin_vec::ThinVec;
use tracing::instrument; use tracing::instrument;
use crate::data_structures::Lrc; use crate::data_structures::Lrc;
@ -322,6 +323,12 @@ impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> {
} }
} }
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for ThinVec<T> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.into_iter().map(|t| t.try_fold_with(folder)).collect()
}
}
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> { impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Vec::from(self).try_fold_with(folder).map(Vec::into_boxed_slice) Vec::from(self).try_fold_with(folder).map(Vec::into_boxed_slice)

View File

@ -47,6 +47,7 @@ use std::ops::ControlFlow;
use rustc_ast_ir::visit::VisitorResult; use rustc_ast_ir::visit::VisitorResult;
use rustc_ast_ir::{try_visit, walk_visitable_list}; use rustc_ast_ir::{try_visit, walk_visitable_list};
use rustc_index::{Idx, IndexVec}; use rustc_index::{Idx, IndexVec};
use thin_vec::ThinVec;
use crate::data_structures::Lrc; use crate::data_structures::Lrc;
use crate::inherent::*; use crate::inherent::*;
@ -184,6 +185,13 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Vec<T> {
} }
} }
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for ThinVec<T> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
walk_visitable_list!(visitor, self.iter());
V::Result::output()
}
}
// `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general // `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general
// case, because we can't return a new slice. But note that there are a couple // case, because we can't return a new slice. But note that there are a couple
// of trivial impls of `TypeFoldable` for specific slice types elsewhere. // of trivial impls of `TypeFoldable` for specific slice types elsewhere.