diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 868c6f11b68dc..bca2de041b657 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { 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 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // 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)) }, )); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 05d16d2ddb49c..3242fe30d0165 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -728,6 +728,7 @@ fn region_known_to_outlive<'tcx>( SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), region_b, region_a, + ty::VisibleForLeakCheck::Unreachable, ); }) } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 4a10bde4d6da3..c983a03f613bb 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -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)) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5203b4ee5d99f..bc159ee8a004c 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -188,14 +188,14 @@ impl<'tcx> InferCtxt<'tcx> { 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 @@ impl<'tcx> InferCtxt<'tcx> { output_query_region_constraints.constraints.push(( ty::RegionEqPredicate(v_o.into(), v_r).into(), constraint_category, + ty::VisibleForLeakCheck::Yes, )); } } @@ -586,6 +587,7 @@ impl<'tcx> InferCtxt<'tcx> { 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 } diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index fada30ff30633..74da4d4c6db8b 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -256,19 +256,33 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { 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, ); } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 9e5c31eecbe77..e6af7b30f4ad3 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -149,7 +149,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // 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(); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 26c03066c7e40..05043f8617a92 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -698,8 +698,9 @@ impl<'tcx> InferCtxt<'tcx> { 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 @@ impl<'tcx> InferCtxt<'tcx> { 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. diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index e98bee3b12cde..c4ca9e9ac9c57 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -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 @@ impl<'tcx> InferCtxt<'tcx> { 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 @@ impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> { b: ty::Region<'tcx>, _constraint_category: ConstraintCategory<'tcx>, ) { - self.sub_regions(origin, a, b) + // We don't do leak check in borrowck + self.sub_regions(origin, a, b, ty::VisibleForLeakCheck::Unreachable) } fn push_verify( diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 81a3ca6755d20..a1c32a3c0396b 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -392,10 +392,15 @@ impl<'tcx> MiniGraph<'tcx> { { 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 @@ impl<'tcx> MiniGraph<'tcx> { .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!(), + } + }) } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 38b87eb7a9863..03bcb5215ee1a 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -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 @@ impl Constraint<'_> { } pub fn iter_outlives(self) -> impl Iterator { - let Constraint { kind, sub, sup } = self; + let Constraint { kind, sub, sup, visible_for_leak_check } = self; match kind { ConstraintKind::VarSubVar @@ -135,18 +136,42 @@ impl Constraint<'_> { | 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 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { 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 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } (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 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { 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 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { (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 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { 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 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { (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 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { 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); diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 408e2a055f1ef..595392fcfb524 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -223,26 +223,29 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, 'tcx> { 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") diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 033e3e36b0247..f6b0b89874d25 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -135,7 +135,9 @@ impl<'tcx, R> QueryResponse<'tcx, R> { } } -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> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 914fb43147156..837b3cf8c7704 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -64,7 +64,7 @@ pub use rustc_type_ir::fast_reject::DeepRejectCtxt; )] 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}; diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index b4a2eab2e838a..7ecb7466d623c 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -25,7 +25,7 @@ use crate::delegate::SolverDelegate; 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( param_env: I::ParamEnv, original_values: &[I::GenericArg], response: CanonicalResponse, + visible_for_leak_check: VisibleForLeakCheck, span: I::Span, ) -> (NestedNormalizationGoals, Certainty) where @@ -116,7 +117,11 @@ where 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( fn register_region_constraints( delegate: &D, - constraints: &[ty::RegionConstraint], + constraints: impl IntoIterator, VisibleForLeakCheck)>, span: I::Span, ) where D: SolverDelegate, 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) } } } diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 7cf4e8a9238a5..541276f5925da 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -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 + Sized { @@ -45,7 +45,9 @@ pub trait SolverDelegate: Deref + Sized { term: ::Term, ) -> Option::Predicate>>>; - fn make_deduplicated_region_constraints(&self) -> Vec>; + fn make_deduplicated_region_constraints( + &self, + ) -> Vec<(ty::RegionConstraint, VisibleForLeakCheck)>; fn instantiate_canonical( &self, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 278e1f7c0794c..9e4c5e0f5ec53 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -30,7 +30,8 @@ use crate::solve::ty::may_use_unstable_feature; 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 @@ where 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 @@ where 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 @@ where 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, goal.param_env, &proof_tree.orig_values, response, + VisibleForLeakCheck::Yes, origin_span, ); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 1df5a80cf29ad..6f05df707ad84 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -101,7 +101,7 @@ where goal: Goal>, ) -> QueryResult { 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) } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 05ecc4725a7b6..f4173c016726b 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,6 +1,8 @@ +use std::collections::hash_map::Entry; use std::ops::Deref; -use rustc_data_structures::fx::FxHashSet; +use itertools::Itertools; +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 +114,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< SubregionOrigin::RelateRegionParamBound(span, None), outlives.1, outlives.0, + ty::VisibleForLeakCheck::Yes, ); Some(Certainty::Yes) } @@ -204,7 +207,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect()) } - fn make_deduplicated_region_constraints(&self) -> Vec> { + 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 +222,25 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ) }); - 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![]; + let mut visibilities = 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 = + visibilities.get_mut(*idx).unwrap(); + *prev_vis = (*prev_vis).or(vis); + } + Entry::Vacant(vacant) => { + vacant.insert(visibilities.len()); + constraints.push(outlives); + visibilities.push(vis); + } + } + } + constraints.into_iter().zip_eq(visibilities.into_iter()).collect() } fn instantiate_canonical( diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index f28e6f32b5f86..ef99b7772d6be 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -738,7 +738,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { 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)) => { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 2992e396c1b99..0b1d4a8453d05 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -484,7 +484,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { 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()) diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 8bbdc9d76c514..8be26fed0ca42 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -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) } } } diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 0dd4ea823c949..83a77f17b28ce 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -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. diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 905b005cd48f8..2ecc4ebec1500 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -8,6 +8,7 @@ use crate::fold::TypeFoldable; 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 @@ pub trait InferCtxtLike: Sized { &self, sub: ::Region, sup: ::Region, + vis: VisibleForLeakCheck, span: ::Span, ); @@ -330,6 +332,7 @@ pub trait InferCtxtLike: Sized { &self, a: ::Region, b: ::Region, + vis: VisibleForLeakCheck, span: ::Span, ); diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 9064f13eb45e9..857738d207b4f 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -58,6 +58,7 @@ TrivialTypeTraversalImpls! { crate::solve::BuiltinImplSource, crate::solve::Certainty, crate::solve::GoalSource, + crate::solve::VisibleForLeakCheck, rustc_ast_ir::Mutability, // tidy-alphabetical-end } diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index 82ee4f75fcb0a..a643d22c17643 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -4,7 +4,7 @@ use self::combine::{PredicateEmittingRelation, super_combine_consts, super_combi 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 @@ where fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult { 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") } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 0328a819d9b01..f1b84902c2308 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -250,7 +250,7 @@ impl Eq for Response {} #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct ExternalConstraintsData { - pub region_constraints: Vec>, + pub region_constraints: Vec<(ty::RegionConstraint, VisibleForLeakCheck)>, pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, pub normalization_nested_goals: NestedNormalizationGoals, } @@ -265,6 +265,44 @@ impl ExternalConstraintsData { } } +/// 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 the constraints shouldn't be 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) { + (VisibleForLeakCheck::Yes, _) | (_, VisibleForLeakCheck::Yes) => { + VisibleForLeakCheck::Yes + } + (VisibleForLeakCheck::No, _) | (_, VisibleForLeakCheck::No) => VisibleForLeakCheck::No, + (VisibleForLeakCheck::Unreachable, VisibleForLeakCheck::Unreachable) => { + VisibleForLeakCheck::Unreachable + } + } + } +} + #[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] diff --git a/tests/crashes/140577.rs b/tests/crashes/140577.rs deleted file mode 100644 index 21e6b1e1522fb..0000000000000 --- a/tests/crashes/140577.rs +++ /dev/null @@ -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() -> impl Future + Send { - let x: Pin + Send>> = todo!(); - x -} -fn main() { - async { - b::<&()>().await; - } - .aa(); -} - -impl Filter for F where F: Send {} - -trait Filter { - fn aa(self) - where - Self: Sized, - { - } -} diff --git a/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr b/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr index ab51e2bdae77f..27418eb05dc7d 100644 --- a/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr +++ b/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr @@ -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 diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr index ddfc94da1354c..dcf0ed0931995 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr @@ -1,14 +1,8 @@ -error[E0271]: type mismatch resolving `>::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::(); - | ^ types differ - | -note: required by a bound in `projection_bound` - --> $DIR/candidate-from-env-universe-err-project.rs:19:42 - | -LL | fn projection_bound 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(>::Assoc) = |_| (); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs index dd6da62a47272..2dce218f5b83b 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs @@ -36,7 +36,7 @@ fn function2>() { // 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::(); - //[next]~^ ERROR type mismatch resolving `>::Assoc == usize` + //[next]~^ ERROR higher-ranked subtype error //[current]~^^ ERROR mismatched types } diff --git a/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs new file mode 100644 index 0000000000000..7c20246e5eb71 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs @@ -0,0 +1,43 @@ +//@ check-pass +//@ compile-flags: -Znext-solver=globally +//@ edition:2021 + +// Regression test for . +// +// This previously caused an ICE due to a non–well-formed coroutine +// hidden type 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() -> impl Future + Send { + let x: Pin + Send>> = todo!(); + x +} +fn main() { + async { + b::<&()>().await; + } + .aa(); +} + +impl Filter for F where F: Send {} + +trait Filter { + fn aa(self) + where + Self: Sized, + { + } +} diff --git a/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs new file mode 100644 index 0000000000000..004775b822976 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs @@ -0,0 +1,48 @@ +//@ check-pass +//@ compile-flags: -Znext-solver -Zvalidate-mir +//@ edition: 2021 + +// Regression test for . +// +// This previously caused an ICE due to a non–well-formed coroutine +// hidden type 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 + 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() {} diff --git a/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs new file mode 100644 index 0000000000000..7de6ec519eaa5 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs @@ -0,0 +1,34 @@ +//@ check-pass +//@ compile-flags: -Znext-solver +//@ edition:2021 + +// Regression test for . +// +// This previously caused an ICE due to a non–well-formed coroutine +// hidden type 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::Assoc); + +fn prove_send_and_hide(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; + }); +} diff --git a/tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs b/tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs new file mode 100644 index 0000000000000..e071510976a14 --- /dev/null +++ b/tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs @@ -0,0 +1,45 @@ +//@ run-pass + +// Regression test for . + +#![allow(warnings)] + +trait Trait { + type Assoc; +} +impl<'a, 'b: 'a> Trait for Inv<'a, 'b> { + type Assoc = (); +} + +trait ReqWf {} +impl 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 {} +impl Bound for F where F: FnOnce(T) -> R {} +trait ImpossiblePredicates { + fn call_me(&self) + where + F: for<'a, 'b> Bound<&'a &'b u32>, + { + println!("method body"); + } +} +impl ImpossiblePredicates for () {} +fn mk_trait_object(_: F) -> Box> { + 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(); +}