Skip to content

new solver proof tree generation #112351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ pub enum CodegenObligationError {
FulfillmentError,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum DefiningAnchor {
/// `DefId` of the item.
Bind(LocalDefId),
Expand All @@ -991,3 +991,9 @@ pub enum DefiningAnchor {
/// Used to catch type mismatch errors when handling opaque types.
Error,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum IsNormalizesToHack {
Yes,
No,
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/traits/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;

#[derive(Copy, Clone, Debug, HashStable, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, Hash, HashStable, PartialEq, Eq)]
pub struct NoSolution;

impl<'tcx> From<TypeError<'tcx>> for NoSolution {
Expand Down
20 changes: 11 additions & 9 deletions compiler/rustc_middle/src/traits/solve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ use crate::ty::{
TypeVisitor,
};

pub mod inspect;

pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>;

/// A goal is a statement, i.e. `predicate`, we want to prove
/// given some assumptions, i.e. `param_env`.
///
/// Most of the time the `param_env` contains the `where`-bounds of the function
/// we're currently typechecking while the `predicate` is some trait bound.
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct Goal<'tcx, P> {
pub predicate: P,
pub param_env: ty::ParamEnv<'tcx>,
Expand All @@ -39,15 +41,15 @@ impl<'tcx, P> Goal<'tcx, P> {
}
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct Response<'tcx> {
pub certainty: Certainty,
pub var_values: CanonicalVarValues<'tcx>,
/// Additional constraints returned by this query.
pub external_constraints: ExternalConstraints<'tcx>,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum Certainty {
Yes,
Maybe(MaybeCause),
Expand Down Expand Up @@ -86,7 +88,7 @@ impl Certainty {
}

/// Why we failed to evaluate a goal.
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum MaybeCause {
/// We failed due to ambiguity. This ambiguity can either
/// be a true ambiguity, i.e. there are multiple different answers,
Expand All @@ -96,20 +98,20 @@ pub enum MaybeCause {
Overflow,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct QueryInput<'tcx, T> {
pub goal: Goal<'tcx, T>,
pub anchor: DefiningAnchor,
pub predefined_opaques_in_body: PredefinedOpaques<'tcx>,
}

/// Additional constraints returned on success.
#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)]
pub struct PredefinedOpaquesData<'tcx> {
pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)]
pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>);

impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> {
Expand All @@ -132,7 +134,7 @@ pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
/// solver, merge the two responses again.
pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>;

#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)]
pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>);

impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> {
Expand All @@ -144,7 +146,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> {
}

/// Additional constraints returned on success.
#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)]
pub struct ExternalConstraintsData<'tcx> {
// FIXME: implement this.
pub region_constraints: QueryRegionConstraints<'tcx>,
Expand Down
79 changes: 79 additions & 0 deletions compiler/rustc_middle/src/traits/solve/inspect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use super::{CanonicalInput, Certainty, Goal, NoSolution, QueryInput, QueryResult};
use crate::{traits::IsNormalizesToHack, ty};
use format::ProofTreeFormatter;
use std::fmt::{Debug, Write};

mod format;

#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
pub enum CacheHit {
Provisional,
Global,
}

#[derive(Eq, PartialEq, Hash, HashStable)]
pub struct GoalEvaluation<'tcx> {
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
pub canonicalized_goal: CanonicalInput<'tcx>,

pub kind: GoalEvaluationKind<'tcx>,
pub is_normalizes_to_hack: IsNormalizesToHack,
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,

pub result: QueryResult<'tcx>,
}
#[derive(Eq, PartialEq, Hash, HashStable)]
pub enum GoalEvaluationKind<'tcx> {
CacheHit(CacheHit),
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
}
impl Debug for GoalEvaluation<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ProofTreeFormatter { f, on_newline: true }.format_goal_evaluation(self)
}
}

#[derive(Eq, PartialEq, Hash, HashStable)]
pub struct AddedGoalsEvaluation<'tcx> {
pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>,
pub result: Result<Certainty, NoSolution>,
}
impl Debug for AddedGoalsEvaluation<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ProofTreeFormatter { f, on_newline: true }.format_nested_goal_evaluation(self)
}
}

#[derive(Eq, PartialEq, Hash, HashStable)]
pub struct GoalEvaluationStep<'tcx> {
pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,

pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
pub candidates: Vec<GoalCandidate<'tcx>>,

pub result: QueryResult<'tcx>,
}
impl Debug for GoalEvaluationStep<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ProofTreeFormatter { f, on_newline: true }.format_evaluation_step(self)
}
}

