Skip to content

Commit

Permalink
Unrolled build for rust-lang#122687
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#122687 - lcnr:normalizes-to-emit-nested-goals, r=compiler-errors

`NormalizesTo`: return nested goals to caller

Fixes the regression of `paperclip-core`. see https://hackmd.io/IsVAafiOTAaPIFcUxRJufw for more details.

r? ```@compiler-errors```
  • Loading branch information
rust-timer authored Mar 18, 2024
2 parents d31b6fb + 0b29b71 commit d291299
Show file tree
Hide file tree
Showing 29 changed files with 267 additions and 198 deletions.
29 changes: 21 additions & 8 deletions compiler/rustc_middle/src/traits/solve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,19 @@ 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
Expand All @@ -183,21 +196,27 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
.iter()
.map(|opaque| opaque.try_fold_with(folder))
.collect::<Result<_, F::Error>>()?,
normalization_nested_goals: self
.normalization_nested_goals
.clone()
.try_fold_with(folder)?,
}))
}

fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData {
region_constraints: self.region_constraints.clone().fold_with(folder),
opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
normalization_nested_goals: self.normalization_nested_goals.clone().fold_with(folder),
})
}
}

impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
try_visit!(self.region_constraints.visit_with(visitor));
self.opaque_types.visit_with(visitor)
try_visit!(self.opaque_types.visit_with(visitor));
self.normalization_nested_goals.visit_with(visitor)
}
}

Expand Down Expand Up @@ -239,7 +258,7 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
///
/// This is necessary as we treat nested goals different depending on
/// their source.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TypeVisitable, TypeFoldable)]
pub enum GoalSource {
Misc,
/// We're proving a where-bound of an impl.
Expand All @@ -256,12 +275,6 @@ pub enum GoalSource {
ImplWhereBound,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum IsNormalizesToHack {
Yes,
No,
}

/// Possible ways the given goal can be proven.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CandidateSource {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/traits/solve/inspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
//! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
use super::{
CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack,
NoSolution, QueryInput, QueryResult,
CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, NoSolution,
QueryInput, QueryResult,
};
use crate::{infer::canonical::CanonicalVarValues, ty};
use format::ProofTreeFormatter;
Expand Down Expand Up @@ -50,7 +50,7 @@ pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>;
#[derive(Eq, PartialEq)]
pub enum GoalEvaluationKind<'tcx> {
Root { orig_values: Vec<ty::GenericArg<'tcx>> },
Nested { is_normalizes_to_hack: IsNormalizesToHack },
Nested,
}

#[derive(Eq, PartialEq)]
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_middle/src/traits/solve/inspect/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
let goal_text = match eval.kind {
GoalEvaluationKind::Root { orig_values: _ } => "ROOT GOAL",
GoalEvaluationKind::Nested { is_normalizes_to_hack } => match is_normalizes_to_hack {
IsNormalizesToHack::No => "GOAL",
IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
},
GoalEvaluationKind::Nested => "GOAL",
};
write!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?;
self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))
Expand Down
33 changes: 21 additions & 12 deletions compiler/rustc_trait_selection/src/solve/alias_relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
//! However, if `?fresh_var` ends up geteting equated to another type, we retry the
//! `NormalizesTo` goal, at which point the opaque is actually defined.
use super::{EvalCtxt, GoalSource};
use super::EvalCtxt;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::GoalSource;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty::{self, Ty};

Expand Down Expand Up @@ -121,10 +122,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
ty::TermKind::Const(_) => {
if let Some(alias) = term.to_alias_ty(self.tcx()) {
let term = self.next_term_infer_of_kind(term);
self.add_goal(
GoalSource::Misc,
Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias, term }),
);
self.add_normalizes_to_goal(Goal::new(
self.tcx(),
param_env,
ty::NormalizesTo { alias, term },
));
self.try_evaluate_added_goals()?;
Ok(Some(self.resolve_vars_if_possible(term)))
} else {
Expand All @@ -145,18 +147,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
return None;
}

