Skip to content
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

Improve const traits diagnostics for new desugaring #131152

Merged
merged 1 commit into from
Oct 2, 2024
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
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ macro_rules! TrivialLiftImpls {
};
}

/// Used for types that are `Copy` and which **do not care arena
/// Used for types that are `Copy` and which **do not care about arena
/// allocated data** (i.e., don't need to be folded).
#[macro_export]
macro_rules! TrivialTypeTraversalImpls {
Expand Down
46 changes: 34 additions & 12 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1951,19 +1951,18 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {

fn pretty_print_bound_constness(
&mut self,
trait_ref: ty::TraitRef<'tcx>,
constness: ty::BoundConstness,
) -> Result<(), PrintError> {
define_scoped_cx!(self);

let Some(idx) = self.tcx().generics_of(trait_ref.def_id).host_effect_index else {
return Ok(());
};
let arg = trait_ref.args.const_at(idx);

if arg == self.tcx().consts.false_ {
p!("const ");
} else if arg != self.tcx().consts.true_ && !arg.has_infer() {
p!("~const ");
match constness {
ty::BoundConstness::NotConst => {}
ty::BoundConstness::Const => {
p!("const ");
}
ty::BoundConstness::ConstIfConst => {
p!("~const ");
}
}
Ok(())
}
Expand Down Expand Up @@ -2948,13 +2947,29 @@ impl<'tcx> ty::TraitPredicate<'tcx> {
}
}

#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
pub struct TraitPredPrintWithBoundConstness<'tcx>(ty::TraitPredicate<'tcx>, ty::BoundConstness);

impl<'tcx> fmt::Debug for TraitPredPrintWithBoundConstness<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}

#[extension(pub trait PrintPolyTraitPredicateExt<'tcx>)]
impl<'tcx> ty::PolyTraitPredicate<'tcx> {
fn print_modifiers_and_trait_path(
self,
) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> {
self.map_bound(TraitPredPrintModifiersAndPath)
}

fn print_with_bound_constness(
self,
constness: ty::BoundConstness,
) -> ty::Binder<'tcx, TraitPredPrintWithBoundConstness<'tcx>> {
self.map_bound(|trait_pred| TraitPredPrintWithBoundConstness(trait_pred, constness))
}
}

#[derive(Debug, Copy, Clone, Lift)]
Expand Down Expand Up @@ -3052,7 +3067,6 @@ define_print! {

ty::TraitPredicate<'tcx> {
p!(print(self.trait_ref.self_ty()), ": ");
p!(pretty_print_bound_constness(self.trait_ref));
if let ty::PredicatePolarity::Negative = self.polarity {
p!("!");
}
Expand Down Expand Up @@ -3184,13 +3198,21 @@ define_print_and_forward_display! {
}

TraitPredPrintModifiersAndPath<'tcx> {
p!(pretty_print_bound_constness(self.0.trait_ref));
if let ty::PredicatePolarity::Negative = self.0.polarity {
p!("!")
}
p!(print(self.0.trait_ref.print_trait_sugared()));
}

TraitPredPrintWithBoundConstness<'tcx> {
p!(print(self.0.trait_ref.self_ty()), ": ");
p!(pretty_print_bound_constness(self.1));
if let ty::PredicatePolarity::Negative = self.0.polarity {
p!("!");
}
p!(print(self.0.trait_ref.print_trait_sugared()))
}

PrintClosureAsImpl<'tcx> {
p!(pretty_closure_as_impl(self.closure))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{
FmtPrinter, Print, PrintTraitPredicateExt as _, PrintTraitRefExt as _,
with_forced_trimmed_paths,
FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _,
PrintTraitRefExt as _, with_forced_trimmed_paths,
};
use rustc_middle::ty::{
self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast,
Expand Down Expand Up @@ -154,6 +154,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
} else {
(leaf_trait_predicate, &obligation)
};

let (main_trait_predicate, leaf_trait_predicate, predicate_constness) = self.get_effects_trait_pred_override(main_trait_predicate, leaf_trait_predicate, span);