#[derive(Eq, PartialEq, Hash, HashStable)]
pub struct GoalCandidate<'tcx> {
pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
pub candidates: Vec<GoalCandidate<'tcx>>,
pub kind: CandidateKind<'tcx>,
}
#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
pub enum CandidateKind<'tcx> {
/// Probe entered when normalizing the self ty during candidate assembly
NormalizedSelfTyAssembly,
/// A normal candidate for proving a goal
Candidate { name: String, result: QueryResult<'tcx> },
}
impl Debug for GoalCandidate<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ProofTreeFormatter { f, on_newline: true }.format_candidate(self)
}
}
131 changes: 131 additions & 0 deletions compiler/rustc_middle/src/traits/solve/inspect/format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use super::*;

pub(super) struct ProofTreeFormatter<'a, 'b> {
pub(super) f: &'a mut (dyn Write + 'b),
pub(super) on_newline: bool,
}

impl Write for ProofTreeFormatter<'_, '_> {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
for line in s.split_inclusive("\n") {
if self.on_newline {
self.f.write_str(" ")?;
}
self.on_newline = line.ends_with("\n");
self.f.write_str(line)?;
}

Ok(())
}
}

impl ProofTreeFormatter<'_, '_> {
fn nested(&mut self) -> ProofTreeFormatter<'_, '_> {
ProofTreeFormatter { f: self, on_newline: true }
}

pub(super) fn format_goal_evaluation(&mut self, goal: &GoalEvaluation<'_>) -> std::fmt::Result {
let f = &mut *self.f;

let goal_text = match goal.is_normalizes_to_hack {
IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
IsNormalizesToHack::No => "GOAL",
};

writeln!(f, "{}: {:?}", goal_text, goal.uncanonicalized_goal,)?;
writeln!(f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?;

match &goal.kind {
GoalEvaluationKind::CacheHit(CacheHit::Global) => {
writeln!(f, "GLOBAL CACHE HIT: {:?}", goal.result)
}
GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
writeln!(f, "PROVISIONAL CACHE HIT: {:?}", goal.result)
}
GoalEvaluationKind::Uncached { revisions } => {
for (n, step) in revisions.iter().enumerate() {
let f = &mut *self.f;
writeln!(f, "REVISION {n}: {:?}", step.result)?;
let mut f = self.nested();
f.format_evaluation_step(step)?;
}

let f = &mut *self.f;
writeln!(f, "RESULT: {:?}", goal.result)
}
}?;

if goal.returned_goals.len() > 0 {
let f = &mut *self.f;
writeln!(f, "NESTED GOALS ADDED TO CALLER: [")?;
let mut f = self.nested();
for goal in goal.returned_goals.iter() {
writeln!(f, "ADDED GOAL: {:?},", goal)?;
}
writeln!(self.f, "]")?;
}

Ok(())
}

pub(super) fn format_evaluation_step(
&mut self,
evaluation_step: &GoalEvaluationStep<'_>,
) -> std::fmt::Result {
let f = &mut *self.f;
writeln!(f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;

for candidate in &evaluation_step.candidates {
let mut f = self.nested();
f.format_candidate(candidate)?;
}
for nested_goal_evaluation in &evaluation_step.nested_goal_evaluations {
let mut f = self.nested();
f.format_nested_goal_evaluation(nested_goal_evaluation)?;
}

Ok(())
}

pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result {
let f = &mut *self.f;

match &candidate.kind {
CandidateKind::NormalizedSelfTyAssembly => {
writeln!(f, "NORMALIZING SELF TY FOR ASSEMBLY:")
}
CandidateKind::Candidate { name, result } => {
writeln!(f, "CANDIDATE {}: {:?}", name, result)
}
}?;

let mut f = self.nested();
for candidate in &candidate.candidates {
f.format_candidate(candidate)?;
}
for nested_evaluations in &candidate.nested_goal_evaluations {
f.format_nested_goal_evaluation(nested_evaluations)?;
}

Ok(())
}

pub(super) fn format_nested_goal_evaluation(
&mut self,
nested_goal_evaluation: &AddedGoalsEvaluation<'_>,
) -> std::fmt::Result {
let f = &mut *self.f;
writeln!(f, "TRY_EVALUATE_ADDED_GOALS: {:?}", nested_goal_evaluation.result)?;

for (n, revision) in nested_goal_evaluation.evaluations.iter().enumerate() {
let f = &mut *self.f;
writeln!(f, "REVISION {n}")?;
let mut f = self.nested();
for goal_evaluation in revision {
f.format_goal_evaluation(goal_evaluation)?;
}
}

Ok(())
}
}
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1436,6 +1436,8 @@ options! {
"output statistics about monomorphization collection"),
dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
"the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
dump_solver_proof_tree: bool = (false, parse_bool, [UNTRACKED],
"dump a proof tree for every goal evaluated by the new trait solver"),
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
Expand Down
Loading