Skip to content

Commit

Permalink
Rollup merge of #134951 - compiler-errors:double-trait-err-msg, r=dav…
Browse files Browse the repository at this point in the history
…idtwco

Suppress host effect predicates if underlying trait doesn't hold

Don't report two errors for when the (`HostEffectPredicate`) `T: const Trait` isn't implemented because (`TraitPredicate`) `T: Trait` doesn't even hold.
  • Loading branch information
matthiaskrgr authored Jan 6, 2025
2 parents 44c6e83 + 62d6ee3 commit 68791ef
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
//
// We rely on a few heuristics to identify cases where this root
// obligation is more important than the leaf obligation:
let (main_trait_predicate, o) = if let ty::PredicateKind::Clause(
let (main_trait_predicate, main_obligation) = if let ty::PredicateKind::Clause(
ty::ClauseKind::Trait(root_pred)
) = root_obligation.predicate.kind().skip_binder()
&& !leaf_trait_predicate.self_ty().skip_binder().has_escaping_bound_vars()
Expand Down Expand Up @@ -199,7 +199,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
notes,
parent_label,
append_const_msg,
} = self.on_unimplemented_note(main_trait_predicate, o, &mut long_ty_file);
} = self.on_unimplemented_note(main_trait_predicate, main_obligation, &mut long_ty_file);

let have_alt_message = message.is_some() || label.is_some();
let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id());
Expand Down Expand Up @@ -538,23 +538,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}

ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
// FIXME(const_trait_impl): We should recompute the predicate with `~const`
// if it's `const`, and if it holds, explain that this bound only
// *conditionally* holds. If that fails, we should also do selection
// to drill this down to an impl or built-in source, so we can
// point at it and explain that while the trait *is* implemented,
// that implementation is not const.
let err_msg = self.get_standard_error_message(
bound_predicate.rebind(ty::TraitPredicate {
trait_ref: predicate.trait_ref,
polarity: ty::PredicatePolarity::Positive,
}),
None,
Some(predicate.constness),
None,
String::new(),
);
struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg)
self.report_host_effect_error(bound_predicate.rebind(predicate), obligation.param_env, span)
}

ty::PredicateKind::Subtype(predicate) => {
Expand Down Expand Up @@ -763,6 +747,41 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
applied_do_not_recommend
}

fn report_host_effect_error(
&self,
predicate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
span: Span,
) -> Diag<'a> {
// FIXME(const_trait_impl): We should recompute the predicate with `~const`
// if it's `const`, and if it holds, explain that this bound only
// *conditionally* holds. If that fails, we should also do selection
// to drill this down to an impl or built-in source, so we can
// point at it and explain that while the trait *is* implemented,
// that implementation is not const.
let trait_ref = predicate.map_bound(|predicate| ty::TraitPredicate {
trait_ref: predicate.trait_ref,
polarity: ty::PredicatePolarity::Positive,
});
let err_msg = self.get_standard_error_message(
trait_ref,
None,
Some(predicate.constness()),
None,
String::new(),
);
let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
if !self.predicate_may_hold(&Obligation::new(
self.tcx,
ObligationCause::dummy(),
param_env,
trait_ref,
)) {
diag.downgrade_to_delayed_bug();
}
diag
}

fn emit_specialized_closure_kind_error(
&self,
obligation: &PredicateObligation<'tcx>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Make sure we don't issue *two* error messages for the trait predicate *and* host predicate.

#![feature(const_trait_impl)]

#[const_trait]
trait Trait {
type Out;
}

const fn needs_const<T: ~const Trait>(_: &T) {}

const IN_CONST: () = {
needs_const(&());
//~^ ERROR the trait bound `(): Trait` is not satisfied
};

const fn conditionally_const() {
needs_const(&());
//~^ ERROR the trait bound `(): Trait` is not satisfied
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
error[E0277]: the trait bound `(): Trait` is not satisfied
--> $DIR/double-error-for-unimplemented-trait.rs:13:15
|
LL | needs_const(&());
| ----------- ^^^ the trait `Trait` is not implemented for `()`
| |
| required by a bound introduced by this call
|
help: this trait has no implementations, consider adding one
--> $DIR/double-error-for-unimplemented-trait.rs:6:1
|
LL | trait Trait {
| ^^^^^^^^^^^
note: required by a bound in `needs_const`
--> $DIR/double-error-for-unimplemented-trait.rs:10:25
|
LL | const fn needs_const<T: ~const Trait>(_: &T) {}
| ^^^^^^^^^^^^ required by this bound in `needs_const`

error[E0277]: the trait bound `(): Trait` is not satisfied
--> $DIR/double-error-for-unimplemented-trait.rs:18:15
|
LL | needs_const(&());
| ----------- ^^^ the trait `Trait` is not implemented for `()`
| |
| required by a bound introduced by this call
|
help: this trait has no implementations, consider adding one
--> $DIR/double-error-for-unimplemented-trait.rs:6:1
|
LL | trait Trait {
| ^^^^^^^^^^^
note: required by a bound in `needs_const`
--> $DIR/double-error-for-unimplemented-trait.rs:10:25
|
LL | const fn needs_const<T: ~const Trait>(_: &T) {}
| ^^^^^^^^^^^^ required by this bound in `needs_const`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.

0 comments on commit 68791ef

Please sign in to comment.