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

Suppress host effect predicates if underlying trait doesn't hold #134951

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
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`.
Loading