diff options
Diffstat (limited to 'compiler/rustc_trait_selection')
24 files changed, 284 insertions, 79 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index bc464b099e2..b9acadc406e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -51,6 +51,7 @@ use std::path::PathBuf; use std::{cmp, fmt, iter}; use rustc_abi::ExternAbi; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize, @@ -73,7 +74,7 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -225,7 +226,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, - segments: Vec<String>, + segments: Vec<Symbol>, } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { @@ -253,7 +254,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { - self.segments = vec![self.tcx.crate_name(cnum).to_string()]; + self.segments = vec![self.tcx.crate_name(cnum)]; Ok(()) } fn path_qualified( @@ -279,7 +280,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result<(), PrintError> { print_prefix(self)?; - self.segments.push(disambiguated_data.to_string()); + self.segments.push(disambiguated_data.as_sym(true)); Ok(()) } fn path_generic_args( @@ -314,7 +315,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // known" by the same name, we use the "absolute path" which uses the original // crate name instead. let (expected, found) = if expected_str == found_str { - (expected_abs.join("::"), found_abs.join("::")) + (join_path_syms(&expected_abs), join_path_syms(&found_abs)) } else { (expected_str.clone(), found_str.clone()) }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 712e88300ff..98f67257fd1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -12,6 +12,7 @@ use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, }; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _}; +use rustc_session::parse::feature_err_unstable_feature_bound; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use tracing::{debug, instrument}; @@ -611,6 +612,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) .with_span_label(span, format!("cannot normalize `{alias}`")) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => { + if let Some(e) = self.tainted_by_errors() { + return e; + } + + let mut err; + + if self.tcx.features().staged_api() { + err = self.dcx().struct_span_err( + span, + format!("unstable feature `{sym}` is used without being enabled."), + ); + + err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")); + } else { + err = feature_err_unstable_feature_bound( + &self.tcx.sess, + sym, + span, + format!("use of unstable library feature `{sym}`"), + ); + } + err + } _ => { if let Some(e) = self.tainted_by_errors() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index cd3e6c4bc54..1ac309da101 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ty::PredicateKind::ConstEquate { .. } // Ambiguous predicates should never error | ty::PredicateKind::Ambiguous + // We never return Err when proving UnstableFeature goal. + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. }) | ty::PredicateKind::NormalizesTo { .. } | ty::PredicateKind::AliasRelate { .. } | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index d4cc1ceb280..1d8b934cef3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -453,7 +453,7 @@ pub fn report_dyn_incompatibility<'tcx>( let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node { hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(_, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { + hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { Some(ident.span) } _ => unreachable!(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index bd1d29826e6..bf7d4257b62 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -22,6 +22,7 @@ use rustc_hir::{ expr_needs_parens, is_range_literal, }; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_middle::middle::privacy::Level; use rustc_middle::traits::IsConstable; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::{ @@ -267,7 +268,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let node = self.tcx.hir_node_by_def_id(body_id); match node { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ident, generics, bounds, _), + kind: hir::ItemKind::Trait(_, _, _, ident, generics, bounds, _), .. }) if self_ty == self.tcx.types.self_param => { assert!(param_ty); @@ -330,7 +331,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } hir::Node::Item(hir::Item { kind: - hir::ItemKind::Trait(_, _, _, generics, ..) + hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }), .. }) if projection.is_some() => { @@ -354,7 +355,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) @@ -414,7 +415,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) @@ -2870,11 +2871,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::ClauseKind::Trait(trait_pred) => { let def_id = trait_pred.def_id(); let visible_item = if let Some(local) = def_id.as_local() { - // Check for local traits being reachable. - let vis = &tcx.resolutions(()).effective_visibilities; - // Account for non-`pub` traits in the root of the local crate. - let is_locally_reachable = tcx.parent(def_id).is_crate_root(); - vis.is_reachable(local) || is_locally_reachable + let ty = trait_pred.self_ty(); + // when `TraitA: TraitB` and `S` only impl TraitA, + // we check if `TraitB` can be reachable from `S` + // to determine whether to note `TraitA` is sealed trait. + if let ty::Adt(adt, _) = ty.kind() { + let visibilities = tcx.effective_visibilities(()); + visibilities.effective_vis(local).is_none_or(|v| { + v.at_level(Level::Reexported) + .is_accessible_from(adt.did(), tcx) + }) + } else { + // FIXME(xizheyin): if the type is not ADT, we should not suggest it + true + } } else { // Check for foreign traits being reachable. tcx.visible_parent_map(()).get(&def_id).is_some() @@ -3436,7 +3446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut is_auto_trait = false; match tcx.hir_get_if_local(data.impl_or_alias_def_id) { Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait(is_auto, _, ident, ..), + kind: hir::ItemKind::Trait(_, is_auto, _, ident, ..), .. })) => { // FIXME: we should do something else so that it works even on crate foreign diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 90cdf75265d..7901d52dffb 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -534,7 +534,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope)) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, _, generics, ..), + kind: hir::ItemKind::Trait(_, _, _, _, generics, ..), .. }) | hir::Node::Item(hir::Item { diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 0118321befb..7c6b7b14ecb 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -33,8 +33,8 @@ impl<'tcx> InferCtxt<'tcx> { let ty = self.resolve_vars_if_possible(ty); // FIXME(#132279): This should be removed as it causes us to incorrectly - // handle opaques in their defining scope. - if !self.next_trait_solver() && !(param_env, ty).has_infer() { + // handle opaques in their defining scope, and stalled coroutines. + if !self.next_trait_solver() && !(param_env, ty).has_infer() && !ty.has_coroutines() { return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty); } diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 068e90b00b8..2b33b8ac9f8 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -4,7 +4,7 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, elaborate}; use crate::traits::ScrubbedTraitError; use crate::traits::outlives_bounds::InferCtxtExt; @@ -46,6 +46,11 @@ impl<'tcx> OutlivesEnvironment<'tcx> { } } + // FIXME(-Znext-trait-solver): Normalize these. + let higher_ranked_assumptions = infcx.take_registered_region_assumptions(); + let higher_ranked_assumptions = + elaborate::elaborate_outlives_assumptions(infcx.tcx, higher_ranked_assumptions); + // FIXME: This needs to be modified so that we normalize the known type // outlives obligations then elaborate them into their region/type components. // Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even @@ -59,6 +64,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { assumed_wf_tys, disable_implied_bounds_hack, ), + higher_ranked_assumptions, ) } } diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index 5a5d16167d2..f58961683a9 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -7,7 +7,7 @@ mod normalize; mod select; pub(crate) use delegate::SolverDelegate; -pub use fulfill::{FulfillmentCtxt, NextSolverError}; +pub use fulfill::{FulfillmentCtxt, NextSolverError, StalledOnCoroutines}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 1a24254d57f..17429e15cce 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -206,14 +206,18 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect()) } - fn make_deduplicated_outlives_constraints( - &self, - ) -> Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> { + fn make_deduplicated_outlives_constraints(&self) -> Vec<ty::ArgOutlivesPredicate<'tcx>> { // 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(); + let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned(); let region_constraints = self.0.with_region_constraints(|region_constraints| { - make_query_region_constraints(self.tcx, region_obligations, region_constraints) + make_query_region_constraints( + self.tcx, + region_obligations, + region_constraints, + region_assumptions, + ) }); let mut seen = FxHashSet::default(); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index d56042a5ca2..3ce0f025512 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -10,7 +10,8 @@ use rustc_infer::traits::{ FromSolverError, PredicateObligation, PredicateObligations, TraitEngine, }; use rustc_middle::ty::{ - self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode, + self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + TypingMode, }; use rustc_next_trait_solver::delegate::SolverDelegate as _; use rustc_next_trait_solver::solve::{ @@ -254,7 +255,7 @@ where &mut self, infcx: &InferCtxt<'tcx>, ) -> PredicateObligations<'tcx> { - let stalled_generators = match infcx.typing_mode() { + let stalled_coroutines = match infcx.typing_mode() { TypingMode::Analysis { defining_opaque_types_and_generators } => { defining_opaque_types_and_generators } @@ -264,7 +265,7 @@ where | TypingMode::PostAnalysis => return Default::default(), }; - if stalled_generators.is_empty() { + if stalled_coroutines.is_empty() { return Default::default(); } @@ -275,7 +276,7 @@ where .visit_proof_tree( obl.as_goal(), &mut StalledOnCoroutines { - stalled_generators, + stalled_coroutines, span: obl.cause.span, cache: Default::default(), }, @@ -297,10 +298,10 @@ where /// /// This function can be also return false positives, which will lead to poor diagnostics /// so we want to keep this visitor *precise* too. -struct StalledOnCoroutines<'tcx> { - stalled_generators: &'tcx ty::List<LocalDefId>, - span: Span, - cache: DelayedSet<Ty<'tcx>>, +pub struct StalledOnCoroutines<'tcx> { + pub stalled_coroutines: &'tcx ty::List<LocalDefId>, + pub span: Span, + pub cache: DelayedSet<Ty<'tcx>>, } impl<'tcx> inspect::ProofTreeVisitor<'tcx> for StalledOnCoroutines<'tcx> { @@ -330,12 +331,14 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for StalledOnCoroutines<'tcx> { } if let ty::CoroutineWitness(def_id, _) = *ty.kind() - && def_id.as_local().is_some_and(|def_id| self.stalled_generators.contains(&def_id)) + && def_id.as_local().is_some_and(|def_id| self.stalled_coroutines.contains(&def_id)) { - return ControlFlow::Break(()); + ControlFlow::Break(()) + } else if ty.has_coroutines() { + ty.super_visit_with(self) + } else { + ControlFlow::Continue(()) } - - ty.super_visit_with(self) } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 3ae908ec16b..759db1d18c0 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -800,6 +800,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {} ty::PredicateKind::Ambiguous => return false, }; diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index ce5a4edeaaa..f50f01a285b 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -461,6 +461,7 @@ fn impl_intersection_has_negative_obligation( // requirements, when proving the negated where clauses below. drop(equate_obligations); drop(infcx.take_registered_region_obligations()); + drop(infcx.take_registered_region_assumptions()); drop(infcx.take_and_reset_region_constraints()); plug_infer_with_placeholders( diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 9a4f3887bbb..ea1eed95723 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -238,6 +238,7 @@ fn predicate_references_self<'tcx>( // FIXME(generic_const_exprs): this can mention `Self` | ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::HostEffect(..) + | ty::ClauseKind::UnstableFeature(_) => None, } } @@ -278,6 +279,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => false, }) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 64a51e0550b..e35f89358e9 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use rustc_data_structures::obligation_forest::{ Error, ForestObligation, ObligationForest, ObligationProcessor, Outcome, ProcessResult, }; +use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::{ FromSolverError, PolyTraitObligation, PredicateObligations, ProjectionCacheKey, SelectionError, @@ -11,7 +12,11 @@ use rustc_infer::traits::{ use rustc_middle::bug; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{ + self, Binder, Const, GenericArgsRef, TypeVisitable, TypeVisitableExt, TypingMode, + may_use_unstable_feature, +}; +use rustc_span::DUMMY_SP; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, debug_span, instrument}; @@ -24,6 +29,7 @@ use super::{ }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; +use crate::solve::StalledOnCoroutines; use crate::traits::normalize::normalize_with_depth_to; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -166,8 +172,25 @@ where &mut self, infcx: &InferCtxt<'tcx>, ) -> PredicateObligations<'tcx> { - let mut processor = - DrainProcessor { removed_predicates: PredicateObligations::new(), infcx }; + let stalled_coroutines = match infcx.typing_mode() { + TypingMode::Analysis { defining_opaque_types_and_generators } => { + defining_opaque_types_and_generators + } + TypingMode::Coherence + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } + | TypingMode::PostAnalysis => return Default::default(), + }; + + if stalled_coroutines.is_empty() { + return Default::default(); + } + + let mut processor = DrainProcessor { + infcx, + removed_predicates: PredicateObligations::new(), + stalled_coroutines, + }; let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor); assert!(outcome.errors.is_empty()); return processor.removed_predicates; @@ -175,6 +198,7 @@ where struct DrainProcessor<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, removed_predicates: PredicateObligations<'tcx>, + stalled_coroutines: &'tcx ty::List<LocalDefId>, } impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> { @@ -183,10 +207,14 @@ where type OUT = Outcome<Self::Obligation, Self::Error>; fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { - pending_obligation - .stalled_on - .iter() - .any(|&var| self.infcx.ty_or_const_infer_var_changed(var)) + self.infcx + .resolve_vars_if_possible(pending_obligation.obligation.predicate) + .visit_with(&mut StalledOnCoroutines { + stalled_coroutines: self.stalled_coroutines, + span: DUMMY_SP, + cache: Default::default(), + }) + .is_break() } fn process_obligation( @@ -404,6 +432,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used by the new solver") } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => { + unreachable!("unexpected higher ranked `UnstableFeature` goal") + } }, Some(pred) => match pred { ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { @@ -767,6 +798,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + if may_use_unstable_feature(self.selcx.infcx, obligation.param_env, symbol) { + ProcessResult::Changed(Default::default()) + } else { + ProcessResult::Unchanged + } + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 59d3ac21387..53518038f8d 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -78,7 +78,10 @@ fn implied_outlives_bounds<'a, 'tcx>( bounds.retain(|bound| !bound.has_placeholders()); if !constraints.is_empty() { - let QueryRegionConstraints { outlives } = constraints; + // FIXME(higher_ranked_auto): Should we register assumptions here? + // We otherwise would get spurious errors if normalizing an implied + // outlives bound required proving some higher-ranked coroutine obl. + let QueryRegionConstraints { outlives, assumptions: _ } = constraints; let cause = ObligationCause::misc(span, body_id); for &(predicate, _) in &outlives { infcx.register_outlives_constraint(predicate, &cause); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 3b549244431..f027ba1c5cb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -80,6 +80,11 @@ where pre_obligations.is_empty(), "scrape_region_constraints: incoming region obligations = {pre_obligations:#?}", ); + let pre_assumptions = infcx.take_registered_region_assumptions(); + assert!( + pre_assumptions.is_empty(), + "scrape_region_constraints: incoming region assumptions = {pre_assumptions:#?}", + ); let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(infcx); @@ -100,11 +105,13 @@ where let value = infcx.resolve_vars_if_possible(value); let region_obligations = infcx.take_registered_region_obligations(); + let region_assumptions = infcx.take_registered_region_assumptions(); let region_constraint_data = infcx.take_and_reset_region_constraints(); let region_constraints = query_response::make_query_region_constraints( infcx.tcx, region_obligations, ®ion_constraint_data, + region_assumptions, ); if region_constraints.is_empty() { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index e294f7839aa..7540cbe3fd1 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -110,6 +110,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::NormalizesTo(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::AliasRelate(..) => {} // We need to search through *all* WellFormed predicates diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 4bdf04311a0..018e9748cf0 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -180,8 +180,9 @@ where span, )?; output.error_info = error_info; - if let Some(QueryRegionConstraints { outlives }) = output.constraints { + if let Some(QueryRegionConstraints { outlives, assumptions }) = output.constraints { region_constraints.outlives.extend(outlives.iter().cloned()); + region_constraints.assumptions.extend(assumptions.iter().cloned()); } output.constraints = if region_constraints.is_empty() { None diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index cc188a280aa..2c7089507a8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -842,6 +842,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::CoroutineWitness(def_id, _) => { + if self.should_stall_coroutine_witness(def_id) { + candidates.ambiguous = true; + } else { + candidates.vec.push(AutoImplCandidate); + } + } + ty::Bool | ty::Char | ty::Int(_) @@ -861,7 +869,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Coroutine(..) | ty::Never | ty::Tuple(_) - | ty::CoroutineWitness(..) | ty::UnsafeBinder(_) => { // Only consider auto impls of unsafe traits when there are // no unsafe fields. @@ -1119,12 +1126,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match *self_ty.kind() { // These impls are built-in because we cannot express sufficiently // generic impls in libcore. - ty::FnDef(..) - | ty::FnPtr(..) - | ty::Error(_) - | ty::Tuple(..) - | ty::CoroutineWitness(..) - | ty::Pat(..) => { + ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) | ty::Tuple(..) | ty::Pat(..) => { candidates.vec.push(BuiltinCandidate); } @@ -1192,6 +1194,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::CoroutineWitness(coroutine_def_id, _) => { + if self.should_stall_coroutine_witness(coroutine_def_id) { + candidates.ambiguous = true; + } else { + candidates.vec.push(SizedCandidate); + } + } + // Fallback to whatever user-defined impls or param-env clauses exist in this case. ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {} @@ -1229,7 +1239,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Char | ty::Ref(..) | ty::Coroutine(..) - | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1238,6 +1247,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(SizedCandidate); } + ty::CoroutineWitness(coroutine_def_id, _) => { + if self.should_stall_coroutine_witness(coroutine_def_id) { + candidates.ambiguous = true; + } else { + candidates.vec.push(SizedCandidate); + } + } + // Conditionally `Sized`. ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => { candidates.vec.push(SizedCandidate); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index ee8cef20279..488094b15ac 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -411,18 +411,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty); - let types = self.constituent_types_for_ty(self_ty)?; - let types = self.infcx.enter_forall_and_leak_universe(types); + let constituents = self.constituent_types_for_auto_trait(self_ty)?; + let constituents = self.infcx.enter_forall_and_leak_universe(constituents); let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); - let obligations = self.collect_predicates_for_types( + let mut obligations = self.collect_predicates_for_types( obligation.param_env, - cause, + cause.clone(), obligation.recursion_depth + 1, obligation.predicate.def_id(), - types, + constituents.types, ); + // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types` + // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really + // matter yet. + for assumption in constituents.assumptions { + let assumption = normalize_with_depth_to( + self, + obligation.param_env, + cause.clone(), + obligation.recursion_depth + 1, + assumption, + &mut obligations, + ); + self.infcx.register_region_assumption(assumption); + } + Ok(obligations) }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2e65750db25..2b563c5b8d5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -20,6 +20,7 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::relate::TypeRelation; use rustc_infer::traits::{PredicateObligations, TraitObligation}; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds}; pub use rustc_middle::traits::select::*; @@ -28,7 +29,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt, - TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, + TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature, }; use rustc_span::{Symbol, sym}; use tracing::{debug, instrument, trace}; @@ -832,6 +833,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToAmbig) + } + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.infcx, @@ -1504,7 +1513,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { defining_opaque_types_and_generators: defining_opaque_types, } | TypingMode::Borrowck { defining_opaque_types } => { - defining_opaque_types.is_empty() || !pred.has_opaque_types() + defining_opaque_types.is_empty() + || (!pred.has_opaque_types() && !pred.has_coroutines()) } // The hidden types of `defined_opaque_types` is not local to the current // inference context, so we can freely move this to the global cache. @@ -2247,10 +2257,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> { /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` #[instrument(level = "debug", skip(self), ret)] - fn constituent_types_for_ty( + fn constituent_types_for_auto_trait( &self, t: Ty<'tcx>, - ) -> Result<ty::Binder<'tcx, Vec<Ty<'tcx>>>, SelectionError<'tcx>> { + ) -> Result<ty::Binder<'tcx, AutoImplConstituents<'tcx>>, SelectionError<'tcx>> { Ok(match *t.kind() { ty::Uint(_) | ty::Int(_) @@ -2261,17 +2271,26 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never - | ty::Char => ty::Binder::dummy(Vec::new()), + | ty::Char => { + ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] }) + } // This branch is only for `experimental_default_bounds`. // Other foreign types were rejected earlier in // `assemble_candidates_from_auto_impls`. - ty::Foreign(..) => ty::Binder::dummy(Vec::new()), + ty::Foreign(..) => { + ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] }) + } - ty::UnsafeBinder(ty) => ty.map_bound(|ty| vec![ty]), + ty::UnsafeBinder(ty) => { + ty.map_bound(|ty| AutoImplConstituents { types: vec![ty], assumptions: vec![] }) + } // Treat this like `struct str([u8]);` - ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]), + ty::Str => ty::Binder::dummy(AutoImplConstituents { + types: vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)], + assumptions: vec![], + }), ty::Placeholder(..) | ty::Dynamic(..) @@ -2283,30 +2302,41 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => { - ty::Binder::dummy(vec![element_ty]) + ty::Binder::dummy(AutoImplConstituents { + types: vec![element_ty], + assumptions: vec![], + }) } - ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => ty::Binder::dummy(vec![ty]), + ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => { + ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) + } ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - ty::Binder::dummy(tys.iter().collect()) + ty::Binder::dummy(AutoImplConstituents { + types: tys.iter().collect(), + assumptions: vec![], + }) } ty::Closure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); - ty::Binder::dummy(vec![ty]) + ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) } ty::CoroutineClosure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()); - ty::Binder::dummy(vec![ty]) + ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) } ty::Coroutine(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let witness = args.as_coroutine().witness(); - ty::Binder::dummy([ty].into_iter().chain(iter::once(witness)).collect()) + ty::Binder::dummy(AutoImplConstituents { + types: [ty].into_iter().chain(iter::once(witness)).collect(), + assumptions: vec![], + }) } ty::CoroutineWitness(def_id, args) => self @@ -2314,16 +2344,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> { .tcx .coroutine_hidden_types(def_id) .instantiate(self.infcx.tcx, args) - .map_bound(|witness| witness.types.to_vec()), + .map_bound(|witness| AutoImplConstituents { + types: witness.types.to_vec(), + assumptions: witness.assumptions.to_vec(), + }), // For `PhantomData<T>`, we pass `T`. ty::Adt(def, args) if def.is_phantom_data() => { - ty::Binder::dummy(args.types().collect()) + ty::Binder::dummy(AutoImplConstituents { + types: args.types().collect(), + assumptions: vec![], + }) } - ty::Adt(def, args) => { - ty::Binder::dummy(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect()) - } + ty::Adt(def, args) => ty::Binder::dummy(AutoImplConstituents { + types: def.all_fields().map(|f| f.ty(self.tcx(), args)).collect(), + assumptions: vec![], + }), ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { if self.infcx.can_define_opaque_ty(def_id) { @@ -2333,7 +2370,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // which enforces a DAG between the functions requiring // the auto trait bounds in question. match self.tcx().type_of_opaque(def_id) { - Ok(ty) => ty::Binder::dummy(vec![ty.instantiate(self.tcx(), args)]), + Ok(ty) => ty::Binder::dummy(AutoImplConstituents { + types: vec![ty.instantiate(self.tcx(), args)], + assumptions: vec![], + }), Err(_) => { return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); } @@ -2803,6 +2843,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligations } + + fn should_stall_coroutine_witness(&self, def_id: DefId) -> bool { + match self.infcx.typing_mode() { + TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => { + def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id)) + } + TypingMode::Coherence + | TypingMode::PostAnalysis + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => false, + } + } } impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { @@ -3113,3 +3165,9 @@ pub(crate) enum ProjectionMatchesProjection { Ambiguous, No, } + +#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] +pub(crate) struct AutoImplConstituents<'tcx> { + pub types: Vec<Ty<'tcx>>, + pub assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>, +} diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 141454bfe37..0c14b124e25 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -80,6 +80,7 @@ pub fn expand_trait_aliases<'tcx>( | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => {} } } @@ -378,6 +379,13 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc _ => return false, }; + // FIXME(sized_hierarchy): this temporarily reverts the `sized_hierarchy` feature + // while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs` + // is pending a proper fix + if !tcx.features().sized_hierarchy() && matches!(sizedness, SizedTraitKind::MetaSized) { + return true; + } + if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) { debug!("fast path -- trivial sizedness"); return true; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fed9f254cdf..adce9850b59 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -197,6 +197,7 @@ pub fn clause_obligations<'tcx>( ty::ClauseKind::ConstEvaluatable(ct) => { wf.add_wf_preds_for_term(ct.into()); } + ty::ClauseKind::UnstableFeature(_) => {} } wf.normalize(infcx) @@ -1095,6 +1096,7 @@ pub fn object_region_bounds<'tcx>( | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::ConstEvaluatable(_) => None, } }) |
