From e951bcff96ac606aad3b7870c7fa64a4a48aa04b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Feb 2024 18:31:35 +0000 Subject: [PATCH] Normalize the whole PolyTypeOutlivesPredicate, more simplifications --- .../src/type_check/constraint_conversion.rs | 84 +++++++++---------- .../src/type_check/free_region_relations.rs | 17 ++-- .../src/infer/error_reporting/mod.rs | 7 +- .../src/infer/lexical_region_resolve/mod.rs | 2 +- .../rustc_infer/src/infer/outlives/mod.rs | 13 +-- .../src/infer/outlives/obligations.rs | 38 +++++---- compiler/rustc_trait_selection/src/regions.rs | 6 +- .../src/traits/auto_trait.rs | 2 +- .../next-solver/specialization-transmute.rs | 2 +- .../specialization-transmute.stderr | 2 +- 10 files changed, 92 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 4c224248945..c97e3170166 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -5,13 +5,11 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; +use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::GenericArgKind; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::solve::deeply_normalize; -use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -146,7 +144,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { let ConstraintConversion { tcx, infcx, - param_env, region_bound_pairs, implicit_region_bound, known_type_outlives_obligations, @@ -178,43 +175,10 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // Normalize the type we receive from a `TypeOutlives` obligation // in the new trait solver. if infcx.next_trait_solver() { - let result = CustomTypeOp::new( - |ocx| { - match deeply_normalize( - ocx.infcx.at( - &ObligationCause::dummy_with_span(self.span), - param_env, - ), - t1, - ) { - Ok(normalized_ty) => { - t1 = normalized_ty; - } - Err(e) => { - infcx.err_ctxt().report_fulfillment_errors(e); - } - } - - Ok(()) - }, - "normalize type outlives obligation", - ) - .fully_perform(infcx, self.span); - - match result { - Ok(TypeOpOutput { output: (), constraints, .. }) => { - if let Some(constraints) = constraints { - assert!( - constraints.member_constraints.is_empty(), - "no member constraints expected from normalizing: {:#?}", - constraints.member_constraints - ); - next_outlives_predicates - .extend(constraints.outlives.iter().copied()); - } - } - Err(_) => {} - } + t1 = self.normalize_and_add_type_outlives_constraints( + t1, + &mut next_outlives_predicates, + ); } // we don't actually use this for anything, but @@ -306,6 +270,42 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { debug!("add_type_test(type_test={:?})", type_test); self.constraints.type_tests.push(type_test); } + + fn normalize_and_add_type_outlives_constraints( + &self, + ty: Ty<'tcx>, + next_outlives_predicates: &mut Vec<( + ty::OutlivesPredicate, ty::Region<'tcx>>, + ConstraintCategory<'tcx>, + )>, + ) -> Ty<'tcx> { + let result = CustomTypeOp::new( + |ocx| { + deeply_normalize( + ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env), + ty, + ) + .map_err(|_| NoSolution) + }, + "normalize type outlives obligation", + ) + .fully_perform(self.infcx, self.span); + + match result { + Ok(TypeOpOutput { output: ty, constraints, .. }) => { + if let Some(constraints) = constraints { + assert!( + constraints.member_constraints.is_empty(), + "no member constraints expected from normalizing: {:#?}", + constraints.member_constraints + ); + next_outlives_predicates.extend(constraints.outlives.iter().copied()); + } + ty + } + Err(_) => ty, + } + } } impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> { diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 4d53a53ee19..2e0caf44819 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -11,7 +11,7 @@ use rustc_middle::traits::query::OutlivesBound; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; -use rustc_trait_selection::solve::deeply_normalize_with_skipped_universes; +use rustc_trait_selection::solve::deeply_normalize; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; @@ -226,18 +226,16 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let mut constraints = vec![]; let mut known_type_outlives_obligations = vec![]; for bound in param_env.caller_bounds() { - let Some(outlives) = bound.as_type_outlives_clause() else { continue }; - let ty::OutlivesPredicate(mut ty, region) = outlives.skip_binder(); + let Some(mut outlives) = bound.as_type_outlives_clause() else { continue }; // In the new solver, normalize the type-outlives obligation assumptions. if self.infcx.next_trait_solver() { - match deeply_normalize_with_skipped_universes( + match deeply_normalize( self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env), - ty, - vec![None; ty.outer_exclusive_binder().as_usize()], + outlives, ) { - Ok(normalized_ty) => { - ty = normalized_ty; + Ok(normalized_outlives) => { + outlives = normalized_outlives; } Err(e) => { self.infcx.err_ctxt().report_fulfillment_errors(e); @@ -245,8 +243,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } } - known_type_outlives_obligations - .push(outlives.rebind(ty::OutlivesPredicate(ty, region))); + known_type_outlives_obligations.push(outlives); } let known_type_outlives_obligations = self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b8344310d5d..f74e13db447 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -71,6 +71,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -519,10 +520,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } - RegionResolutionError::CannotNormalize(ty, origin) => { + RegionResolutionError::CannotNormalize(clause, origin) => { + let clause: ty::Clause<'tcx> = + clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx); self.tcx .dcx() - .struct_span_err(origin.span(), format!("cannot normalize `{ty}`")) + .struct_span_err(origin.span(), format!("cannot normalize `{clause}`")) .emit(); } } 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 4a1169e68e0..6137506d4a9 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -99,7 +99,7 @@ pub enum RegionResolutionError<'tcx> { Region<'tcx>, // the placeholder `'b` ), - CannotNormalize(Ty<'tcx>, SubregionOrigin<'tcx>), + CannotNormalize(ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>), } impl<'tcx> RegionResolutionError<'tcx> { diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 926e198b219..a4f9316b502 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -4,8 +4,8 @@ use super::region_constraints::RegionConstraintData; use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; -use rustc_middle::traits::query::OutlivesBound; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::traits::query::{NoSolution, OutlivesBound}; +use rustc_middle::ty; pub mod components; pub mod env; @@ -49,12 +49,15 @@ impl<'tcx> InferCtxt<'tcx> { pub fn resolve_regions_with_normalize( &self, outlives_env: &OutlivesEnvironment<'tcx>, - deeply_normalize_ty: impl Fn(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result, Ty<'tcx>>, + deeply_normalize_ty: impl Fn( + ty::PolyTypeOutlivesPredicate<'tcx>, + SubregionOrigin<'tcx>, + ) -> Result, NoSolution>, ) -> Vec> { match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) { Ok(()) => {} - Err((ty, origin)) => { - return vec![RegionResolutionError::CannotNormalize(ty, origin)]; + Err((clause, origin)) => { + return vec![RegionResolutionError::CannotNormalize(clause, origin)]; } }; diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index c36d8556d17..7208f17fb34 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -68,8 +68,9 @@ use crate::infer::{ use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::GenericArgKind; +use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate}; use rustc_span::DUMMY_SP; use smallvec::smallvec; @@ -125,11 +126,15 @@ impl<'tcx> InferCtxt<'tcx> { /// invoked after all type-inference variables have been bound -- /// right before lexical region resolution. #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))] - pub fn process_registered_region_obligations( + pub fn process_registered_region_obligations( &self, outlives_env: &OutlivesEnvironment<'tcx>, - mut deeply_normalize_ty: impl FnMut(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result, E>, - ) -> Result<(), (E, SubregionOrigin<'tcx>)> { + mut deeply_normalize_ty: impl FnMut( + PolyTypeOutlivesPredicate<'tcx>, + SubregionOrigin<'tcx>, + ) + -> Result, NoSolution>, + ) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> { assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot"); let normalized_caller_bounds: Vec<_> = outlives_env @@ -137,21 +142,19 @@ impl<'tcx> InferCtxt<'tcx> { .caller_bounds() .iter() .filter_map(|clause| { - let bound_clause = clause.kind(); - let ty::ClauseKind::TypeOutlives(outlives) = bound_clause.skip_binder() else { - return None; - }; + let outlives = clause.as_type_outlives_clause()?; Some( deeply_normalize_ty( - outlives.0, + outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP), ) - .map(|ty| bound_clause.rebind(ty::OutlivesPredicate(ty, outlives.1))), + // FIXME(-Znext-solver): How do we accurately report an error span here :( + .map_err(|NoSolution| { + (outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)) + }), ) }) - // FIXME(-Znext-solver): How do we accurately report an error here :( - .try_collect() - .map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?; + .try_collect()?; // Must loop since the process of normalizing may itself register region obligations. for iteration in 0.. { @@ -167,8 +170,13 @@ impl<'tcx> InferCtxt<'tcx> { } for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { - let sup_type = deeply_normalize_ty(sup_type, origin.clone()) - .map_err(|e| (e, origin.clone()))?; + let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region)); + let ty::OutlivesPredicate(sup_type, sub_region) = + deeply_normalize_ty(outlives, origin.clone()) + .map_err(|NoSolution| (outlives, origin.clone()))? + .no_bound_vars() + .expect("started with no bound vars, should end with no bound vars"); + debug!(?sup_type, ?sub_region, ?origin); let outlives = &mut TypeOutlives::new( diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index e5a7b27446b..756db7cc206 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -1,5 +1,6 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, RegionResolutionError}; +use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; pub trait InferCtxtRegionExt<'tcx> { @@ -24,15 +25,14 @@ impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> { let ty = self.resolve_vars_if_possible(ty); if self.next_trait_solver() { - crate::solve::deeply_normalize_with_skipped_universes( + crate::solve::deeply_normalize( self.at( &ObligationCause::dummy_with_span(origin.span()), outlives_env.param_env, ), ty, - vec![None; ty.outer_exclusive_binder().as_usize()], ) - .map_err(|_| ty) + .map_err(|_| NoSolution) } else { Ok(ty) } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 7933654a915..81c72fc4b7b 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -179,7 +179,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } let outlives_env = OutlivesEnvironment::new(full_env); - let _ = infcx.process_registered_region_obligations::(&outlives_env, |ty, _| Ok(ty)); + let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty)); let region_data = infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone(); diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs index e7de564877d..a0855dd1e17 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.rs +++ b/tests/ui/traits/next-solver/specialization-transmute.rs @@ -1,5 +1,5 @@ // compile-flags: -Znext-solver -//~^ ERROR cannot normalize `::Id` +//~^ ERROR cannot normalize `::Id: '_` #![feature(specialization)] //~^ WARN the feature `specialization` is incomplete diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index a1cf5b761e3..3100a92e3eb 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -8,7 +8,7 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -error: cannot normalize `::Id` +error: cannot normalize `::Id: '_` error[E0282]: type annotations needed --> $DIR/specialization-transmute.rs:14:23