let main_trait_ref = main_trait_predicate.to_poly_trait_ref();
let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref();

Expand All @@ -164,9 +167,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return guar;
}

// FIXME(effects)
let predicate_is_const = false;

if let Err(guar) = leaf_trait_predicate.error_reported()
{
return guar;
Expand Down Expand Up @@ -227,7 +227,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let err_msg = self.get_standard_error_message(
main_trait_predicate,
message,
predicate_is_const,
predicate_constness,
append_const_msg,
post_message,
);
Expand Down Expand Up @@ -286,7 +286,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}

if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop)
&& predicate_is_const
&& matches!(predicate_constness, ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const)
{
err.note("`~const Drop` was renamed to `~const Destruct`");
err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
Expand Down Expand Up @@ -2187,29 +2187,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&self,
trait_predicate: ty::PolyTraitPredicate<'tcx>,
message: Option<String>,
predicate_is_const: bool,
predicate_constness: ty::BoundConstness,
append_const_msg: Option<AppendConstMessage>,
post_message: String,
) -> String {
message
.and_then(|cannot_do_this| {
match (predicate_is_const, append_const_msg) {
match (predicate_constness, append_const_msg) {
// do nothing if predicate is not const
(false, _) => Some(cannot_do_this),
(ty::BoundConstness::NotConst, _) => Some(cannot_do_this),
// suggested using default post message
(true, Some(AppendConstMessage::Default)) => {
Some(format!("{cannot_do_this} in const contexts"))
}
(
ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst,
Some(AppendConstMessage::Default),
) => Some(format!("{cannot_do_this} in const contexts")),
// overridden post message
(true, Some(AppendConstMessage::Custom(custom_msg, _))) => {
Some(format!("{cannot_do_this}{custom_msg}"))
}
(
ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst,
Some(AppendConstMessage::Custom(custom_msg, _)),
) => Some(format!("{cannot_do_this}{custom_msg}")),
// fallback to generic message
(true, None) => None,
(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst, None) => None,
}
})
.unwrap_or_else(|| {
format!("the trait bound `{trait_predicate}` is not satisfied{post_message}")
format!(
"the trait bound `{}` is not satisfied{post_message}",
trait_predicate.print_with_bound_constness(predicate_constness)
)
})
}

Expand Down Expand Up @@ -2333,6 +2338,51 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}

/// For effects predicates such as `<u32 as Add>::Effects: Compat<host>`, pretend that the
/// predicate that failed was `u32: Add`. Return the constness of such predicate to later
/// print as `u32: ~const Add`.
fn get_effects_trait_pred_override(
&self,
p: ty::PolyTraitPredicate<'tcx>,
leaf: ty::PolyTraitPredicate<'tcx>,
span: Span,
) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, ty::BoundConstness) {
let trait_ref = p.to_poly_trait_ref();
if !self.tcx.is_lang_item(trait_ref.def_id(), LangItem::EffectsCompat) {
return (p, leaf, ty::BoundConstness::NotConst);
}

let Some(ty::Alias(ty::AliasTyKind::Projection, projection)) =
trait_ref.self_ty().no_bound_vars().map(Ty::kind)
else {
return (p, leaf, ty::BoundConstness::NotConst);
};

let constness = trait_ref.skip_binder().args.const_at(1);

let constness = if constness == self.tcx.consts.true_ || constness.is_ct_infer() {
ty::BoundConstness::NotConst
} else if constness == self.tcx.consts.false_ {
ty::BoundConstness::Const
} else if matches!(constness.kind(), ty::ConstKind::Param(_)) {
ty::BoundConstness::ConstIfConst
} else {
self.dcx().span_bug(span, format!("Unknown constness argument: {constness:?}"));
};

let new_pred = p.map_bound(|mut trait_pred| {
trait_pred.trait_ref = projection.trait_ref(self.tcx);
trait_pred
});

let new_leaf = leaf.map_bound(|mut trait_pred| {
trait_pred.trait_ref = projection.trait_ref(self.tcx);
trait_pred
});

(new_pred, new_leaf, constness)
}