let ty::Alias(_, alias) = *ty.kind() else {
let ty::Alias(kind, alias) = *ty.kind() else {
return Some(ty);
};

match self.commit_if_ok(|this| {
let tcx = this.tcx();
let normalized_ty = this.next_ty_infer();
let normalizes_to_goal = Goal::new(
this.tcx(),
param_env,
ty::NormalizesTo { alias, term: normalized_ty.into() },
);
this.add_goal(GoalSource::Misc, normalizes_to_goal);
let normalizes_to = ty::NormalizesTo { alias, term: normalized_ty.into() };
match kind {
ty::AliasKind::Opaque => {
// HACK: Unlike for associated types, `normalizes-to` for opaques
// is currently not treated as a function. We do not erase the
// expected term.
this.add_goal(GoalSource::Misc, Goal::new(tcx, param_env, normalizes_to));
}
ty::AliasKind::Projection | ty::AliasKind::Inherent | ty::AliasKind::Weak => {
this.add_normalizes_to_goal(Goal::new(tcx, param_env, normalizes_to))
}
}
this.try_evaluate_added_goals()?;
Ok(this.resolve_vars_if_possible(normalized_ty))
}) {
Expand Down
50 changes: 38 additions & 12 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//!
//! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
use super::{CanonicalInput, Certainty, EvalCtxt, Goal};
use crate::solve::eval_ctxt::NestedGoals;
use crate::solve::{
inspect, response_no_constraints_raw, CanonicalResponse, QueryResult, Response,
};
Expand All @@ -19,6 +20,7 @@ use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
use rustc_infer::infer::resolve::EagerResolver;
use rustc_infer::infer::{InferCtxt, InferOk};
use rustc_infer::traits::solve::NestedNormalizationGoals;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{
Expand All @@ -28,6 +30,7 @@ use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer};
use rustc_span::DUMMY_SP;
use std::assert_matches::assert_matches;
use std::iter;
use std::ops::Deref;

Expand Down Expand Up @@ -93,13 +96,31 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
previous call to `try_evaluate_added_goals!`"
);

let certainty = certainty.unify_with(goals_certainty);

let var_values = self.var_values;
let external_constraints = self.compute_external_query_constraints()?;

// When normalizing, we've replaced the expected term with an unconstrained
// inference variable. This means that we dropped information which could
// have been important. We handle this by instead returning the nested goals
// to the caller, where they are then handled.
//
// As we return all ambiguous nested goals, we can ignore the certainty returned
// by `try_evaluate_added_goals()`.
let (certainty, normalization_nested_goals) = if self.is_normalizes_to_goal {
let NestedGoals { normalizes_to_goals, goals } = std::mem::take(&mut self.nested_goals);
if cfg!(debug_assertions) {
assert!(normalizes_to_goals.is_empty());
if goals.is_empty() {
assert_matches!(goals_certainty, Certainty::Yes);
}
}
(certainty, NestedNormalizationGoals(goals))
} else {
let certainty = certainty.unify_with(goals_certainty);
(certainty, NestedNormalizationGoals::empty())
};

let external_constraints =
self.compute_external_query_constraints(normalization_nested_goals)?;
let (var_values, mut external_constraints) =
(var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx));
(self.var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx));
// Remove any trivial region constraints once we've resolved regions
external_constraints
.region_constraints
Expand Down Expand Up @@ -146,6 +167,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)]
fn compute_external_query_constraints(
&self,
normalization_nested_goals: NestedNormalizationGoals<'tcx>,
) -> Result<ExternalConstraintsData<'tcx>, NoSolution> {
// We only check for leaks from universes which were entered inside
// of the query.
Expand Down Expand Up @@ -176,7 +198,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
});

Ok(ExternalConstraintsData { region_constraints, opaque_types })
Ok(ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals })
}

/// After calling a canonical query, we apply the constraints returned
Expand All @@ -185,13 +207,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
/// This happens in three steps:
/// - we instantiate the bound variables of the query response
/// - we unify the `var_values` of the response with the `original_values`
/// - we apply the `external_constraints` returned by the query
/// - we apply the `external_constraints` returned by the query, returning
/// the `normalization_nested_goals`
pub(super) fn instantiate_and_apply_query_response(
&mut self,
param_env: ty::ParamEnv<'tcx>,
original_values: Vec<ty::GenericArg<'tcx>>,
response: CanonicalResponse<'tcx>,
) -> Certainty {
) -> (NestedNormalizationGoals<'tcx>, Certainty) {
let instantiation = Self::compute_query_response_instantiation_values(
self.infcx,
&original_values,
Expand All @@ -203,11 +226,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {

Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values);

let ExternalConstraintsData { region_constraints, opaque_types } =
external_constraints.deref();
let ExternalConstraintsData {
region_constraints,
opaque_types,
normalization_nested_goals,
} = external_constraints.deref();
self.register_region_constraints(region_constraints);
self.register_new_opaque_types(param_env, opaque_types);
certainty
(normalization_nested_goals.clone(), certainty)
}

/// This returns the canoncial variable values to instantiate the bound variables of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
infcx: self.infcx,
variables: self.variables,
var_values: self.var_values,
is_normalizes_to_goal: self.is_normalizes_to_goal,
predefined_opaques_in_body: self.predefined_opaques_in_body,
max_input_universe: self.max_input_universe,
search_graph: self.search_graph,
Expand All @@ -25,6 +26,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
infcx: _,
variables: _,
var_values: _,
is_normalizes_to_goal: _,
predefined_opaques_in_body: _,
max_input_universe: _,
search_graph: _,
Expand Down
Loading

0 comments on commit d291299

Please sign in to comment.