diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index de786c38326fa..3d4e5caa9b27c 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -110,7 +110,7 @@ macro_rules! arena_types { rustc_hir::def_id::DefId, rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>> >, - [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, + [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData>, [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 202d587f0ad21..b4e3fae1b43b0 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -32,54 +32,7 @@ use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; // FIXME: Remove this import and import via `solve::` -pub use rustc_type_ir::solve::BuiltinImplSource; - -/// Depending on the stage of compilation, we want projection to be -/// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] -pub enum Reveal { - /// At type-checking time, we refuse to project any associated - /// type that is marked `default`. Non-`default` ("final") types - /// are always projected. This is necessary in general for - /// soundness of specialization. However, we *could* allow - /// projections in fully-monomorphic cases. We choose not to, - /// because we prefer for `default type` to force the type - /// definition to be treated abstractly by any consumers of the - /// impl. Concretely, that means that the following example will - /// fail to compile: - /// - /// ```compile_fail,E0308 - /// #![feature(specialization)] - /// trait Assoc { - /// type Output; - /// } - /// - /// impl Assoc for T { - /// default type Output = bool; - /// } - /// - /// fn main() { - /// let x: <() as Assoc>::Output = true; - /// } - /// ``` - /// - /// We also do not reveal the hidden type of opaque types during - /// type-checking. - UserFacing, - - /// At codegen time, all monomorphic projections will succeed. - /// Also, `impl Trait` is normalized to the concrete type, - /// which has to be already collected by type-checking. - /// - /// NOTE: as `impl Trait`'s concrete type should *never* - /// be observable directly by the user, `Reveal::All` - /// should not be used by checks which may expose - /// type equality or type contents to the user. - /// There are some exceptions, e.g., around auto traits and - /// transmute-checking, which expose some details, but - /// not the whole concrete type of the `impl Trait`. - All, -} +pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal}; /// The reason why we incurred this obligation; used for error reporting. /// diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 0d9ce402c64e5..9e979620a440e 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,10 +1,9 @@ use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; -use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; +use rustc_macros::HashStable; use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; -use crate::infer::canonical::QueryRegionConstraints; use crate::ty::{ self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; @@ -38,37 +37,18 @@ impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] -pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); +pub struct ExternalConstraints<'tcx>( + pub(crate) Interned<'tcx, ExternalConstraintsData>>, +); impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { - type Target = ExternalConstraintsData<'tcx>; + type Target = ExternalConstraintsData>; fn deref(&self) -> &Self::Target { &self.0 } } -/// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] -pub struct ExternalConstraintsData<'tcx> { - // FIXME: implement this. - pub region_constraints: QueryRegionConstraints<'tcx>, - pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, - pub normalization_nested_goals: NestedNormalizationGoals<'tcx>, -} - -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] -pub struct NestedNormalizationGoals<'tcx>(pub Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>); -impl<'tcx> NestedNormalizationGoals<'tcx> { - pub fn empty() -> Self { - NestedNormalizationGoals(vec![]) - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - // FIXME: Having to clone `region_constraints` for folding feels bad and // probably isn't great wrt performance. // diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3651c990c9792..e2f15dac01987 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -88,6 +88,7 @@ use std::ops::{Bound, Deref}; #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; + type LocalDefId = LocalDefId; type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; @@ -382,7 +383,7 @@ pub struct CtxtInterners<'tcx> { bound_variable_kinds: InternedSet<'tcx, List>, layout: InternedSet<'tcx, LayoutS>, adt_def: InternedSet<'tcx, AdtDefData>, - external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>, + external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, @@ -2093,7 +2094,7 @@ direct_interners! { const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutS): Layout -> Layout<'tcx>, adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, - external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>): + external_constraints: pub mk_external_constraints(ExternalConstraintsData>): ExternalConstraints -> ExternalConstraints<'tcx>, predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>): PredefinedOpaques -> PredefinedOpaques<'tcx>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5a94a53e175ea..4e388de6fb8ad 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -94,6 +94,7 @@ pub use self::context::{ }; pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams}; pub use self::list::{List, ListWithCachedTypeInfo}; +pub use self::opaque_types::OpaqueTypeKey; pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ @@ -758,45 +759,6 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct OpaqueTypeKey<'tcx> { - pub def_id: LocalDefId, - pub args: GenericArgsRef<'tcx>, -} - -impl<'tcx> OpaqueTypeKey<'tcx> { - pub fn iter_captured_args( - self, - tcx: TyCtxt<'tcx>, - ) -> impl Iterator)> { - std::iter::zip(self.args, tcx.variances_of(self.def_id)).enumerate().filter_map( - |(i, (arg, v))| match (arg.unpack(), v) { - (_, ty::Invariant) => Some((i, arg)), - (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None, - _ => bug!("unexpected opaque type arg variance"), - }, - ) - } - - pub fn fold_captured_lifetime_args( - self, - tcx: TyCtxt<'tcx>, - mut f: impl FnMut(Region<'tcx>) -> Region<'tcx>, - ) -> Self { - let Self { def_id, args } = self; - let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| { - match (arg.unpack(), v) { - (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, - (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), - _ => arg, - } - }); - let args = tcx.mk_args_from_iter(args); - Self { def_id, args } - } -} - #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct OpaqueHiddenType<'tcx> { /// The span of this particular definition of the opaque type. So diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 52902aadd7c7b..08b2f9e892031 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -7,6 +7,8 @@ use rustc_span::def_id::DefId; use rustc_span::Span; use tracing::{debug, instrument, trace}; +pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey>; + /// Converts generic params of a TypeFoldable from one /// item's generics to another. Usually from a function's generics /// list to the opaque type's own generics. diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index b913a05095c2b..144caf36ee538 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -1,3 +1,9 @@ +//! Crate containing the implementation of the next-generation trait solver. +//! +//! This crate may also contain things that are used by the old trait solver, +//! but were uplifted in the process of making the new trait solver generic. +//! So if you got to this crate from the old solver, it's totally normal. + pub mod canonicalizer; pub mod resolve; pub mod solve; diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 0e0b9e983391c..b5753d60f5993 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -135,8 +135,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // Remove any trivial region constraints once we've resolved regions external_constraints .region_constraints - .outlives - .retain(|(outlives, _)| outlives.0.as_region().map_or(true, |re| re != outlives.1)); + .retain(|outlives| outlives.0.as_region().map_or(true, |re| re != outlives.1)); let canonical = Canonicalizer::canonicalize( self.infcx, @@ -179,8 +178,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn compute_external_query_constraints( &self, certainty: Certainty, - normalization_nested_goals: NestedNormalizationGoals<'tcx>, - ) -> ExternalConstraintsData<'tcx> { + normalization_nested_goals: NestedNormalizationGoals>, + ) -> ExternalConstraintsData> { // We only return region constraints once the certainty is `Yes`. This // is necessary as we may drop nested goals on ambiguity, which may result // in unconstrained inference variables in the region constraints. It also @@ -193,30 +192,40 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'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.infcx.inner.borrow().region_obligations().to_owned(); - let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { - make_query_region_constraints( - self.interner(), - region_obligations.iter().map(|r_o| { - (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) - }), - region_constraints, - ) - }); - + let QueryRegionConstraints { outlives, member_constraints } = + self.infcx.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.interner(), + region_obligations.iter().map(|r_o| { + (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) + }), + region_constraints, + ) + }); + assert_eq!(member_constraints, vec![]); let mut seen = FxHashSet::default(); - region_constraints.outlives.retain(|outlives| seen.insert(*outlives)); - region_constraints + outlives + .into_iter() + .filter(|(outlives, _)| seen.insert(*outlives)) + .map(|(outlives, _origin)| outlives) + .collect() } else { Default::default() }; - let mut opaque_types = self.infcx.clone_opaque_types_for_query_response(); - // Only return opaque type keys for newly-defined opaques - opaque_types.retain(|(a, _)| { - self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) - }); - - ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } + ExternalConstraintsData { + region_constraints, + opaque_types: self + .infcx + .clone_opaque_types_for_query_response() + .into_iter() + // Only return *newly defined* opaque types. + .filter(|(a, _)| { + self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) + }) + .collect(), + normalization_nested_goals, + } } /// After calling a canonical query, we apply the constraints returned @@ -232,7 +241,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { param_env: ty::ParamEnv<'tcx>, original_values: Vec>, response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals<'tcx>, Certainty) { + ) -> (NestedNormalizationGoals>, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( self.infcx, &original_values, @@ -369,16 +378,17 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { - for &(ty::OutlivesPredicate(lhs, rhs), _) in ®ion_constraints.outlives { + fn register_region_constraints( + &mut self, + outlives: &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>], + ) { + for &ty::OutlivesPredicate(lhs, rhs) in outlives { match lhs.unpack() { GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs), GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs), GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"), } } - - assert!(region_constraints.member_constraints.is_empty()); } fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 6b8375b53e8ff..74938d2bbd708 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -29,11 +29,9 @@ use super::inspect::ProofTreeBuilder; use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; use super::{search_graph::SearchGraph, Goal}; use super::{GoalSource, SolverMode}; -pub use select::InferCtxtSelectExt; pub(super) mod canonical; mod probe; -mod select; pub struct EvalCtxt<'a, Infcx, I = ::Interner> where @@ -339,7 +337,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { goal_evaluation_kind: GoalEvaluationKind, _source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(NestedNormalizationGoals<'tcx>, bool, Certainty), NoSolution> { + ) -> Result<(NestedNormalizationGoals>, bool, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -382,7 +380,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { param_env: ty::ParamEnv<'tcx>, original_values: Vec>, response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals<'tcx>, Certainty, bool) { + ) -> (NestedNormalizationGoals>, Certainty, bool) { if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty { return (NestedNormalizationGoals::empty(), response.value.certainty, false); } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index fdcf4ff11e468..4f1be5cbc8532 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -37,12 +37,14 @@ mod normalize; mod normalizes_to; mod project_goals; mod search_graph; +mod select; mod trait_goals; -pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; +pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt}; pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +pub use select::InferCtxtSelectExt; /// How many fixpoint iterations we should attempt inside of the solver before bailing /// with overflow. diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 60a15392e0bee..5c5923e9d3964 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -10,13 +10,13 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::inspect::ProbeKind; use rustc_infer::traits::solve::MaybeCause; use rustc_infer::traits::Reveal; +use rustc_middle::bug; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::NormalizesTo; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeVisitableExt, Upcast}; -use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; mod anon_const; @@ -200,14 +200,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| { let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason); - let error_term = match assoc_def.item.kind { - ty::AssocKind::Const => ty::Const::new_error(tcx, guar).into(), - ty::AssocKind::Type => Ty::new_error(tcx, guar).into(), - // This makes no sense... - ty::AssocKind::Fn => span_bug!( - tcx.def_span(assoc_def.item.def_id), - "cannot project to an associated function" - ), + let error_term = match goal.predicate.alias.kind(tcx) { + ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(), + ty::AliasTermKind::ProjectionConst => ty::Const::new_error(tcx, guar).into(), + kind => bug!("expected projection, found {kind:?}"), }; ecx.instantiate_normalizes_to_term(goal, error_term); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -238,9 +234,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } // Finally we construct the actual value of the associated type. - let term = match assoc_def.item.kind { - ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), - ty::AssocKind::Const => { + let term = match goal.predicate.alias.kind(tcx) { + ty::AliasTermKind::ProjectionTy => { + tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()) + } + ty::AliasTermKind::ProjectionConst => { if tcx.features().associated_const_equality { bug!("associated const projection is not supported yet") } else { @@ -254,7 +252,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ) } } - ty::AssocKind::Fn => unreachable!("we should never project to a fn"), + kind => bug!("expected projection, found {kind:?}"), }; ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args)); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs similarity index 100% rename from compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs rename to compiler/rustc_trait_selection/src/solve/select.rs diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index a2b71e1fc2575..11c1f73fef338 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -29,6 +29,7 @@ pub trait Interner: + IrPrint> { type DefId: Copy + Debug + Hash + Eq + TypeFoldable; + type LocalDefId: Copy + Debug + Hash + Eq + Into + TypeFoldable; type AdtDef: AdtDef; type GenericArgs: GenericArgs; @@ -103,7 +104,11 @@ pub trait Interner: type GenericsOf: GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; - type VariancesOf: Copy + Debug + Deref; + type VariancesOf: Copy + + Debug + + Deref + // FIXME: This is terrible! + + IntoIterator>; fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf; // FIXME: Remove after uplifting `EarlyBinder` diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 4775a0f8cbbe4..ac9b2808804c6 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -47,6 +47,7 @@ mod flags; mod generic_arg; mod infcx; mod interner; +mod opaque_ty; mod predicate; mod predicate_kind; mod region_kind; @@ -63,6 +64,7 @@ pub use flags::*; pub use generic_arg::*; pub use infcx::InferCtxtLike; pub use interner::*; +pub use opaque_ty::*; pub use predicate::*; pub use predicate_kind::*; pub use region_kind::*; diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs new file mode 100644 index 0000000000000..6073706659756 --- /dev/null +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -0,0 +1,51 @@ +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::inherent::*; +use crate::{self as ty, Interner}; + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Copy(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub struct OpaqueTypeKey { + pub def_id: I::LocalDefId, + pub args: I::GenericArgs, +} + +impl OpaqueTypeKey { + pub fn iter_captured_args(self, tcx: I) -> impl Iterator { + let variances = tcx.variances_of(self.def_id.into()); + std::iter::zip(self.args, variances.into_iter()).enumerate().filter_map(|(i, (arg, v))| { + match (arg.kind(), *v) { + (_, ty::Invariant) => Some((i, arg)), + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None, + _ => panic!("unexpected opaque type arg variance"), + } + }) + } + + pub fn fold_captured_lifetime_args( + self, + tcx: I, + mut f: impl FnMut(I::Region) -> I::Region, + ) -> Self { + let Self { def_id, args } = self; + let variances = tcx.variances_of(def_id.into()); + let args = + std::iter::zip(args, variances.into_iter()).map(|(arg, v)| match (arg.kind(), *v) { + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, + (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), + _ => arg, + }); + let args = tcx.mk_args_from_iter(args); + Self { def_id, args } + } +} diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 6a89a8a4cc306..99d2fa7449477 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -7,7 +7,55 @@ use std::hash::Hash; use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::{Canonical, CanonicalVarValues, Interner, Upcast}; +use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast}; + +/// Depending on the stage of compilation, we want projection to be +/// more or less conservative. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub enum Reveal { + /// At type-checking time, we refuse to project any associated + /// type that is marked `default`. Non-`default` ("final") types + /// are always projected. This is necessary in general for + /// soundness of specialization. However, we *could* allow + /// projections in fully-monomorphic cases. We choose not to, + /// because we prefer for `default type` to force the type + /// definition to be treated abstractly by any consumers of the + /// impl. Concretely, that means that the following example will + /// fail to compile: + /// + /// ```compile_fail,E0308 + /// #![feature(specialization)] + /// trait Assoc { + /// type Output; + /// } + /// + /// impl Assoc for T { + /// default type Output = bool; + /// } + /// + /// fn main() { + /// let x: <() as Assoc>::Output = true; + /// } + /// ``` + /// + /// We also do not reveal the hidden type of opaque types during + /// type-checking. + UserFacing, + + /// At codegen time, all monomorphic projections will succeed. + /// Also, `impl Trait` is normalized to the concrete type, + /// which has to be already collected by type-checking. + /// + /// NOTE: as `impl Trait`'s concrete type should *never* + /// be observable directly by the user, `Reveal::All` + /// should not be used by checks which may expose + /// type equality or type contents to the user. + /// There are some exceptions, e.g., around auto traits and + /// transmute-checking, which expose some details, but + /// not the whole concrete type of the `impl Trait`. + All, +} pub type CanonicalInput::Predicate> = Canonical>; pub type CanonicalResponse = Canonical>; @@ -206,6 +254,47 @@ pub struct Response { pub external_constraints: I::ExternalConstraints, } +/// Additional constraints returned on success. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Default(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub struct ExternalConstraintsData { + pub region_constraints: Vec>, + pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, + pub normalization_nested_goals: NestedNormalizationGoals, +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Default(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub struct NestedNormalizationGoals(pub Vec<(GoalSource, Goal)>); + +impl NestedNormalizationGoals { + pub fn empty() -> Self { + NestedNormalizationGoals(vec![]) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum Certainty {