Skip to content

Commit

Permalink
Auto merge of rust-lang#126492 - compiler-errors:more-uplifting, r=lcnr
Browse files Browse the repository at this point in the history
More preparation for new trait solver uplifting

Getting closer to being able to uplift the whole solver 🙏

Each commit should be self-justifying.

r? lcnr
  • Loading branch information
bors committed Jun 17, 2024
2 parents fd7eefc + ff154c7 commit e23ae72
Show file tree
Hide file tree
Showing 16 changed files with 222 additions and 163 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<rustc_middle::ty::TyCtxt<'tcx>>,
[] 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,
Expand Down
49 changes: 1 addition & 48 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> 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.
///
Expand Down
30 changes: 5 additions & 25 deletions compiler/rustc_middle/src/traits/solve.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down Expand Up @@ -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<TyCtxt<'tcx>>>,
);

impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> {
type Target = ExternalConstraintsData<'tcx>;
type Target = ExternalConstraintsData<TyCtxt<'tcx>>;

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.
//
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down Expand Up @@ -382,7 +383,7 @@ pub struct CtxtInterners<'tcx> {
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
adt_def: InternedSet<'tcx, AdtDefData>,
external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>,
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
fields: InternedSet<'tcx, List<FieldIdx>>,
local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
Expand Down Expand Up @@ -2093,7 +2094,7 @@ direct_interners! {
const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): 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<TyCtxt<'tcx>>):
ExternalConstraints -> ExternalConstraints<'tcx>,
predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>):
PredefinedOpaques -> PredefinedOpaques<'tcx>,
Expand Down
40 changes: 1 addition & 39 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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<Item = (usize, GenericArg<'tcx>)> {
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
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/ty/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TyCtxt<'tcx>>;

/// 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.
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_next_trait_solver/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
66 changes: 38 additions & 28 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<TyCtxt<'tcx>>,
) -> ExternalConstraintsData<TyCtxt<'tcx>> {
// 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
Expand All @@ -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
Expand All @@ -232,7 +241,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
param_env: ty::ParamEnv<'tcx>,
original_values: Vec<ty::GenericArg<'tcx>>,
response: CanonicalResponse<'tcx>,
) -> (NestedNormalizationGoals<'tcx>, Certainty) {
) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty) {
let instantiation = Self::compute_query_response_instantiation_values(
self.infcx,
&original_values,
Expand Down Expand Up @@ -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 &region_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>)]) {
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <Infcx as InferCtxtLike>::Interner>
where
Expand Down Expand Up @@ -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<TyCtxt<'tcx>>, 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);
Expand Down Expand Up @@ -382,7 +380,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
param_env: ty::ParamEnv<'tcx>,
original_values: Vec<ty::GenericArg<'tcx>>,
response: CanonicalResponse<'tcx>,
) -> (NestedNormalizationGoals<'tcx>, Certainty, bool) {
) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty, bool) {
if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty {
return (NestedNormalizationGoals::empty(), response.value.certainty, false);
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_trait_selection/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit e23ae72

Please sign in to comment.