fn add_tuple_trait_message(
&self,
obligation_cause_code: &ObligationCauseCode<'tcx>,
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_type_ir/src/predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,3 +755,10 @@ impl fmt::Display for BoundConstness {
}
}
}

impl<I> Lift<I> for BoundConstness {
type Lifted = BoundConstness;
fn lift_to_interner(self, _: I) -> Option<Self::Lifted> {
Some(self)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ error: using `#![feature(effects)]` without enabling next trait solver globally
= note: the next trait solver must be enabled globally for the effects feature to work correctly
= help: use `-Znext-solver` to enable

error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied
error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-0.rs:13:5
|
LL | T::Assoc::func()
| ^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}`
| ^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
|
note: required by a bound in `Trait::func`
--> $DIR/assoc-type-const-bound-usage-0.rs:6:1
Expand All @@ -17,12 +17,16 @@ LL | #[const_trait]
...
LL | fn func() -> i32;
| ---- required by a bound in this associated function
help: consider further restricting the associated type
|
LL | const fn unqualified<T: ~const Trait>() -> i32 where <T as Trait>::Assoc: Trait {
| ++++++++++++++++++++++++++++++++

error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied
error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-0.rs:17:5
|
LL | <T as Trait>::Assoc::func()
| ^^^^^^^^^^^^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}`
| ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
|
note: required by a bound in `Trait::func`
--> $DIR/assoc-type-const-bound-usage-0.rs:6:1
Expand All @@ -32,6 +36,10 @@ LL | #[const_trait]
...
LL | fn func() -> i32;
| ---- required by a bound in this associated function
help: consider further restricting the associated type
|
LL | const fn qualified<T: ~const Trait>() -> i32 where <T as Trait>::Assoc: Trait {
| ++++++++++++++++++++++++++++++++

error: aborting due to 3 previous errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ error: using `#![feature(effects)]` without enabling next trait solver globally
= note: the next trait solver must be enabled globally for the effects feature to work correctly
= help: use `-Znext-solver` to enable

error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied
error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-1.rs:15:44
|
LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> {
| ^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}`
| ^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
|
note: required by a bound in `Trait::func`
--> $DIR/assoc-type-const-bound-usage-1.rs:7:1
Expand All @@ -17,12 +17,16 @@ LL | #[const_trait]
...
LL | fn func() -> i32;
| ---- required by a bound in this associated function
help: consider further restricting the associated type
|
LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> where <T as Trait>::Assoc: Trait {
| ++++++++++++++++++++++++++++++++

error[E0277]: the trait bound `Trait::{synthetic#0}: Compat` is not satisfied
error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-1.rs:19:42
|
LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> {
| ^^^^^^^^^^^^^^^^^^^ the trait `Compat` is not implemented for `Trait::{synthetic#0}`
| ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
|
note: required by a bound in `Trait::func`
--> $DIR/assoc-type-const-bound-usage-1.rs:7:1
Expand All @@ -32,6 +36,10 @@ LL | #[const_trait]
...
LL | fn func() -> i32;
| ---- required by a bound in this associated function
help: consider further restricting the associated type
|
LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> where <T as Trait>::Assoc: Trait {
| ++++++++++++++++++++++++++++++++

error: aborting due to 3 previous errors

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
//@ compile-flags: -Znext-solver
#![allow(incomplete_features)]
#![feature(const_trait_impl, effects)]

#[const_trait]
pub trait Plus {
Expand All @@ -23,7 +25,7 @@ pub const fn add_i32(a: i32, b: i32) -> i32 {

pub const fn add_u32(a: u32, b: u32) -> u32 {
a.plus(b)
//~^ ERROR the trait bound
//~^ ERROR the trait bound `u32: ~const Plus`
}

fn main() {}
Loading
Loading