diff --git a/.editorconfig b/.editorconfig index d065fa46469fc..eadd72e499373 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,8 @@ trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 + +[*.rs] max_line_length = 100 [*.md] diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c7925be0d7d78..b603a87874602 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -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"); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index ed9bb4945afc1..0df4ba67b4b1b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -2,7 +2,7 @@ use crate::FnCtxt; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; -use rustc_infer::traits::ObligationCauseCode; +use rustc_infer::{infer::type_variable::TypeVariableOriginKind, traits::ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_span::{self, symbol::kw, Span}; use rustc_trait_selection::traits; @@ -254,8 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { type BreakTy = ty::GenericArg<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow { if let Some(origin) = self.0.type_var_origin(ty) - && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = - origin.kind + && let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind && let generics = self.0.tcx.generics_of(self.1) && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index a90a41f5d70a2..5c357f2c65b7e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -163,7 +163,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte let ty_vars = infcx_inner.type_variables(); let var_origin = ty_vars.var_origin(ty_vid); if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind - && !var_origin.span.from_expansion() + && name != kw::SelfUpper && !var_origin.span.from_expansion() { let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id)); let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap(); diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index 527afa005b9f7..8698cf8602262 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -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) } } diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index 2ee625674faa0..f19f1189e4440 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -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 } } - pub(super) fn format_goal_evaluation(&mut self, goal: &GoalEvaluation<'_>) -> std::fmt::Result { - let f = &mut *self.f; + fn nested(&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 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(()) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 87e0b211556b9..527d5220564cc 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -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 } } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 7fb31df84d003..df682cd8f3ac3 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -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()) } diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 3181af46e9cb3..389e3364117f0 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -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), } @@ -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); + +#[derive(Clone, Debug)] +pub enum GenericArgKind { + // FIXME add proper region + Lifetime(Region), + Type(Ty), + // FIXME add proper const + Const(Const), +} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 74dfbdddbab95..7b41e9754741d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -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(); } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index f40202cf2c59e..8f3e638cb57ed 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -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); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 88ee14c4db587..f1d3091225c0f 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -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 { diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs index 2d6717fdad9fa..cda68396321ce 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -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), } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 4dc06d2bfac63..bb70096608ccd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -3556,7 +3556,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(); }); } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index c94968b4817cb..f87dd0e79b703 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -988,6 +988,11 @@ fn string_without_closing_tag( ) .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) + } } }) { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 4c47626363518..cc0e6b85ae1c1 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -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()); diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index eb9262f472b67..ac587bf6008de 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -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); + } } diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml index 67f1497e70ce6..0e4913cafb2ab 100644 --- a/tests/rustdoc-gui/source-anchor-scroll.goml +++ b/tests/rustdoc-gui/source-anchor-scroll.goml @@ -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 diff --git a/tests/rustdoc/check-source-code-urls-to-def.rs b/tests/rustdoc/check-source-code-urls-to-def.rs index 41b9d41fa4410..b803c7e9e86c7 100644 --- a/tests/rustdoc/check-source-code-urls-to-def.rs +++ b/tests/rustdoc/check-source-code-urls-to-def.rs @@ -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: &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: &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 = Vec::new(); } diff --git a/tests/rustdoc/jump-to-def-doc-links.rs b/tests/rustdoc/jump-to-def-doc-links.rs new file mode 100644 index 0000000000000..014d5803299cb --- /dev/null +++ b/tests/rustdoc/jump-to-def-doc-links.rs @@ -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 {} diff --git a/tests/ui/inference/need_type_info/infer-var-for-self-param.rs b/tests/ui/inference/need_type_info/infer-var-for-self-param.rs new file mode 100644 index 0000000000000..51ac7943f2490 --- /dev/null +++ b/tests/ui/inference/need_type_info/infer-var-for-self-param.rs @@ -0,0 +1,7 @@ +// Regression test for #113610 where we ICEd when trying to print +// inference variables created by instantiating the self type parameter. + +fn main() { + let _ = (Default::default(),); + //~^ ERROR cannot call associated function on trait +} diff --git a/tests/ui/inference/need_type_info/infer-var-for-self-param.stderr b/tests/ui/inference/need_type_info/infer-var-for-self-param.stderr new file mode 100644 index 0000000000000..fdef4d0dd0920 --- /dev/null +++ b/tests/ui/inference/need_type_info/infer-var-for-self-param.stderr @@ -0,0 +1,14 @@ +error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type + --> $DIR/infer-var-for-self-param.rs:5:14 + | +LL | let _ = (Default::default(),); + | ^^^^^^^^^^^^^^^^ cannot call associated function of trait + | +help: use a fully-qualified path to a specific available implementation (271 found) + | +LL | let _ = (::default(),); + | +++++++++++++++++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0790`.