Add an opt-out in pretty printing for RTN rendering
This commit is contained in:
parent
6650252439
commit
7a08d0368f
8 changed files with 154 additions and 32 deletions
|
@ -84,6 +84,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt as _};
|
|||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::print::with_types_for_signature;
|
||||
use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::parse::feature_err;
|
||||
|
@ -240,11 +241,11 @@ fn missing_items_err(
|
|||
(Vec::new(), Vec::new(), Vec::new());
|
||||
|
||||
for &trait_item in missing_items {
|
||||
let snippet = suggestion_signature(
|
||||
let snippet = with_types_for_signature!(suggestion_signature(
|
||||
tcx,
|
||||
trait_item,
|
||||
tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(),
|
||||
);
|
||||
));
|
||||
let code = format!("{padding}{snippet}\n{padding}");
|
||||
if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
|
||||
missing_trait_item_label
|
||||
|
|
|
@ -63,6 +63,18 @@ thread_local! {
|
|||
static FORCE_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
|
||||
static REDUCED_QUERIES: Cell<bool> = const { Cell::new(false) };
|
||||
static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };
|
||||
static RTN_MODE: Cell<RtnMode> = const { Cell::new(RtnMode::ForDiagnostic) };
|
||||
}
|
||||
|
||||
/// Rendering style for RTN types.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum RtnMode {
|
||||
/// Print the RTN type as an impl trait with its path, i.e.e `impl Sized { T::method(..) }`.
|
||||
ForDiagnostic,
|
||||
/// Print the RTN type as an impl trait, i.e. `impl Sized`.
|
||||
ForSignature,
|
||||
/// Print the RTN type as a value path, i.e. `T::method(..): ...`.
|
||||
ForSuggestion,
|
||||
}
|
||||
|
||||
macro_rules! define_helper {
|
||||
|
@ -124,6 +136,38 @@ define_helper!(
|
|||
fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH);
|
||||
);
|
||||
|
||||
#[must_use]
|
||||
pub struct RtnModeHelper(RtnMode);
|
||||
|
||||
impl RtnModeHelper {
|
||||
pub fn with(mode: RtnMode) -> RtnModeHelper {
|
||||
RtnModeHelper(RTN_MODE.with(|c| c.replace(mode)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RtnModeHelper {
|
||||
fn drop(&mut self) {
|
||||
RTN_MODE.with(|c| c.set(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
/// Print types for the purposes of a suggestion.
|
||||
///
|
||||
/// Specifically, this will render RPITITs as `T::method(..)` which is suitable for
|
||||
/// things like where-clauses.
|
||||
pub macro with_types_for_suggestion($e:expr) {{
|
||||
let _guard = $crate::ty::print::pretty::RtnModeHelper::with(RtnMode::ForSuggestion);
|
||||
$e
|
||||
}}
|
||||
|
||||
/// Print types for the purposes of a signature suggestion.
|
||||
///
|
||||
/// Specifically, this will render RPITITs as `impl Trait` rather than `T::method(..)`.
|
||||
pub macro with_types_for_signature($e:expr) {{
|
||||
let _guard = $crate::ty::print::pretty::RtnModeHelper::with(RtnMode::ForSignature);
|
||||
$e
|
||||
}}
|
||||
|
||||
/// Avoids running any queries during prints.
|
||||
pub macro with_no_queries($e:expr) {{
|
||||
$crate::ty::print::with_reduced_queries!($crate::ty::print::with_forced_impl_filename_line!(
|
||||
|
@ -1223,22 +1267,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
}
|
||||
}
|
||||
|
||||
if self.tcx().features().return_type_notation()
|
||||
&& let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
|
||||
self.tcx().opt_rpitit_info(def_id)
|
||||
&& let ty::Alias(_, alias_ty) =
|
||||
self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind()
|
||||
&& alias_ty.def_id == def_id
|
||||
&& let generics = self.tcx().generics_of(fn_def_id)
|
||||
// FIXME(return_type_notation): We only support lifetime params for now.
|
||||
&& generics.own_params.iter().all(|param| matches!(param.kind, ty::GenericParamDefKind::Lifetime))
|
||||
{
|
||||
let num_args = generics.count();
|
||||
write!(self, " {{ ")?;
|
||||
self.print_def_path(fn_def_id, &args[..num_args])?;
|
||||
write!(self, "(..) }}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1306,6 +1334,46 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
)
|
||||
}
|
||||
|
||||
fn pretty_print_rpitit(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> Result<(), PrintError> {
|
||||
let fn_args = if self.tcx().features().return_type_notation()
|
||||
&& let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
|
||||
self.tcx().opt_rpitit_info(def_id)
|
||||
&& let ty::Alias(_, alias_ty) =
|
||||
self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind()
|
||||
&& alias_ty.def_id == def_id
|
||||
&& let generics = self.tcx().generics_of(fn_def_id)
|
||||
// FIXME(return_type_notation): We only support lifetime params for now.
|
||||
&& generics.own_params.iter().all(|param| matches!(param.kind, ty::GenericParamDefKind::Lifetime))
|
||||
{
|
||||
let num_args = generics.count();
|
||||
Some((fn_def_id, &args[..num_args]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match (fn_args, RTN_MODE.with(|c| c.get())) {
|
||||
(Some((fn_def_id, fn_args)), RtnMode::ForDiagnostic) => {
|
||||
self.pretty_print_opaque_impl_type(def_id, args)?;
|
||||
write!(self, " {{ ")?;
|
||||
self.print_def_path(fn_def_id, fn_args)?;
|
||||
write!(self, "(..) }}")?;
|
||||
}
|
||||
(Some((fn_def_id, fn_args)), RtnMode::ForSuggestion) => {
|
||||
self.print_def_path(fn_def_id, fn_args)?;
|
||||
write!(self, "(..)")?;
|
||||
}
|
||||
_ => {
|
||||
self.pretty_print_opaque_impl_type(def_id, args)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> {
|
||||
None
|
||||
}
|
||||
|
@ -3123,21 +3191,20 @@ define_print! {
|
|||
ty::AliasTerm<'tcx> {
|
||||
match self.kind(cx.tcx()) {
|
||||
ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
|
||||
ty::AliasTermKind::ProjectionTy
|
||||
ty::AliasTermKind::ProjectionTy => {
|
||||
if !(cx.should_print_verbose() || with_reduced_queries())
|
||||
&& cx.tcx().is_impl_trait_in_trait(self.def_id)
|
||||
{
|
||||
p!(pretty_print_rpitit(self.def_id, self.args))
|
||||
} else {
|
||||
p!(print_def_path(self.def_id, self.args));
|
||||
}
|
||||
}
|
||||
| ty::AliasTermKind::WeakTy
|
||||
| ty::AliasTermKind::OpaqueTy
|
||||
| ty::AliasTermKind::UnevaluatedConst
|
||||
| ty::AliasTermKind::ProjectionConst => {
|
||||
// If we're printing verbosely, or don't want to invoke queries
|
||||
// (`is_impl_trait_in_trait`), then fall back to printing the def path.
|
||||
// This is likely what you want if you're debugging the compiler anyways.
|
||||
if !(cx.should_print_verbose() || with_reduced_queries())
|
||||
&& cx.tcx().is_impl_trait_in_trait(self.def_id)
|
||||
{
|
||||
return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
|
||||
} else {
|
||||
p!(print_def_path(self.def_id, self.args));
|
||||
}
|
||||
p!(print_def_path(self.def_id, self.args));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ use rustc_middle::traits::IsConstable;
|
|||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::print::{
|
||||
PrintPolyTraitPredicateExt as _, PrintPolyTraitRefExt, PrintTraitPredicateExt as _,
|
||||
with_forced_trimmed_paths, with_no_trimmed_paths,
|
||||
with_forced_trimmed_paths, with_no_trimmed_paths, with_types_for_suggestion,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,
|
||||
|
@ -111,7 +111,7 @@ impl<'a, 'tcx> CoroutineData<'a, 'tcx> {
|
|||
fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
|
||||
(
|
||||
generics.tail_span_for_predicate_suggestion(),
|
||||
format!("{} {}", generics.add_where_or_trailing_comma(), pred),
|
||||
with_types_for_suggestion!(format!("{} {}", generics.add_where_or_trailing_comma(), pred)),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,8 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(
|
|||
if hir_generics.where_clause_span.from_expansion()
|
||||
|| hir_generics.where_clause_span.desugaring_kind().is_some()
|
||||
|| projection.is_some_and(|projection| {
|
||||
tcx.is_impl_trait_in_trait(projection.def_id)
|
||||
(tcx.is_impl_trait_in_trait(projection.def_id)
|
||||
&& !tcx.features().return_type_notation())
|
||||
|| tcx.lookup_stability(projection.def_id).is_some_and(|stab| stab.is_unstable())
|
||||
})
|
||||
{
|
||||
|
|
|
@ -15,6 +15,10 @@ note: required by a bound in `is_send`
|
|||
|
|
||||
LL | fn is_send(_: impl Send) {}
|
||||
| ^^^^ required by this bound in `is_send`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | >() where <T as Foo>::method(..): Send {
|
||||
| ++++++++++++++++++++++++++++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@ note: required by a bound in `needs_trait`
|
|||
|
|
||||
LL | fn needs_trait(_: impl Trait) {}
|
||||
| ^^^^^ required by this bound in `needs_trait`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn foo<T: Assoc>(t: T) where <T as Assoc>::method(..): Trait {
|
||||
| +++++++++++++++++++++++++++++++++++++
|
||||
|
||||
error[E0277]: the trait bound `impl Sized { <T as Assoc>::method_with_lt(..) }: Trait` is not satisfied
|
||||
--> $DIR/display.rs:16:17
|
||||
|
@ -25,6 +29,10 @@ note: required by a bound in `needs_trait`
|
|||
|
|
||||
LL | fn needs_trait(_: impl Trait) {}
|
||||
| ^^^^^ required by this bound in `needs_trait`
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | fn foo<T: Assoc>(t: T) where <T as Assoc>::method_with_lt(..): Trait {
|
||||
| +++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
error[E0277]: the trait bound `impl Sized: Trait` is not satisfied
|
||||
--> $DIR/display.rs:18:17
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
//@ run-rustfix
|
||||
|
||||
#![allow(unused)]
|
||||
#![feature(return_type_notation)]
|
||||
|
||||
trait Foo {
|
||||
fn missing() -> impl Sized;
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
//~^ ERROR not all trait items implemented, missing: `missing`
|
||||
fn missing() -> impl Sized { todo!() }
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,14 @@
|
|||
//@ run-rustfix
|
||||
|
||||
#![allow(unused)]
|
||||
#![feature(return_type_notation)]
|
||||
|
||||
trait Foo {
|
||||
fn missing() -> impl Sized;
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
//~^ ERROR not all trait items implemented, missing: `missing`
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,12 @@
|
|||
error[E0046]: not all trait items implemented, missing: `missing`
|
||||
--> $DIR/rendering.rs:10:1
|
||||
|
|
||||
LL | fn missing() -> impl Sized;
|
||||
| --------------------------- `missing` from trait
|
||||
...
|
||||
LL | impl Foo for () {
|
||||
| ^^^^^^^^^^^^^^^ missing `missing` in implementation
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0046`.
|
Loading…
Add table
Add a link
Reference in a new issue