Auto merge of #156072 - GuillaumeGomez:rollup-9U8oPPe, r=GuillaumeGomez

Rollup of 4 pull requests

Successful merges:

 - rust-lang/rust#154571 (Fix alias path for rustdoc)
 - rust-lang/rust#155749 (`-Znext-solver` Ignore region constraints from the nested goals in leakcheck)
 - rust-lang/rust#156026 (`bufreader::Buffer`: Remove leftover note about `initialized` field)
 - rust-lang/rust#156063 (Map `WSAESHUTDOWN` to `io::ErrorKind::BrokenPipe`)
This commit is contained in:
bors
2026-05-02 04:46:31 +00:00
51 changed files with 572 additions and 185 deletions
@@ -74,7 +74,7 @@ pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<
let assumptions =
elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied());
for &(constraint, constraint_category) in constraints {
for &(constraint, constraint_category, _) in constraints {
constraint.iter_outlives().for_each(|predicate| {
self.convert(predicate, constraint_category, &assumptions);
});
@@ -296,7 +296,7 @@ fn normalize_and_add_type_outlives_constraints(
// FIXME(higher_ranked_auto): What should we do with the assumptions here?
if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints {
next_outlives_predicates.extend(constraints.iter().flat_map(
|(constraint, category)| {
|(constraint, category, _)| {
constraint.iter_outlives().map(|outlives| (outlives, *category))
},
));
@@ -728,6 +728,7 @@ fn region_known_to_outlive<'tcx>(
SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
region_b,
region_a,
ty::VisibleForLeakCheck::Unreachable,
);
})
}
@@ -496,7 +496,12 @@ pub(crate) fn coerce_unsized_info<'tcx>(
}
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
infcx.sub_regions(
SubregionOrigin::RelateObjectBound(span),
r_b,
r_a,
ty::VisibleForLeakCheck::Yes,
);
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
@@ -188,14 +188,14 @@ pub fn instantiate_query_response_and_region_obligations<R>(
let InferOk { value: result_args, obligations } =
self.query_response_instantiation(cause, param_env, original_values, query_response)?;
for (constraint, _category) in &query_response.value.region_constraints.constraints {
for (constraint, _category, vis) in &query_response.value.region_constraints.constraints {
let constraint = instantiate_value(self.tcx, &result_args, *constraint);
match constraint {
ty::RegionConstraint::Outlives(predicate) => {
self.register_outlives_constraint(predicate, cause);
self.register_outlives_constraint(predicate, *vis, cause);
}
ty::RegionConstraint::Eq(predicate) => {
self.register_region_eq_constraint(predicate, cause);
self.register_region_eq_constraint(predicate, *vis, cause);
}
}
}
@@ -288,6 +288,7 @@ pub fn instantiate_nll_query_response_and_region_obligations<R>(
output_query_region_constraints.constraints.push((
ty::RegionEqPredicate(v_o.into(), v_r).into(),
constraint_category,
ty::VisibleForLeakCheck::Yes,
));
}
}
@@ -586,6 +587,7 @@ fn unify_canonical_vars(
SubregionOrigin::RelateRegionParamBound(cause.span, None),
v1,
v2,
ty::VisibleForLeakCheck::Yes,
);
}
(GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
@@ -623,20 +625,24 @@ pub fn make_query_region_constraints<'tcx>(
| ConstraintKind::RegSubReg => {
// Swap regions because we are going from sub (<=) to outlives (>=).
let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub).into();
(constraint, origin.to_constraint_category())
(constraint, origin.to_constraint_category(), c.visible_for_leak_check)
}
ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
let constraint = ty::RegionEqPredicate(c.sup, c.sub).into();
(constraint, origin.to_constraint_category())
(constraint, origin.to_constraint_category(), c.visible_for_leak_check)
}
})
.chain(outlives_obligations.into_iter().map(|obl| {
(
ty::OutlivesPredicate(obl.sup_type.into(), obl.sub_region).into(),
obl.origin.to_constraint_category(),
)
}))
.chain(outlives_obligations.into_iter().map(
|TypeOutlivesConstraint { sub_region, sup_type, origin }| {
(
ty::OutlivesPredicate(sup_type.into(), sub_region).into(),
origin.to_constraint_category(),
// We don't do leak checks for type outlives
ty::VisibleForLeakCheck::Unreachable,
)
},
))
.collect();
QueryRegionConstraints { constraints, assumptions }
+16 -2
View File
@@ -256,19 +256,33 @@ fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
self.probe(|_| probe())
}
fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>, span: Span) {
fn sub_regions(
&self,
sub: ty::Region<'tcx>,
sup: ty::Region<'tcx>,
vis: ty::VisibleForLeakCheck,
span: Span,
) {
self.inner.borrow_mut().unwrap_region_constraints().make_subregion(
SubregionOrigin::RelateRegionParamBound(span, None),
sub,
sup,
vis,
);
}
fn equate_regions(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, span: Span) {
fn equate_regions(
&self,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
vis: ty::VisibleForLeakCheck,
span: Span,
) {
self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(
SubregionOrigin::RelateRegionParamBound(span, None),
a,
b,
vis,
);
}
@@ -149,7 +149,11 @@ fn infer_variable_values(
// Deduplicating constraints is shown to have a positive perf impact.
let mut seen = UnordSet::default();
self.data.constraints.retain(|(constraint, _)| seen.insert(*constraint));
self.data.constraints.retain_mut(|(constraint, _)| {
// We don't want to discern constraints by leak check visibility here
constraint.visible_for_leak_check = ty::VisibleForLeakCheck::Unreachable;
seen.insert(*constraint)
});
if cfg!(debug_assertions) {
self.dump_constraints();
+4 -2
View File
@@ -698,8 +698,9 @@ pub fn sub_regions(
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
vis: ty::VisibleForLeakCheck,
) {
self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b);
self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b, vis);
}
#[instrument(skip(self), level = "debug")]
@@ -708,8 +709,9 @@ pub fn equate_regions(
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
vis: ty::VisibleForLeakCheck,
) {
self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(origin, a, b);
self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(origin, a, b, vis);
}
/// Processes a `Coerce` predicate from the fulfillment context.
@@ -85,11 +85,12 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn register_outlives_constraint(
&self,
ty::OutlivesPredicate(arg, r2): ty::ArgOutlivesPredicate<'tcx>,
vis: ty::VisibleForLeakCheck,
cause: &ObligationCause<'tcx>,
) {
match arg.kind() {
ty::GenericArgKind::Lifetime(r1) => {
self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), cause);
self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), vis, cause);
}
ty::GenericArgKind::Type(ty1) => {
self.register_type_outlives_constraint(ty1, r2, cause);
@@ -101,24 +102,26 @@ pub fn register_outlives_constraint(
pub fn register_region_eq_constraint(
&self,
ty::RegionEqPredicate(r_a, r_b): ty::RegionEqPredicate<'tcx>,
vis: ty::VisibleForLeakCheck,
cause: &ObligationCause<'tcx>,
) {
let origin = SubregionOrigin::from_obligation_cause(cause, || {
SubregionOrigin::RelateRegionParamBound(cause.span, None)
});
self.equate_regions(origin, r_a, r_b);
self.equate_regions(origin, r_a, r_b, vis);
}
pub fn register_region_outlives_constraint(
&self,
ty::OutlivesPredicate(r_a, r_b): ty::RegionOutlivesPredicate<'tcx>,
vis: ty::VisibleForLeakCheck,
cause: &ObligationCause<'tcx>,
) {
let origin = SubregionOrigin::from_obligation_cause(cause, || {
SubregionOrigin::RelateRegionParamBound(cause.span, None)
});
// `'a: 'b` ==> `'b <= 'a`
self.sub_regions(origin, r_b, r_a);
self.sub_regions(origin, r_b, r_a, vis);
}
/// Registers that the given region obligation must be resolved
@@ -577,7 +580,8 @@ fn push_sub_region_constraint(
b: ty::Region<'tcx>,
_constraint_category: ConstraintCategory<'tcx>,
) {
self.sub_regions(origin, a, b)
// We don't do leak check in lexical region resolution
self.sub_regions(origin, a, b, ty::VisibleForLeakCheck::Unreachable)
}
fn push_verify(
@@ -392,10 +392,15 @@ fn iterate_region_constraints(
{
match undo_entry {
&AddConstraint(i) => {
region_constraints.data().constraints[i]
.0
.iter_outlives()
.for_each(|c| each_edge(c.sub, c.sup));
region_constraints.data().constraints[i].0.iter_outlives().for_each(
|Constraint { kind: _, sub, sup, visible_for_leak_check }| {
match visible_for_leak_check {
ty::VisibleForLeakCheck::Yes => each_edge(sub, sup),
ty::VisibleForLeakCheck::No => {}
ty::VisibleForLeakCheck::Unreachable => unreachable!(),
}
},
);
}
&AddVerify(i) => span_bug!(
region_constraints.data().verifys[i].origin.span(),
@@ -410,7 +415,13 @@ fn iterate_region_constraints(
.constraints
.iter()
.flat_map(|(c, _)| c.iter_outlives())
.for_each(|c| each_edge(c.sub, c.sup))
.for_each(|Constraint { kind: _, sub, sup, visible_for_leak_check }| {
match visible_for_leak_check {
ty::VisibleForLeakCheck::Yes => each_edge(sub, sup),
ty::VisibleForLeakCheck::No => {}
ty::VisibleForLeakCheck::Unreachable => unreachable!(),
}
})
}
}
@@ -115,10 +115,11 @@ pub enum ConstraintKind {
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct Constraint<'tcx> {
pub kind: ConstraintKind,
// If `kind` is `VarSubVar` or `VarSubReg`, this must be a `ReVar`.
// If `kind` is `VarSubVar`, `VarSubReg`, `VarEqVar` or `VarEqReg`, this must be a `ReVar`.
pub sub: Region<'tcx>,
// If `kind` is `VarSubVar` or `RegSubVar`, this must be a `ReVar`.
// If `kind` is `VarSubVar`, `RegSubVar` or `VarEqVar`, this must be a `ReVar`.
pub sup: Region<'tcx>,
pub visible_for_leak_check: ty::VisibleForLeakCheck,
}
impl Constraint<'_> {
@@ -127,7 +128,7 @@ pub fn involves_placeholders(&self) -> bool {
}
pub fn iter_outlives(self) -> impl Iterator<Item = Self> {
let Constraint { kind, sub, sup } = self;
let Constraint { kind, sub, sup, visible_for_leak_check } = self;
match kind {
ConstraintKind::VarSubVar
@@ -135,18 +136,42 @@ pub fn iter_outlives(self) -> impl Iterator<Item = Self> {
| ConstraintKind::VarSubReg
| ConstraintKind::RegSubReg => iter::once(self).chain(None),
ConstraintKind::VarEqVar => {
iter::once(Constraint { kind: ConstraintKind::VarSubVar, sub, sup })
.chain(Some(Constraint { kind: ConstraintKind::VarSubVar, sub: sup, sup: sub }))
}
ConstraintKind::VarEqReg => {
iter::once(Constraint { kind: ConstraintKind::VarSubReg, sub, sup })
.chain(Some(Constraint { kind: ConstraintKind::RegSubVar, sub: sup, sup: sub }))
}
ConstraintKind::RegEqReg => {
iter::once(Constraint { kind: ConstraintKind::RegSubReg, sub, sup })
.chain(Some(Constraint { kind: ConstraintKind::RegSubReg, sub: sup, sup: sub }))
}
ConstraintKind::VarEqVar => iter::once(Constraint {
kind: ConstraintKind::VarSubVar,
sub,
sup,
visible_for_leak_check,
})
.chain(Some(Constraint {
kind: ConstraintKind::VarSubVar,
sub: sup,
sup: sub,
visible_for_leak_check,
})),
ConstraintKind::VarEqReg => iter::once(Constraint {
kind: ConstraintKind::VarSubReg,
sub,
sup,
visible_for_leak_check,
})
.chain(Some(Constraint {
kind: ConstraintKind::RegSubVar,
sub: sup,
sup: sub,
visible_for_leak_check,
})),
ConstraintKind::RegEqReg => iter::once(Constraint {
kind: ConstraintKind::RegSubReg,
sub,
sup,
visible_for_leak_check,
})
.chain(Some(Constraint {
kind: ConstraintKind::RegSubReg,
sub: sup,
sup: sub,
visible_for_leak_check,
})),
}
}
}
@@ -457,6 +482,7 @@ pub(super) fn make_eqregion(
origin: SubregionOrigin<'tcx>,
a: Region<'tcx>,
b: Region<'tcx>,
visible_for_leak_check: ty::VisibleForLeakCheck,
) {
if a != b {
// FIXME: We could only emit constraints if `unify_var_{var, value}` fails when
@@ -467,7 +493,12 @@ pub(super) fn make_eqregion(
}
(ReVar(a_vid), ReVar(b_vid), _, _) => {
self.add_constraint(
Constraint { kind: ConstraintKind::VarEqVar, sub: a, sup: b },
Constraint {
kind: ConstraintKind::VarEqVar,
sub: a,
sup: b,
visible_for_leak_check,
},
origin,
);
debug!("make_eqregion: unifying {:?} with {:?}", a_vid, b_vid);
@@ -479,12 +510,22 @@ pub(super) fn make_eqregion(
if reg.is_static() {
// all regions are subregions of static, so don't go bidirectional here
self.add_constraint(
Constraint { kind: ConstraintKind::RegSubVar, sub: reg, sup: var },
Constraint {
kind: ConstraintKind::RegSubVar,
sub: reg,
sup: var,
visible_for_leak_check,
},
origin,
);
} else {
self.add_constraint(
Constraint { kind: ConstraintKind::VarEqReg, sub: var, sup: reg },
Constraint {
kind: ConstraintKind::VarEqReg,
sub: var,
sup: reg,
visible_for_leak_check,
},
origin,
);
}
@@ -500,13 +541,23 @@ pub(super) fn make_eqregion(
(ReStatic, _, st, reg) | (_, ReStatic, reg, st) => {
// all regions are subregions of static, so don't go bidirectional here
self.add_constraint(
Constraint { kind: ConstraintKind::RegSubReg, sub: st, sup: reg },
Constraint {
kind: ConstraintKind::RegSubReg,
sub: st,
sup: reg,
visible_for_leak_check,
},
origin,
);
}
_ => {
self.add_constraint(
Constraint { kind: ConstraintKind::RegEqReg, sub: a, sup: b },
Constraint {
kind: ConstraintKind::RegEqReg,
sub: a,
sup: b,
visible_for_leak_check,
},
origin,
);
}
@@ -520,6 +571,7 @@ pub(super) fn make_subregion(
origin: SubregionOrigin<'tcx>,
sub: Region<'tcx>,
sup: Region<'tcx>,
visible_for_leak_check: ty::VisibleForLeakCheck,
) {
// cannot add constraints once regions are resolved
debug!("origin = {:#?}", origin);
@@ -534,19 +586,33 @@ pub(super) fn make_subregion(
(ReVar(sub_id), ReVar(sup_id)) => {
if sub_id != sup_id {
self.add_constraint(
Constraint { kind: ConstraintKind::VarSubVar, sub, sup },
Constraint {
kind: ConstraintKind::VarSubVar,
sub,
sup,
visible_for_leak_check,
},
origin,
);
}
}
(_, ReVar(_)) => self
.add_constraint(Constraint { kind: ConstraintKind::RegSubVar, sub, sup }, origin),
(ReVar(_), _) => self
.add_constraint(Constraint { kind: ConstraintKind::VarSubReg, sub, sup }, origin),
(_, ReVar(_)) => self.add_constraint(
Constraint { kind: ConstraintKind::RegSubVar, sub, sup, visible_for_leak_check },
origin,
),
(ReVar(_), _) => self.add_constraint(
Constraint { kind: ConstraintKind::VarSubReg, sub, sup, visible_for_leak_check },
origin,
),
_ => {
if sub != sup {
self.add_constraint(
Constraint { kind: ConstraintKind::RegSubReg, sub, sup },
Constraint {
kind: ConstraintKind::RegSubReg,
sub,
sup,
visible_for_leak_check,
},
origin,
)
}
@@ -655,8 +721,12 @@ fn combine_vars(
let new_r = ty::Region::new_var(tcx, c);
for old_r in [a, b] {
match t {
Glb => self.make_subregion(origin.clone(), new_r, old_r),
Lub => self.make_subregion(origin.clone(), old_r, new_r),
Glb => {
self.make_subregion(origin.clone(), new_r, old_r, ty::VisibleForLeakCheck::Yes)
}
Lub => {
self.make_subregion(origin.clone(), old_r, new_r, ty::VisibleForLeakCheck::Yes)
}
}
}
debug!("combine_vars() c={:?}", c);
@@ -223,26 +223,29 @@ fn regions(
match self.ambient_variance {
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
ty::Covariant => {
self.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.make_subregion(origin, b, a);
self.infcx.inner.borrow_mut().unwrap_region_constraints().make_subregion(
origin,
b,
a,
ty::VisibleForLeakCheck::Yes,
);
}
// Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b)
ty::Contravariant => {
self.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.make_subregion(origin, a, b);
self.infcx.inner.borrow_mut().unwrap_region_constraints().make_subregion(
origin,
a,
b,
ty::VisibleForLeakCheck::Yes,
);
}
ty::Invariant => {
self.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.make_eqregion(origin, a, b);
self.infcx.inner.borrow_mut().unwrap_region_constraints().make_eqregion(
origin,
a,
b,
ty::VisibleForLeakCheck::Yes,
);
}
ty::Bivariant => {
unreachable!("Expected bivariance to be handled in relate_with_variance")
+3 -1
View File
@@ -135,7 +135,9 @@ pub fn is_proven(&self) -> bool {
}
}
pub type QueryRegionConstraint<'tcx> = (ty::RegionConstraint<'tcx>, ConstraintCategory<'tcx>);
// FIXME: Convert this into a struct
pub type QueryRegionConstraint<'tcx> =
(ty::RegionConstraint<'tcx>, ConstraintCategory<'tcx>, ty::VisibleForLeakCheck);
#[derive(Default)]
pub struct CanonicalParamEnvCache<'tcx> {
+1 -1
View File
@@ -64,7 +64,7 @@
)]
use rustc_type_ir::inherent;
pub use rustc_type_ir::relate::VarianceDiagInfo;
pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind};
pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind, VisibleForLeakCheck};
pub use rustc_type_ir::*;
#[allow(hidden_glob_reexports, unused_imports)]
use rustc_type_ir::{InferCtxtLike, Interner};
@@ -25,7 +25,7 @@
use crate::resolve::eager_resolve_vars;
use crate::solve::{
CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, Goal,
NestedNormalizationGoals, QueryInput, Response, inspect,
NestedNormalizationGoals, QueryInput, Response, VisibleForLeakCheck, inspect,
};
pub mod canonicalizer;
@@ -99,6 +99,7 @@ pub(super) fn instantiate_and_apply_query_response<D, I>(
param_env: I::ParamEnv,
original_values: &[I::GenericArg],
response: CanonicalResponse<I>,
visible_for_leak_check: VisibleForLeakCheck,
span: I::Span,
) -> (NestedNormalizationGoals<I>, Certainty)
where
@@ -116,7 +117,11 @@ pub(super) fn instantiate_and_apply_query_response<D, I>(
let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } =
&*external_constraints;
register_region_constraints(delegate, region_constraints, span);
register_region_constraints(
delegate,
region_constraints.iter().map(|(c, vis)| (*c, vis.and(visible_for_leak_check))),
span,
);
register_new_opaque_types(delegate, opaque_types, span);
(normalization_nested_goals.clone(), certainty)
@@ -262,21 +267,21 @@ fn unify_query_var_values<D, I>(
fn register_region_constraints<D, I>(
delegate: &D,
constraints: &[ty::RegionConstraint<I>],
constraints: impl IntoIterator<Item = (ty::RegionConstraint<I>, VisibleForLeakCheck)>,
span: I::Span,
) where
D: SolverDelegate<Interner = I>,
I: Interner,
{
for &constraint in constraints {
for (constraint, vis) in constraints {
match constraint {
ty::RegionConstraint::Outlives(ty::OutlivesPredicate(lhs, rhs)) => match lhs.kind() {
ty::GenericArgKind::Lifetime(lhs) => delegate.sub_regions(rhs, lhs, span),
ty::GenericArgKind::Lifetime(lhs) => delegate.sub_regions(rhs, lhs, vis, span),
ty::GenericArgKind::Type(lhs) => delegate.register_ty_outlives(lhs, rhs, span),
ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"),
},
ty::RegionConstraint::Eq(ty::RegionEqPredicate(lhs, rhs)) => {
delegate.equate_regions(lhs, rhs, span)
delegate.equate_regions(lhs, rhs, vis, span)
}
}
}
@@ -1,6 +1,6 @@
use std::ops::Deref;
use rustc_type_ir::solve::{Certainty, Goal, NoSolution};
use rustc_type_ir::solve::{Certainty, Goal, NoSolution, VisibleForLeakCheck};
use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable};
pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
@@ -45,7 +45,9 @@ fn well_formed_goals(
term: <Self::Interner as Interner>::Term,
) -> Option<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>>;
fn make_deduplicated_region_constraints(&self) -> Vec<ty::RegionConstraint<Self::Interner>>;
fn make_deduplicated_region_constraints(
&self,
) -> Vec<(ty::RegionConstraint<Self::Interner>, VisibleForLeakCheck)>;
fn instantiate_canonical<V>(
&self,
@@ -30,7 +30,8 @@
use crate::solve::{
CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, FIXPOINT_STEP_LIMIT,
Goal, GoalEvaluation, GoalSource, GoalStalledOn, HasChanged, MaybeCause,
NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, Response, inspect,
NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, Response, VisibleForLeakCheck,
inspect,
};
mod probe;
@@ -484,11 +485,29 @@ pub(super) fn evaluate_goal_raw(
let has_changed =
if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };
// FIXME: We should revisit and consider removing this after
// *assumptions on binders* is available, like once we had done in the
// stabilization of `-Znext-solver=coherence`(#121848).
// We ignore constraints from the nested goals in leak check. This is to match
// with the old solver's behavior, which has separated evaluation and fulfillment,
// and the former doesn't consider outlives obligations from the later.
let vis = match goal.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(_)
| ty::PredicateKind::DynCompatible(_)
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::ConstEquate(_, _)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::NormalizesTo(_) => VisibleForLeakCheck::No,
ty::PredicateKind::AliasRelate(_, _, _) => VisibleForLeakCheck::Yes,
};
let (normalization_nested_goals, certainty) = instantiate_and_apply_query_response(
self.delegate,
goal.param_env,
&orig_values,
response,
vis,
self.origin_span,
);
@@ -1100,9 +1119,14 @@ pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) {
self.delegate.register_ty_outlives(ty, lt, self.origin_span);
}
pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) {
pub(super) fn register_region_outlives(
&self,
a: I::Region,
b: I::Region,
vis: VisibleForLeakCheck,
) {
// `'a: 'b` ==> `'b <= 'a`
self.delegate.sub_regions(b, a, self.origin_span);
self.delegate.sub_regions(b, a, vis, self.origin_span);
}
/// Computes the list of goals required for `arg` to be well-formed
@@ -1303,7 +1327,7 @@ pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
let mut unique = HashSet::default();
external_constraints
.region_constraints
.retain(|outlives| !outlives.is_trivial() && unique.insert(*outlives));
.retain(|(outlives, _)| !outlives.is_trivial() && unique.insert(*outlives));
let canonical = canonicalize_response(
self.delegate,
@@ -1533,6 +1557,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree<D: SolverDelegate<Interner = I>,
goal.param_env,
&proof_tree.orig_values,
response,
VisibleForLeakCheck::Yes,
origin_span,
);
@@ -101,7 +101,7 @@ fn compute_region_outlives_goal(
goal: Goal<I, ty::OutlivesPredicate<I, I::Region>>,
) -> QueryResult<I> {
let ty::OutlivesPredicate(a, b) = goal.predicate;
self.register_region_outlives(a, b);
self.register_region_outlives(a, b, VisibleForLeakCheck::Yes);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
@@ -1,6 +1,7 @@
use std::collections::hash_map::Entry;
use std::ops::Deref;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::LangItem;
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
@@ -112,6 +113,7 @@ fn compute_goal_fast_path(
SubregionOrigin::RelateRegionParamBound(span, None),
outlives.1,
outlives.0,
ty::VisibleForLeakCheck::Yes,
);
Some(Certainty::Yes)
}
@@ -204,7 +206,9 @@ fn well_formed_goals(
.map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect())
}
fn make_deduplicated_region_constraints(&self) -> Vec<ty::RegionConstraint<'tcx>> {
fn make_deduplicated_region_constraints(
&self,
) -> Vec<(ty::RegionConstraint<'tcx>, ty::VisibleForLeakCheck)> {
// Cannot use `take_registered_region_obligations` as we may compute the response
// inside of a `probe` whenever we have multiple choices inside of the solver.
let region_obligations = self.0.inner.borrow().region_obligations().to_owned();
@@ -217,13 +221,23 @@ fn make_deduplicated_region_constraints(&self) -> Vec<ty::RegionConstraint<'tcx>
)
});
let mut seen = FxHashSet::default();
region_constraints
.constraints
.into_iter()
.filter(|&(outlives, _)| seen.insert(outlives))
.map(|(outlives, _)| outlives)
.collect()
let mut seen = FxHashMap::default();
let mut constraints = vec![];
for (outlives, _, vis) in region_constraints.constraints {
match seen.entry(outlives) {
Entry::Occupied(occupied) => {
let idx = occupied.get();
let (_, prev_vis): &mut (_, ty::VisibleForLeakCheck) =
constraints.get_mut(*idx).unwrap();
*prev_vis = (*prev_vis).or(vis);
}
Entry::Vacant(vacant) => {
vacant.insert(constraints.len());
constraints.push((outlives, vis));
}
}
}
constraints
}
fn instantiate_canonical<V>(
@@ -738,7 +738,7 @@ fn evaluate_nested_obligations(
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => {
let binder = bound_predicate.rebind(binder);
selcx.infcx.enter_forall(binder, |pred| {
selcx.infcx.register_region_outlives_constraint(pred, &dummy_cause);
selcx.infcx.register_region_outlives_constraint(pred, ty::VisibleForLeakCheck::Yes,&dummy_cause);
});
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => {
@@ -484,7 +484,11 @@ fn process_obligation(
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
if infcx.considering_regions {
infcx.register_region_outlives_constraint(data, &obligation.cause);
infcx.register_region_outlives_constraint(
data,
ty::VisibleForLeakCheck::Yes,
&obligation.cause,
);
}
ProcessResult::Changed(Default::default())
@@ -83,13 +83,13 @@ fn implied_outlives_bounds<'a, 'tcx>(
// outlives bound required proving some higher-ranked coroutine obl.
let QueryRegionConstraints { constraints, assumptions: _ } = constraints;
let cause = ObligationCause::misc(span, body_id);
for &(constraint, _) in &constraints {
for &(constraint, _, vis) in &constraints {
match constraint {
ty::RegionConstraint::Outlives(predicate) => {
infcx.register_outlives_constraint(predicate, &cause)
infcx.register_outlives_constraint(predicate, vis, &cause)
}
ty::RegionConstraint::Eq(predicate) => {
infcx.register_region_eq_constraint(predicate, &cause)
infcx.register_region_eq_constraint(predicate, vis, &cause)
}
}
}
@@ -80,7 +80,7 @@ fn compute_assumptions<'tcx>(
tcx.mk_outlives_from_iter(
constraints
.into_iter()
.flat_map(|(constraint, _)| constraint.iter_outlives())
.flat_map(|(constraint, _, _)| constraint.iter_outlives())
// FIXME(higher_ranked_auto): We probably should deeply resolve these before
// filtering out infers which only correspond to unconstrained infer regions
// which we can sometimes get.
+3
View File
@@ -8,6 +8,7 @@
use crate::inherent::*;
use crate::relate::RelateResult;
use crate::relate::combine::PredicateEmittingRelation;
use crate::solve::VisibleForLeakCheck;
use crate::{self as ty, Interner, TyVid};
/// The current typing mode of an inference context. We unfortunately have some
@@ -323,6 +324,7 @@ fn sub_regions(
&self,
sub: <Self::Interner as Interner>::Region,
sup: <Self::Interner as Interner>::Region,
vis: VisibleForLeakCheck,
span: <Self::Interner as Interner>::Span,
);
@@ -330,6 +332,7 @@ fn equate_regions(
&self,
a: <Self::Interner as Interner>::Region,
b: <Self::Interner as Interner>::Region,
vis: VisibleForLeakCheck,
span: <Self::Interner as Interner>::Span,
);
+1
View File
@@ -58,6 +58,7 @@ fn visit_with<F: $crate::TypeVisitor<I>>(
crate::solve::BuiltinImplSource,
crate::solve::Certainty,
crate::solve::GoalSource,
crate::solve::VisibleForLeakCheck,
rustc_ast_ir::Mutability,
// tidy-alphabetical-end
}
@@ -4,7 +4,7 @@
use crate::data_structures::DelayedSet;
use crate::relate::combine::combine_ty_args;
pub use crate::relate::*;
use crate::solve::Goal;
use crate::solve::{Goal, VisibleForLeakCheck};
use crate::{self as ty, InferCtxtLike, Interner};
pub trait RelateExt: InferCtxtLike {
@@ -256,10 +256,10 @@ fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty> {
fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region> {
match self.ambient_variance {
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
ty::Covariant => self.infcx.sub_regions(b, a, self.span),
ty::Covariant => self.infcx.sub_regions(b, a, VisibleForLeakCheck::Yes, self.span),
// Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b)
ty::Contravariant => self.infcx.sub_regions(a, b, self.span),
ty::Invariant => self.infcx.equate_regions(a, b, self.span),
ty::Contravariant => self.infcx.sub_regions(a, b, VisibleForLeakCheck::Yes, self.span),
ty::Invariant => self.infcx.equate_regions(a, b, VisibleForLeakCheck::Yes, self.span),
ty::Bivariant => {
unreachable!("Expected bivariance to be handled in relate_with_variance")
}
+42 -1
View File
@@ -250,7 +250,7 @@ impl<I: Interner> Eq for Response<I> {}
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
pub struct ExternalConstraintsData<I: Interner> {
pub region_constraints: Vec<ty::RegionConstraint<I>>,
pub region_constraints: Vec<(ty::RegionConstraint<I>, VisibleForLeakCheck)>,
pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
pub normalization_nested_goals: NestedNormalizationGoals<I>,
}
@@ -265,6 +265,47 @@ pub fn is_empty(&self) -> bool {
}
}
/// Whether the given region constraint should be considered/ignored for
/// leak check. In most part of the compiler, this should be `Yes`, except
/// for applying constraints from the nested goals in next-solver.
/// `Unreachable` is used in places in which leak check isn't done, e.g.
/// borrowck.
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
pub enum VisibleForLeakCheck {
Yes,
No,
Unreachable,
}
impl VisibleForLeakCheck {
pub fn and(self, other: VisibleForLeakCheck) -> VisibleForLeakCheck {
match (self, other) {
// Make sure that we never overwrite that constraints shouldn't
// be encountered by the leak checked
(VisibleForLeakCheck::Unreachable, _) | (_, VisibleForLeakCheck::Unreachable) => {
VisibleForLeakCheck::Unreachable
}
(VisibleForLeakCheck::No, _) | (_, VisibleForLeakCheck::No) => VisibleForLeakCheck::No,
(VisibleForLeakCheck::Yes, VisibleForLeakCheck::Yes) => VisibleForLeakCheck::Yes,
}
}
pub fn or(self, other: VisibleForLeakCheck) -> VisibleForLeakCheck {
match (self, other) {
// Make sure that we never overwrite that constraints shouldn't
// be encountered by the leak checked
(VisibleForLeakCheck::Unreachable, _) | (_, VisibleForLeakCheck::Unreachable) => {
VisibleForLeakCheck::Unreachable
}
(VisibleForLeakCheck::Yes, _) | (_, VisibleForLeakCheck::Yes) => {
VisibleForLeakCheck::Yes
}
(VisibleForLeakCheck::No, VisibleForLeakCheck::No) => VisibleForLeakCheck::No,
}
}
}
#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
@@ -23,9 +23,8 @@ pub struct Buffer {
filled: usize,
// Whether `buf` has been fully initialized. We track this so that we can accurately tell
// `read_buf` how many bytes of buf are initialized, to bypass as much of its defensive
// initialization as possible. Note that while this often the same as `filled`, it doesn't need
// to be. Calls to `fill_buf` are not required to actually fill the buffer, and omitting this
// is a huge perf regression for `Read` impls that do not.
// initialization as possible. Calls to `fill_buf` are not required to actually fill the buffer,
// and omitting this is a huge perf regression for `Read` impls that do not.
initialized: bool,
}
+4
View File
@@ -81,6 +81,10 @@ pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
c::WSAENETDOWN => NetworkDown,
c::WSAENETUNREACH => NetworkUnreachable,
c::WSAEDQUOT => QuotaExceeded,
// Not a perfect mapping but this error is only returned when writing to
// a socket after shutting down the write-end. On Unix targets, EPIPE is
// returned in those cases.
c::WSAESHUTDOWN => BrokenPipe,
_ => Uncategorized,
}
+1 -1
View File
@@ -706,7 +706,7 @@ impl Step for $name {
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path($path) $( .path( $alt_path ) )*
run.selectors(&[$path $(, $alt_path )*])
}
fn is_default_step(_builder: &Builder<'_>) -> bool {
+1 -1
View File
@@ -3235,7 +3235,7 @@ impl Step for CrateRustdoc {
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/librustdoc").path("src/tools/rustdoc")
run.selectors(&["src/librustdoc", "src/tools/rustdoc"])
}
fn is_default_step(_builder: &Builder<'_>) -> bool {
+1 -1
View File
@@ -689,7 +689,7 @@ impl Step for Rustdoc {
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rustdoc").path("src/librustdoc")
run.selectors(&["src/tools/rustdoc", "src/librustdoc"])
}
fn is_default_step(_builder: &Builder<'_>) -> bool {
@@ -96,5 +96,4 @@ expression: bench
- Set({bench::compiler/rustc_windows_rc})
[Bench] test::CrateRustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({bench::src/librustdoc})
- Set({bench::src/tools/rustdoc})
- Set({bench::src/librustdoc, bench::src/tools/rustdoc})
@@ -19,5 +19,4 @@ expression: build
- Set({build::library/unwind})
[Build] tool::Rustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({build::src/librustdoc})
- Set({build::src/tools/rustdoc})
- Set({build::src/librustdoc, build::src/tools/rustdoc})
@@ -80,8 +80,7 @@ expression: check
- Set({check::compiler/rustc_windows_rc})
[Check] check::Rustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({check::src/librustdoc})
- Set({check::src/tools/rustdoc})
- Set({check::src/librustdoc, check::src/tools/rustdoc})
[Check] check::CraneliftCodegenBackend
targets: [x86_64-unknown-linux-gnu]
- Set({check::cg_clif})
@@ -80,8 +80,7 @@ expression: check compiletest --include-default-paths
- Set({check::compiler/rustc_windows_rc})
[Check] check::Rustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({check::src/librustdoc})
- Set({check::src/tools/rustdoc})
- Set({check::src/librustdoc, check::src/tools/rustdoc})
[Check] check::CraneliftCodegenBackend
targets: [x86_64-unknown-linux-gnu]
- Set({check::cg_clif})
@@ -80,8 +80,7 @@ expression: fix
- Set({fix::compiler/rustc_windows_rc})
[Fix] check::Rustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({fix::src/librustdoc})
- Set({fix::src/tools/rustdoc})
- Set({fix::src/librustdoc, fix::src/tools/rustdoc})
[Fix] check::CraneliftCodegenBackend
targets: [x86_64-unknown-linux-gnu]
- Set({fix::cg_clif})
@@ -146,8 +146,7 @@ expression: test
- Set({test::compiler/rustc_windows_rc})
[Test] test::CrateRustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/librustdoc})
- Set({test::src/tools/rustdoc})
- Set({test::src/librustdoc, test::src/tools/rustdoc})
[Test] test::CrateRustdocJsonTypes
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/rustdoc-json-types})
@@ -4,8 +4,7 @@ expression: test librustdoc rustdoc
---
[Test] test::CrateRustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/librustdoc})
- Set({test::src/tools/rustdoc})
- Set({test::src/librustdoc, test::src/tools/rustdoc})
[Test] test::RustdocBook
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/doc/rustdoc})
@@ -145,8 +145,7 @@ expression: test --skip=coverage
- Set({test::compiler/rustc_windows_rc})
[Test] test::CrateRustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/librustdoc})
- Set({test::src/tools/rustdoc})
- Set({test::src/librustdoc, test::src/tools/rustdoc})
[Test] test::CrateRustdocJsonTypes
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/rustdoc-json-types})
@@ -109,8 +109,7 @@ expression: test --skip=tests
- Set({test::compiler/rustc_windows_rc})
[Test] test::CrateRustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/librustdoc})
- Set({test::src/tools/rustdoc})
- Set({test::src/librustdoc, test::src/tools/rustdoc})
[Test] test::CrateRustdocJsonTypes
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/rustdoc-json-types})
@@ -89,8 +89,7 @@ expression: test --skip=tests --skip=coverage-map --skip=coverage-run --skip=lib
- Set({test::compiler/rustc_windows_rc})
[Test] test::CrateRustdoc
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/librustdoc})
- Set({test::src/tools/rustdoc})
- Set({test::src/librustdoc, test::src/tools/rustdoc})
[Test] test::CrateRustdocJsonTypes
targets: [x86_64-unknown-linux-gnu]
- Set({test::src/rustdoc-json-types})
+21 -5
View File
@@ -356,7 +356,7 @@ pub enum PathSet {
/// command-line value of `std` will match if `library/std` is in the
/// set.
///
/// NOTE: the paths within a set should always be aliases of one another.
/// NOTE: the paths within a set should all select the same unit of work.
/// For example, `src/librustdoc` and `src/tools/rustdoc` should be in the same set,
/// but `library/core` and `library/std` generally should not, unless there's no way (for that Step)
/// to build them separately.
@@ -555,10 +555,7 @@ pub fn alias(mut self, alias: &str) -> Self {
self
}
/// single, non-aliased path
///
/// Must be an on-disk path; use `alias` for names that do not correspond to on-disk paths.
pub fn path(mut self, path: &str) -> Self {
fn assert_valid_path(&self, path: &str) {
let submodules_paths = self.builder.submodule_paths();
// assert only if `p` isn't submodule
@@ -568,12 +565,31 @@ pub fn path(mut self, path: &str) -> Self {
"`should_run.path` should correspond to a real on-disk path - use `alias` if there is no relevant path: {path}"
);
}
}
/// A single path
///
/// Must be an on-disk path; use [`alias`][Self::alias] for names that do not
/// correspond to on-disk paths.
pub fn path(mut self, path: &str) -> Self {
self.assert_valid_path(path);
let task = TaskPath { path: path.into(), kind: Some(self.kind) };
self.paths.insert(PathSet::Set(BTreeSet::from_iter([task])));
self
}
/// Multiple on-disk paths that should select the same unit of work.
pub fn selectors(mut self, paths: &[&str]) -> Self {
let mut set = BTreeSet::new();
for path in paths {
self.assert_valid_path(path);
set.insert(TaskPath { path: (*path).into(), kind: Some(self.kind) });
}
self.paths.insert(PathSet::Set(set));
self
}
/// Handles individual files (not directories) within a test suite.
fn is_suite_path(&self, requested_path: &Path) -> Option<&PathSet> {
self.paths.iter().find(|pathset| match pathset {
+23
View File
@@ -2400,6 +2400,29 @@ fn test_exclude_kind() {
steps.assert_contains_fuzzy(StepMetadata::build("rustc", host));
}
#[test]
fn test_exclude_rustdoc_aliases() {
let ctx = TestCtx::new();
let host = TargetSelection::from_user(&host_target());
let get_steps = |args: &[&str]| ctx.config("build").args(args).get_steps();
for args in [
["--skip", "rustdoc"].as_slice(),
["--skip", "src/tools/rustdoc"].as_slice(),
["--skip", "src/librustdoc"].as_slice(),
] {
let steps = get_steps(args);
steps.assert_contains_fuzzy(StepMetadata::build("rustc", host));
steps.assert_no_match(|metadata| {
metadata.name == "rustdoc"
&& metadata.kind == Kind::Build
&& metadata.target == host
});
}
}
#[test]
fn test_cargo_stage_1() {
let ctx = TestCtx::new();
-32
View File
@@ -1,32 +0,0 @@
//@ known-bug: #140577
//@ compile-flags: -Znext-solver=globally
//@ edition:2021
use std::future::Future;
use std::pin::Pin;
trait Acquire {
type Connection;
}
impl Acquire for &'static () {
type Connection = ();
}
fn b<T: Acquire>() -> impl Future + Send {
let x: Pin<Box<dyn Future<Output = T::Connection> + Send>> = todo!();
x
}
fn main() {
async {
b::<&()>().await;
}
.aa();
}
impl<F> Filter for F where F: Send {}
trait Filter {
fn aa(self)
where
Self: Sized,
{
}
}
@@ -2,12 +2,10 @@ error[E0308]: mismatched types
--> $DIR/must-prove-where-clauses-on-norm.rs:23:61
|
LL | let func: for<'a, 'b> fn((), &'b str) -> &'static str = foo::<()>;
| ------------------------------------------- ^^^^^^^^^ one type is more general than the other
| |
| expected due to this
| ^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'b> fn((), &'b _) -> &'static _`
found fn item `for<'b> fn(<() as Trait>::Assoc<'_, 'b>, &'b _) -> &_ {foo::<'_, ()>}`
= note: expected fn pointer `for<'b> fn((), &'b _) -> &_`
found fn pointer `for<'b> fn((), &'b _) -> &_`
error: aborting due to 1 previous error
@@ -1,14 +1,8 @@
error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
--> $DIR/candidate-from-env-universe-err-project.rs:38:24
error: higher-ranked subtype error
--> $DIR/candidate-from-env-universe-err-project.rs:38:5
|
LL | projection_bound::<T>();
| ^ types differ
|
note: required by a bound in `projection_bound`
--> $DIR/candidate-from-env-universe-err-project.rs:19:42
|
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^ required by this bound in `projection_bound`
| ^^^^^^^^^^^^^^^^^^^^^
error: higher-ranked subtype error
--> $DIR/candidate-from-env-universe-err-project.rs:52:30
@@ -26,4 +20,3 @@ LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0271`.
@@ -36,7 +36,7 @@ fn function2<T: Trait<'static, Assoc = usize>>() {
// does not use the leak check when trying the where-bound, causing us
// to prefer it over the impl, resulting in a placeholder error.
projection_bound::<T>();
//[next]~^ ERROR type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
//[next]~^ ERROR higher-ranked subtype error
//[current]~^^ ERROR mismatched types
}
@@ -0,0 +1,45 @@
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ edition:2021
// Regression test for <https://github.com/rust-lang/rust/issues/140577>.
//
// This previously caused an ICE due to a nonwell-formed opaque type
// in a coroutine witness failing the leak check in the next-solver.
//
// In `TypingMode::Analysis`, the problematic type is hidden behind a
// stalled coroutine candidate. However, in later passes (e.g. MIR
// validation), we eagerly normalize it. The candidate that was
// previously accepted as a solution then fails the leak check, resulting
// in broken MIR and ultimately an ICE.
use std::future::Future;
use std::pin::Pin;
trait Acquire {
type Connection;
}
impl Acquire for &'static () {
type Connection = ();
}
fn b<T: Acquire>() -> impl Future + Send {
let x: Pin<Box<dyn Future<Output = T::Connection> + Send>> = todo!();
x
}
fn main() {
async {
b::<&()>().await;
}
.aa();
}
impl<F> Filter for F where F: Send {}
trait Filter {
fn aa(self)
where
Self: Sized,
{
}
}
@@ -0,0 +1,50 @@
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ edition: 2021
// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/251>.
//
// This previously caused an ICE due to a nonwell-formed opaque type
// in a coroutine witness failing the leak check in the next-solver.
//
// In `TypingMode::Analysis`, the problematic type is hidden behind a
// stalled coroutine candidate. However, in later passes (e.g. MIR
// validation), we eagerly normalize it. The candidate that was
// previously accepted as a solution then fails the leak check, resulting
// in broken MIR and ultimately an ICE.
use std::future::Future;
trait Access {
// has to have an associated type, but can be anything
type Reader;
fn read(&self) -> impl Future<Output = Self::Reader> + Send {
async { loop {} }
}
}
trait AccessDyn: Sync {}
impl Access for dyn AccessDyn {
type Reader = ();
}
trait Stream {
fn poll_next(s: &'static dyn AccessDyn);
}
// has to be a function in a trait impl, can't be a normal impl block or standalone fn
impl Stream for () {
fn poll_next(s: &'static dyn AccessDyn) {
// new async block is important
is_dyn_send(&async {
s.read().await;
});
}
}
fn is_dyn_send(_: &dyn Send) {}
fn main() {}
@@ -0,0 +1,36 @@
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ edition:2021
// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/251>.
//
// This previously caused an ICE due to a nonwell-formed opaque type
// in a coroutine witness failing the leak check in the next-solver.
//
// In `TypingMode::Analysis`, the problematic type is hidden behind a
// stalled coroutine candidate. However, in later passes (e.g. MIR
// validation), we eagerly normalize it. The candidate that was
// previously accepted as a solution then fails the leak check, resulting
// in broken MIR and ultimately an ICE.
trait Trait {
type Assoc;
}
impl Trait for &'static u32 {
type Assoc = ();
}
struct W<T: Trait>(T::Assoc);
fn prove_send_and_hide<T: Send>(x: T) -> impl Send { x }
fn as_dyn_send(_: &dyn Send) {}
pub fn main() {
// Checking whether the cast to the trait object is correct
// during MIR validation uses `TypingMode::PostAnalysis` and
// therefore looks into the opaque.
as_dyn_send(&async move {
let opaque_ty = prove_send_and_hide(W::<&'static u32>(()));
std::future::ready(opaque_ty).await;
});
}
@@ -0,0 +1,48 @@
//@ run-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// Regression test for <https://github.com/rust-lang/rust/issues/153596>.
#![allow(warnings)]
trait Trait {
type Assoc;
}
impl<'a, 'b: 'a> Trait for Inv<'a, 'b> {
type Assoc = ();
}
trait ReqWf {}
impl<T: Trait> ReqWf for T where T::Assoc: Sized {}
struct Inv<'a, 'b: 'a>(Option<*mut &'a &'b ()>);
fn mk_opaque<'a, 'b>(x: &'a &'b u32) -> impl ReqWf + use<'a, 'b> {
Inv::<'a, 'b>(None)
}
trait Bound<T> {}
impl<T, F, R: ReqWf> Bound<T> for F where F: FnOnce(T) -> R {}
trait ImpossiblePredicates<F> {
fn call_me(&self)
where
F: for<'a, 'b> Bound<&'a &'b u32>,
{
println!("method body");
}
}
impl<F> ImpossiblePredicates<F> for () {}
fn mk_trait_object<F>(_: F) -> Box<dyn ImpossiblePredicates<F>> {
Box::new(())
}
pub fn main() {
let obj = mk_trait_object(mk_opaque);
// This previously caused a segfault: the where-bounds of
// `ImpossiblePredicate::call_me` did not hold due to missing implied bounds
// for the fully normalized opaque type of `obj` in `fn impossible_predicates`.
// As a result, the method's vtable ended up empty.
//
// However, earlier compilation passes did not report an error because the
// opaque type had not yet been fully normalized.
obj.call_me();
}