Auto merge of #113673 - matthiaskrgr:rollup-zcume6k, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #113536 (avoid building proof trees in select) - #113558 (Only use max_line_length = 100 for *.rs) - #113570 (refactor proof tree formatting) - #113623 (Add jump to doc) - #113629 (Add Adt to SMIR) - #113631 (make MCP510 behavior opt-in to avoid conflicts between the CLI and target flavors) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
7bd81ee190
@ -11,6 +11,8 @@ trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.rs]
|
||||
max_line_length = 100
|
||||
|
||||
[*.md]
|
||||
|
@ -2970,10 +2970,25 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
|
||||
return;
|
||||
}
|
||||
|
||||
let self_contained_linker = sess.opts.cg.link_self_contained.linker();
|
||||
|
||||
// FIXME: some targets default to using `lld`, but users can only override the linker on the CLI
|
||||
// and cannot yet select the precise linker flavor to opt out of that. See for example issue
|
||||
// #113597 for the `thumbv6m-none-eabi` target: a driver is used, and its default linker
|
||||
// conflicts with the target's flavor, causing unexpected arguments being passed.
|
||||
//
|
||||
// Until the new `LinkerFlavor`-like CLI options are stabilized, we only adopt MCP510's behavior
|
||||
// if its dedicated unstable CLI flags are used, to keep the current sub-optimal stable
|
||||
// behavior.
|
||||
let using_mcp510 =
|
||||
self_contained_linker || sess.opts.cg.linker_flavor.is_some_and(|f| f.is_unstable());
|
||||
if !using_mcp510 && !unstable_use_lld {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Implement the "self-contained" part of this feature by adding rustc distribution
|
||||
// directories to the tool's search path.
|
||||
let self_contained_linker = sess.opts.cg.link_self_contained.linker() || unstable_use_lld;
|
||||
if self_contained_linker {
|
||||
if self_contained_linker || unstable_use_lld {
|
||||
for path in sess.get_tools_search_paths(false) {
|
||||
cmd.arg({
|
||||
let mut arg = OsString::from("-B");
|
||||
|
@ -32,7 +32,7 @@ pub enum GoalEvaluationKind<'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)
|
||||
ProofTreeFormatter::new(f).format_goal_evaluation(self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ pub struct AddedGoalsEvaluation<'tcx> {
|
||||
}
|
||||
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)
|
||||
ProofTreeFormatter::new(f).format_nested_goal_evaluation(self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ pub struct GoalEvaluationStep<'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)
|
||||
ProofTreeFormatter::new(f).format_evaluation_step(self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,6 +78,6 @@ pub enum CandidateKind<'tcx> {
|
||||
}
|
||||
impl Debug for GoalCandidate<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
ProofTreeFormatter { f, on_newline: true }.format_candidate(self)
|
||||
ProofTreeFormatter::new(f).format_candidate(self)
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,19 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) struct ProofTreeFormatter<'a, 'b> {
|
||||
pub(super) f: &'a mut (dyn Write + 'b),
|
||||
pub(super) on_newline: bool,
|
||||
f: &'a mut (dyn Write + 'b),
|
||||
}
|
||||
|
||||
impl Write for ProofTreeFormatter<'_, '_> {
|
||||
/// A formatter which adds 4 spaces of indentation to its input before
|
||||
/// passing it on to its nested formatter.
|
||||
///
|
||||
/// We can use this for arbitrary levels of indentation by nesting it.
|
||||
struct Indentor<'a, 'b> {
|
||||
f: &'a mut (dyn Write + 'b),
|
||||
on_newline: bool,
|
||||
}
|
||||
|
||||
impl Write for Indentor<'_, '_> {
|
||||
fn write_str(&mut self, s: &str) -> std::fmt::Result {
|
||||
for line in s.split_inclusive("\n") {
|
||||
if self.on_newline {
|
||||
@ -19,49 +27,52 @@ impl Write for ProofTreeFormatter<'_, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl ProofTreeFormatter<'_, '_> {
|
||||
fn nested(&mut self) -> ProofTreeFormatter<'_, '_> {
|
||||
ProofTreeFormatter { f: self, on_newline: true }
|
||||
impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
||||
pub(super) fn new(f: &'a mut (dyn Write + 'b)) -> Self {
|
||||
ProofTreeFormatter { f }
|
||||
}
|
||||
|
||||
fn nested<F, R>(&mut self, func: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut ProofTreeFormatter<'_, '_>) -> R,
|
||||
{
|
||||
func(&mut ProofTreeFormatter { f: &mut Indentor { f: self.f, 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)?;
|
||||
writeln!(self.f, "{}: {:?}", goal_text, goal.uncanonicalized_goal)?;
|
||||
writeln!(self.f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?;
|
||||
|
||||
match &goal.kind {
|
||||
GoalEvaluationKind::CacheHit(CacheHit::Global) => {
|
||||
writeln!(f, "GLOBAL CACHE HIT: {:?}", goal.result)
|
||||
writeln!(self.f, "GLOBAL CACHE HIT: {:?}", goal.result)
|
||||
}
|
||||
GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
|
||||
writeln!(f, "PROVISIONAL CACHE HIT: {:?}", goal.result)
|
||||
writeln!(self.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)?;
|
||||
writeln!(self.f, "REVISION {n}: {:?}", step.result)?;
|
||||
self.nested(|this| this.format_evaluation_step(step))?;
|
||||
}
|
||||
|
||||
let f = &mut *self.f;
|
||||
writeln!(f, "RESULT: {:?}", goal.result)
|
||||
writeln!(self.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, "NESTED GOALS ADDED TO CALLER: [")?;
|
||||
self.nested(|this| {
|
||||
for goal in goal.returned_goals.iter() {
|
||||
writeln!(this.f, "ADDED GOAL: {:?},", goal)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
writeln!(self.f, "]")?;
|
||||
}
|
||||
|
||||
@ -72,58 +83,53 @@ impl ProofTreeFormatter<'_, '_> {
|
||||
&mut self,
|
||||
evaluation_step: &GoalEvaluationStep<'_>,
|
||||
) -> std::fmt::Result {
|
||||
let f = &mut *self.f;
|
||||
writeln!(f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
|
||||
writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
|
||||
|
||||
for candidate in &evaluation_step.candidates {
|
||||
let mut f = self.nested();
|
||||
f.format_candidate(candidate)?;
|
||||
self.nested(|this| this.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)?;
|
||||
for nested in &evaluation_step.nested_goal_evaluations {
|
||||
self.nested(|this| this.format_nested_goal_evaluation(nested))?;
|
||||
}
|
||||
|
||||
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:")
|
||||
writeln!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:")
|
||||
}
|
||||
CandidateKind::Candidate { name, result } => {
|
||||
writeln!(f, "CANDIDATE {}: {:?}", name, result)
|
||||
writeln!(self.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(())
|
||||
self.nested(|this| {
|
||||
for candidate in &candidate.candidates {
|
||||
this.format_candidate(candidate)?;
|
||||
}
|
||||
for nested in &candidate.nested_goal_evaluations {
|
||||
this.format_nested_goal_evaluation(nested)?;
|
||||
}
|
||||
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)?;
|
||||
writeln!(self.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)?;
|
||||
}
|
||||
writeln!(self.f, "REVISION {n}")?;
|
||||
self.nested(|this| {
|
||||
for goal_evaluation in revision {
|
||||
this.format_goal_evaluation(goal_evaluation)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -27,21 +27,33 @@ pub fn crate_item(did: DefId) -> stable_mir::CrateItem {
|
||||
with_tables(|t| t.crate_item(did))
|
||||
}
|
||||
|
||||
pub fn adt_def(did: DefId) -> stable_mir::ty::AdtDef {
|
||||
with_tables(|t| t.adt_def(did))
|
||||
}
|
||||
|
||||
impl<'tcx> Tables<'tcx> {
|
||||
pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId {
|
||||
self.def_ids[item.0]
|
||||
}
|
||||
|
||||
pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem {
|
||||
stable_mir::CrateItem(self.create_def_id(did))
|
||||
}
|
||||
|
||||
pub fn adt_def(&mut self, did: DefId) -> stable_mir::ty::AdtDef {
|
||||
stable_mir::ty::AdtDef(self.create_def_id(did))
|
||||
}
|
||||
|
||||
fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId {
|
||||
// FIXME: this becomes inefficient when we have too many ids
|
||||
for (i, &d) in self.def_ids.iter().enumerate() {
|
||||
if d == did {
|
||||
return stable_mir::CrateItem(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
let id = self.def_ids.len();
|
||||
self.def_ids.push(did);
|
||||
stable_mir::CrateItem(id)
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
|
||||
|
||||
use crate::rustc_internal::{self, opaque};
|
||||
use crate::stable_mir::ty::{FloatTy, IntTy, RigidTy, TyKind, UintTy};
|
||||
use crate::stable_mir::ty::{AdtSubsts, FloatTy, GenericArgKind, IntTy, RigidTy, TyKind, UintTy};
|
||||
use crate::stable_mir::{self, Context};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
@ -94,7 +94,25 @@ impl<'tcx> Tables<'tcx> {
|
||||
ty::FloatTy::F32 => TyKind::RigidTy(RigidTy::Float(FloatTy::F32)),
|
||||
ty::FloatTy::F64 => TyKind::RigidTy(RigidTy::Float(FloatTy::F64)),
|
||||
},
|
||||
ty::Adt(_, _) => todo!(),
|
||||
ty::Adt(adt_def, substs) => TyKind::RigidTy(RigidTy::Adt(
|
||||
rustc_internal::adt_def(adt_def.did()),
|
||||
AdtSubsts(
|
||||
substs
|
||||
.iter()
|
||||
.map(|arg| match arg.unpack() {
|
||||
ty::GenericArgKind::Lifetime(region) => {
|
||||
GenericArgKind::Lifetime(opaque(®ion))
|
||||
}
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
GenericArgKind::Type(self.intern_ty(ty))
|
||||
}
|
||||
ty::GenericArgKind::Const(const_) => {
|
||||
GenericArgKind::Const(opaque(&const_))
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
)),
|
||||
ty::Foreign(_) => todo!(),
|
||||
ty::Str => todo!(),
|
||||
ty::Array(_, _) => todo!(),
|
||||
@ -149,13 +167,6 @@ pub(crate) trait Stable {
|
||||
fn stable(&self) -> Self::T;
|
||||
}
|
||||
|
||||
impl Stable for DefId {
|
||||
type T = stable_mir::CrateItem;
|
||||
fn stable(&self) -> Self::T {
|
||||
rustc_internal::crate_item(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable for mir::Statement<'tcx> {
|
||||
type T = stable_mir::mir::Statement;
|
||||
fn stable(&self) -> Self::T {
|
||||
@ -190,7 +201,9 @@ impl<'tcx> Stable for mir::Rvalue<'tcx> {
|
||||
Ref(region, kind, place) => {
|
||||
stable_mir::mir::Rvalue::Ref(opaque(region), kind.stable(), place.stable())
|
||||
}
|
||||
ThreadLocalRef(def_id) => stable_mir::mir::Rvalue::ThreadLocalRef(def_id.stable()),
|
||||
ThreadLocalRef(def_id) => {
|
||||
stable_mir::mir::Rvalue::ThreadLocalRef(rustc_internal::crate_item(*def_id))
|
||||
}
|
||||
AddressOf(mutability, place) => {
|
||||
stable_mir::mir::Rvalue::AddressOf(mutability.stable(), place.stable())
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::with;
|
||||
use super::{with, DefId};
|
||||
use crate::rustc_internal::Opaque;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Ty(pub usize);
|
||||
@ -9,6 +10,9 @@ impl Ty {
|
||||
}
|
||||
}
|
||||
|
||||
type Const = Opaque;
|
||||
type Region = Opaque;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TyKind {
|
||||
RigidTy(RigidTy),
|
||||
@ -21,6 +25,7 @@ pub enum RigidTy {
|
||||
Int(IntTy),
|
||||
Uint(UintTy),
|
||||
Float(FloatTy),
|
||||
Adt(AdtDef, AdtSubsts),
|
||||
Tuple(Vec<Ty>),
|
||||
}
|
||||
|
||||
@ -49,3 +54,18 @@ pub enum FloatTy {
|
||||
F32,
|
||||
F64,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct AdtDef(pub(crate) DefId);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AdtSubsts(pub Vec<GenericArgKind>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum GenericArgKind {
|
||||
// FIXME add proper region
|
||||
Lifetime(Region),
|
||||
Type(Ty),
|
||||
// FIXME add proper const
|
||||
Const(Const),
|
||||
}
|
||||
|
@ -116,7 +116,8 @@ impl NestedGoals<'_> {
|
||||
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
|
||||
pub enum GenerateProofTree {
|
||||
Yes(UseGlobalCache),
|
||||
No,
|
||||
IfEnabled,
|
||||
Never,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
|
||||
@ -202,7 +203,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||
(&tree, infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree)
|
||||
{
|
||||
let mut lock = std::io::stdout().lock();
|
||||
let _ = lock.write_fmt(format_args!("{tree:?}"));
|
||||
let _ = lock.write_fmt(format_args!("{tree:?}\n"));
|
||||
let _ = lock.flush();
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
|
||||
self.instantiate_binder_with_placeholders(obligation.predicate),
|
||||
);
|
||||
|
||||
let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::No, |ecx| {
|
||||
let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| {
|
||||
let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate);
|
||||
let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal);
|
||||
let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal);
|
||||
|
@ -57,7 +57,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
||||
.map(|obligation| {
|
||||
let code = infcx.probe(|_| {
|
||||
match infcx
|
||||
.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::No)
|
||||
.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::IfEnabled)
|
||||
.0
|
||||
{
|
||||
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => {
|
||||
@ -96,7 +96,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
||||
for obligation in mem::take(&mut self.obligations) {
|
||||
let goal = obligation.clone().into();
|
||||
let (changed, certainty, nested_goals) =
|
||||
match infcx.evaluate_root_goal(goal, GenerateProofTree::No).0 {
|
||||
match infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0 {
|
||||
Ok(result) => result,
|
||||
Err(NoSolution) => {
|
||||
errors.push(FulfillmentError {
|
||||
|
@ -200,30 +200,23 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> ProofTreeBuilder<'tcx> {
|
||||
let generate_proof_tree = match (
|
||||
tcx.sess.opts.unstable_opts.dump_solver_proof_tree,
|
||||
tcx.sess.opts.unstable_opts.dump_solver_proof_tree_use_cache,
|
||||
generate_proof_tree,
|
||||
) {
|
||||
(_, Some(use_cache), GenerateProofTree::Yes(_)) => {
|
||||
GenerateProofTree::Yes(UseGlobalCache::from_bool(use_cache))
|
||||
}
|
||||
|
||||
(DumpSolverProofTree::Always, use_cache, GenerateProofTree::No) => {
|
||||
let use_cache = use_cache.unwrap_or(true);
|
||||
GenerateProofTree::Yes(UseGlobalCache::from_bool(use_cache))
|
||||
}
|
||||
|
||||
(_, None, GenerateProofTree::Yes(_)) => generate_proof_tree,
|
||||
(DumpSolverProofTree::Never, _, _) => generate_proof_tree,
|
||||
(DumpSolverProofTree::OnError, _, _) => generate_proof_tree,
|
||||
};
|
||||
|
||||
match generate_proof_tree {
|
||||
GenerateProofTree::No => ProofTreeBuilder::new_noop(),
|
||||
GenerateProofTree::Yes(global_cache_disabled) => {
|
||||
ProofTreeBuilder::new_root(global_cache_disabled)
|
||||
GenerateProofTree::Never => ProofTreeBuilder::new_noop(),
|
||||
GenerateProofTree::IfEnabled => {
|
||||
let opts = &tcx.sess.opts.unstable_opts;
|
||||
match opts.dump_solver_proof_tree {
|
||||
DumpSolverProofTree::Always => {
|
||||
let use_cache = opts.dump_solver_proof_tree_use_cache.unwrap_or(true);
|
||||
ProofTreeBuilder::new_root(UseGlobalCache::from_bool(use_cache))
|
||||
}
|
||||
// `OnError` is handled by reevaluating goals in error
|
||||
// reporting with `GenerateProofTree::Yes`.
|
||||
DumpSolverProofTree::OnError | DumpSolverProofTree::Never => {
|
||||
ProofTreeBuilder::new_noop()
|
||||
}
|
||||
}
|
||||
}
|
||||
GenerateProofTree::Yes(use_cache) => ProofTreeBuilder::new_root(use_cache),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3569,7 +3569,7 @@ pub fn dump_proof_tree<'tcx>(o: &Obligation<'tcx, ty::Predicate<'tcx>>, infcx: &
|
||||
.1
|
||||
.expect("proof tree should have been generated");
|
||||
let mut lock = std::io::stdout().lock();
|
||||
let _ = lock.write_fmt(format_args!("{tree:?}"));
|
||||
let _ = lock.write_fmt(format_args!("{tree:?}\n"));
|
||||
let _ = lock.flush();
|
||||
});
|
||||
}
|
||||
|
@ -986,6 +986,11 @@ fn string_without_closing_tag<T: Display>(
|
||||
)
|
||||
.ok()
|
||||
.map(|(url, _, _)| url),
|
||||
LinkFromSrc::Doc(def_id) => {
|
||||
format::href_with_root_path(*def_id, context, Some(&href_context.root_path))
|
||||
.ok()
|
||||
.map(|(doc_link, _, _)| doc_link)
|
||||
}
|
||||
}
|
||||
})
|
||||
{
|
||||
|
@ -349,7 +349,12 @@ impl<'tcx> Context<'tcx> {
|
||||
let e = ExternalCrate { crate_num: cnum };
|
||||
(e.name(self.tcx()), e.src_root(self.tcx()))
|
||||
}
|
||||
ExternalLocation::Unknown => return None,
|
||||
ExternalLocation::Unknown => {
|
||||
let e = ExternalCrate { crate_num: cnum };
|
||||
let name = e.name(self.tcx());
|
||||
root = name.to_string();
|
||||
(name, e.src_root(self.tcx()))
|
||||
}
|
||||
};
|
||||
|
||||
let href = RefCell::new(PathBuf::new());
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::clean::{self, PrimitiveType};
|
||||
use crate::clean::{self, rustc_span, PrimitiveType};
|
||||
use crate::html::sources;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{ExprKind, HirId, Mod, Node};
|
||||
use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
@ -25,6 +25,7 @@ pub(crate) enum LinkFromSrc {
|
||||
Local(clean::Span),
|
||||
External(DefId),
|
||||
Primitive(PrimitiveType),
|
||||
Doc(DefId),
|
||||
}
|
||||
|
||||
/// This function will do at most two things:
|
||||
@ -65,24 +66,43 @@ struct SpanMapVisitor<'tcx> {
|
||||
impl<'tcx> SpanMapVisitor<'tcx> {
|
||||
/// This function is where we handle `hir::Path` elements and add them into the "span map".
|
||||
fn handle_path(&mut self, path: &rustc_hir::Path<'_>) {
|
||||
let info = match path.res {
|
||||
match path.res {
|
||||
// FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
|
||||
// Would be nice to support them too alongside the other `DefKind`
|
||||
// (such as primitive types!).
|
||||
Res::Def(kind, def_id) if kind != DefKind::TyParam => Some(def_id),
|
||||
Res::Local(_) => None,
|
||||
Res::Def(kind, def_id) if kind != DefKind::TyParam => {
|
||||
let link = if def_id.as_local().is_some() {
|
||||
LinkFromSrc::Local(rustc_span(def_id, self.tcx))
|
||||
} else {
|
||||
LinkFromSrc::External(def_id)
|
||||
};
|
||||
self.matches.insert(path.span, link);
|
||||
}
|
||||
Res::Local(_) => {
|
||||
if let Some(span) = self.tcx.hir().res_span(path.res) {
|
||||
self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
|
||||
}
|
||||
}
|
||||
Res::PrimTy(p) => {
|
||||
// FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
|
||||
self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
|
||||
return;
|
||||
}
|
||||
Res::Err => return,
|
||||
_ => return,
|
||||
};
|
||||
if let Some(span) = self.tcx.hir().res_span(path.res) {
|
||||
self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
|
||||
} else if let Some(def_id) = info {
|
||||
self.matches.insert(path.span, LinkFromSrc::External(def_id));
|
||||
Res::Err => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to generate links on items' definition to go to their documentation page.
|
||||
pub(crate) fn extract_info_from_hir_id(&mut self, hir_id: HirId) {
|
||||
if let Some(Node::Item(item)) = self.tcx.hir().find(hir_id) {
|
||||
if let Some(span) = self.tcx.def_ident_span(item.owner_id) {
|
||||
let cspan = clean::Span::new(span);
|
||||
// If the span isn't from the current crate, we ignore it.
|
||||
if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE {
|
||||
return;
|
||||
}
|
||||
self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,10 +137,13 @@ impl<'tcx> SpanMapVisitor<'tcx> {
|
||||
_ => return true,
|
||||
};
|
||||
let link_from_src = match data.macro_def_id {
|
||||
Some(macro_def_id) if macro_def_id.is_local() => {
|
||||
LinkFromSrc::Local(clean::Span::new(data.def_site))
|
||||
Some(macro_def_id) => {
|
||||
if macro_def_id.is_local() {
|
||||
LinkFromSrc::Local(clean::Span::new(data.def_site))
|
||||
} else {
|
||||
LinkFromSrc::External(macro_def_id)
|
||||
}
|
||||
}
|
||||
Some(macro_def_id) => LinkFromSrc::External(macro_def_id),
|
||||
None => return true,
|
||||
};
|
||||
let new_span = data.call_site;
|
||||
@ -160,6 +183,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
|
||||
LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// If it's a "mod foo {}", we want to look to its documentation page.
|
||||
self.extract_info_from_hir_id(id);
|
||||
}
|
||||
intravisit::walk_mod(self, m, id);
|
||||
}
|
||||
@ -176,13 +202,12 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
|
||||
.tcx
|
||||
.typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"));
|
||||
if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
|
||||
self.matches.insert(
|
||||
segment.ident.span,
|
||||
match hir.span_if_local(def_id) {
|
||||
Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
|
||||
None => LinkFromSrc::External(def_id),
|
||||
},
|
||||
);
|
||||
let link = if def_id.as_local().is_some() {
|
||||
LinkFromSrc::Local(rustc_span(def_id, self.tcx))
|
||||
} else {
|
||||
LinkFromSrc::External(def_id)
|
||||
};
|
||||
self.matches.insert(segment.ident.span, link);
|
||||
}
|
||||
} else if self.handle_macro(expr.span) {
|
||||
// We don't want to go deeper into the macro.
|
||||
@ -190,4 +215,28 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
|
||||
}
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
|
||||
match item.kind {
|
||||
ItemKind::Static(_, _, _)
|
||||
| ItemKind::Const(_, _)
|
||||
| ItemKind::Fn(_, _, _)
|
||||
| ItemKind::Macro(_, _)
|
||||
| ItemKind::TyAlias(_, _)
|
||||
| ItemKind::Enum(_, _)
|
||||
| ItemKind::Struct(_, _)
|
||||
| ItemKind::Union(_, _)
|
||||
| ItemKind::Trait(_, _, _, _, _)
|
||||
| ItemKind::TraitAlias(_, _) => self.extract_info_from_hir_id(item.hir_id()),
|
||||
ItemKind::Impl(_)
|
||||
| ItemKind::Use(_, _)
|
||||
| ItemKind::ExternCrate(_)
|
||||
| ItemKind::ForeignMod { .. }
|
||||
| ItemKind::GlobalAsm(_)
|
||||
| ItemKind::OpaqueTy(_)
|
||||
// We already have "visit_mod" above so no need to check it here.
|
||||
| ItemKind::Mod(_) => {}
|
||||
}
|
||||
intravisit::walk_item(self, item);
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,11 @@ set-window-size: (600, 800)
|
||||
// We check that the scroll is at the top first.
|
||||
assert-property: ("html", {"scrollTop": "0"})
|
||||
|
||||
click: '//a[text() = "barbar"]'
|
||||
click: '//a[text() = "barbar" and @href="#5-7"]'
|
||||
assert-property: ("html", {"scrollTop": "149"})
|
||||
click: '//a[text() = "bar"]'
|
||||
click: '//a[text() = "bar" and @href="#28-36"]'
|
||||
assert-property: ("html", {"scrollTop": "180"})
|
||||
click: '//a[text() = "sub_fn"]'
|
||||
click: '//a[text() = "sub_fn" and @href="#2-4"]'
|
||||
assert-property: ("html", {"scrollTop": "77"})
|
||||
|
||||
// We now check that clicking on lines doesn't change the scroll
|
||||
|
@ -14,10 +14,10 @@ extern crate source_code;
|
||||
#[path = "auxiliary/source-code-bar.rs"]
|
||||
pub mod bar;
|
||||
|
||||
// @count - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#5"]' 4
|
||||
// @count - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#5-7"]' 4
|
||||
use bar::Bar;
|
||||
// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#13"]' 'self'
|
||||
// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
|
||||
// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#13-17"]' 'self'
|
||||
// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#14-16"]' 'Trait'
|
||||
use bar::sub::{self, Trait};
|
||||
|
||||
pub struct Foo;
|
||||
@ -32,7 +32,8 @@ fn babar() {}
|
||||
// @has - '//pre[@class="rust"]//a/@href' '/primitive.u32.html'
|
||||
// @has - '//pre[@class="rust"]//a/@href' '/primitive.str.html'
|
||||
// @count - '//pre[@class="rust"]//a[@href="#23"]' 5
|
||||
// @has - '//pre[@class="rust"]//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
|
||||
// @has - '//pre[@class="rust"]//a[@href="../../source_code/struct.SourceCode.html"]' \
|
||||
// 'source_code::SourceCode'
|
||||
pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
|
||||
let x = 12;
|
||||
let y: Foo = Foo;
|
||||
@ -42,15 +43,15 @@ pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::Sour
|
||||
y.hello();
|
||||
}
|
||||
|
||||
// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait'
|
||||
// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
|
||||
// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#14-16"]' 'bar::sub::Trait'
|
||||
// @has - '//pre[@class="rust"]//a[@href="auxiliary/source-code-bar.rs.html#14-16"]' 'Trait'
|
||||
pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {}
|
||||
|
||||
pub trait AnotherTrait {}
|
||||
pub trait WhyNot {}
|
||||
|
||||
// @has - '//pre[@class="rust"]//a[@href="#49"]' 'AnotherTrait'
|
||||
// @has - '//pre[@class="rust"]//a[@href="#50"]' 'WhyNot'
|
||||
// @has - '//pre[@class="rust"]//a[@href="#50"]' 'AnotherTrait'
|
||||
// @has - '//pre[@class="rust"]//a[@href="#51"]' 'WhyNot'
|
||||
pub fn foo3<T, V>(t: &T, v: &V)
|
||||
where
|
||||
T: AnotherTrait,
|
||||
@ -59,7 +60,7 @@ where
|
||||
|
||||
pub trait AnotherTrait2 {}
|
||||
|
||||
// @has - '//pre[@class="rust"]//a[@href="#60"]' 'AnotherTrait2'
|
||||
// @has - '//pre[@class="rust"]//a[@href="#61"]' 'AnotherTrait2'
|
||||
pub fn foo4() {
|
||||
let x: Vec<AnotherTrait2> = Vec::new();
|
||||
}
|
||||
|
51
tests/rustdoc/jump-to-def-doc-links.rs
Normal file
51
tests/rustdoc/jump-to-def-doc-links.rs
Normal file
@ -0,0 +1,51 @@
|
||||
// compile-flags: -Zunstable-options --generate-link-to-definition
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
// @has 'src/foo/jump-to-def-doc-links.rs.html'
|
||||
|
||||
// @has - '//a[@href="../../foo/struct.Bar.html"]' 'Bar'
|
||||
// @has - '//a[@href="../../foo/struct.Foo.html"]' 'Foo'
|
||||
pub struct Bar; pub struct Foo;
|
||||
|
||||
// @has - '//a[@href="../../foo/enum.Enum.html"]' 'Enum'
|
||||
pub enum Enum {
|
||||
Variant1(String),
|
||||
Variant2(u8),
|
||||
}
|
||||
|
||||
// @has - '//a[@href="../../foo/struct.Struct.html"]' 'Struct'
|
||||
pub struct Struct {
|
||||
pub a: u8,
|
||||
b: Foo,
|
||||
}
|
||||
|
||||
impl Struct {
|
||||
pub fn foo() {}
|
||||
pub fn foo2(&self) {}
|
||||
fn bar() {}
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
// @has - '//a[@href="../../foo/trait.Trait.html"]' 'Trait'
|
||||
pub trait Trait {
|
||||
fn foo();
|
||||
}
|
||||
|
||||
impl Trait for Struct {
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
// @has - '//a[@href="../../foo/union.Union.html"]' 'Union'
|
||||
pub union Union {
|
||||
pub a: u16,
|
||||
pub f: u32,
|
||||
}
|
||||
|
||||
// @has - '//a[@href="../../foo/fn.bar.html"]' 'bar'
|
||||
pub fn bar(b: Bar) {
|
||||
let x = Foo;
|
||||
}
|
||||
|
||||
// @has - '//a[@href="../../foo/bar/index.html"]' 'bar'
|
||||
pub mod bar {}
|
Loading…
x
Reference in New Issue
Block a user