1
Fork 0

Rollup merge of #132345 - compiler-errors:fx-diag, r=lcnr

Improve diagnostics for `HostEffectPredicate` in the new solver

Adds derived cause for host effect predicates. Some diagnostics regress, but that's connected to the fact that our predicate visitor doesn't play well with aliases just yet.
This commit is contained in:
Jacob Pratt 2025-01-06 22:04:13 -05:00 committed by GitHub
commit b642740e4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 284 additions and 41 deletions

View file

@ -125,6 +125,15 @@ impl<'tcx> ObligationCause<'tcx> {
self self
} }
pub fn derived_host_cause(
mut self,
parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
variant: impl FnOnce(DerivedHostCause<'tcx>) -> ObligationCauseCode<'tcx>,
) -> ObligationCause<'tcx> {
self.code = variant(DerivedHostCause { parent_host_pred, parent_code: self.code }).into();
self
}
pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
match self.code() { match self.code() {
ObligationCauseCode::MatchImpl(cause, _) => cause.to_constraint_category(), ObligationCauseCode::MatchImpl(cause, _) => cause.to_constraint_category(),
@ -278,6 +287,14 @@ pub enum ObligationCauseCode<'tcx> {
/// Derived obligation for WF goals. /// Derived obligation for WF goals.
WellFormedDerived(DerivedCause<'tcx>), WellFormedDerived(DerivedCause<'tcx>),
/// Derived obligation (i.e. `where` clause) on an user-provided impl
/// or a trait alias.
ImplDerivedHost(Box<ImplDerivedHostCause<'tcx>>),
/// Derived obligation (i.e. `where` clause) on an user-provided impl
/// or a trait alias.
BuiltinDerivedHost(DerivedHostCause<'tcx>),
/// Derived obligation refined to point at a specific argument in /// Derived obligation refined to point at a specific argument in
/// a call or method expression. /// a call or method expression.
FunctionArg { FunctionArg {
@ -437,36 +454,38 @@ pub enum WellFormedLoc {
}, },
} }
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedCause<'tcx> {
pub derived: DerivedCause<'tcx>,
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
/// that exceptional case where appropriate.
pub impl_or_alias_def_id: DefId,
/// The index of the derived predicate in the parent impl's predicates.
pub impl_def_predicate_index: Option<usize>,
pub span: Span,
}
impl<'tcx> ObligationCauseCode<'tcx> { impl<'tcx> ObligationCauseCode<'tcx> {
/// Returns the base obligation, ignoring derived obligations. /// Returns the base obligation, ignoring derived obligations.
pub fn peel_derives(&self) -> &Self { pub fn peel_derives(&self) -> &Self {
let mut base_cause = self; let mut base_cause = self;
while let Some((parent_code, _)) = base_cause.parent() { while let Some(parent_code) = base_cause.parent() {
base_cause = parent_code; base_cause = parent_code;
} }
base_cause base_cause
} }
pub fn parent(&self) -> Option<&Self> {
match self {
ObligationCauseCode::FunctionArg { parent_code, .. } => Some(parent_code),
ObligationCauseCode::BuiltinDerived(derived)
| ObligationCauseCode::WellFormedDerived(derived)
| ObligationCauseCode::ImplDerived(box ImplDerivedCause { derived, .. }) => {
Some(&derived.parent_code)
}
ObligationCauseCode::BuiltinDerivedHost(derived)
| ObligationCauseCode::ImplDerivedHost(box ImplDerivedHostCause { derived, .. }) => {
Some(&derived.parent_code)
}
_ => None,
}
}
/// Returns the base obligation and the base trait predicate, if any, ignoring /// Returns the base obligation and the base trait predicate, if any, ignoring
/// derived obligations. /// derived obligations.
pub fn peel_derives_with_predicate(&self) -> (&Self, Option<ty::PolyTraitPredicate<'tcx>>) { pub fn peel_derives_with_predicate(&self) -> (&Self, Option<ty::PolyTraitPredicate<'tcx>>) {
let mut base_cause = self; let mut base_cause = self;
let mut base_trait_pred = None; let mut base_trait_pred = None;
while let Some((parent_code, parent_pred)) = base_cause.parent() { while let Some((parent_code, parent_pred)) = base_cause.parent_with_predicate() {
base_cause = parent_code; base_cause = parent_code;
if let Some(parent_pred) = parent_pred { if let Some(parent_pred) = parent_pred {
base_trait_pred = Some(parent_pred); base_trait_pred = Some(parent_pred);
@ -476,7 +495,7 @@ impl<'tcx> ObligationCauseCode<'tcx> {
(base_cause, base_trait_pred) (base_cause, base_trait_pred)
} }
pub fn parent(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> { pub fn parent_with_predicate(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
match self { match self {
ObligationCauseCode::FunctionArg { parent_code, .. } => Some((parent_code, None)), ObligationCauseCode::FunctionArg { parent_code, .. } => Some((parent_code, None)),
ObligationCauseCode::BuiltinDerived(derived) ObligationCauseCode::BuiltinDerived(derived)
@ -573,6 +592,42 @@ pub struct DerivedCause<'tcx> {
pub parent_code: InternedObligationCauseCode<'tcx>, pub parent_code: InternedObligationCauseCode<'tcx>,
} }
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedCause<'tcx> {
pub derived: DerivedCause<'tcx>,
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
/// that exceptional case where appropriate.
pub impl_or_alias_def_id: DefId,
/// The index of the derived predicate in the parent impl's predicates.
pub impl_def_predicate_index: Option<usize>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct DerivedHostCause<'tcx> {
/// The trait predicate of the parent obligation that led to the
/// current obligation. Note that only trait obligations lead to
/// derived obligations, so we just store the trait predicate here
/// directly.
pub parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
/// The parent trait had this cause.
pub parent_code: InternedObligationCauseCode<'tcx>,
}
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedHostCause<'tcx> {
pub derived: DerivedHostCause<'tcx>,
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
pub impl_def_id: DefId,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)] #[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)]
pub enum SelectionError<'tcx> { pub enum SelectionError<'tcx> {
/// The trait is not implemented. /// The trait is not implemented.

View file

@ -634,6 +634,28 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyProjectionPredicate<'tcx>> for Clause<'t
} }
} }
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>>
for Predicate<'tcx>
{
fn upcast_from(
from: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
tcx: TyCtxt<'tcx>,
) -> Self {
from.map_bound(ty::ClauseKind::HostEffect).upcast(tcx)
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>>
for Clause<'tcx>
{
fn upcast_from(
from: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
tcx: TyCtxt<'tcx>,
) -> Self {
from.map_bound(ty::ClauseKind::HostEffect).upcast(tcx)
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, NormalizesTo<'tcx>> for Predicate<'tcx> { impl<'tcx> UpcastFrom<TyCtxt<'tcx>, NormalizesTo<'tcx>> for Predicate<'tcx> {
fn upcast_from(from: NormalizesTo<'tcx>, tcx: TyCtxt<'tcx>) -> Self { fn upcast_from(from: NormalizesTo<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
PredicateKind::NormalizesTo(from).upcast(tcx) PredicateKind::NormalizesTo(from).upcast(tcx)

View file

@ -103,7 +103,7 @@ where
|ecx| { |ecx| {
// Const conditions must hold for the implied const bound to hold. // Const conditions must hold for the implied const bound to hold.
ecx.add_goals( ecx.add_goals(
GoalSource::Misc, GoalSource::AliasBoundConstCondition,
cx.const_conditions(alias_ty.def_id) cx.const_conditions(alias_ty.def_id)
.iter_instantiated(cx, alias_ty.args) .iter_instantiated(cx, alias_ty.args)
.map(|trait_ref| { .map(|trait_ref| {
@ -353,7 +353,7 @@ where
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
ecx.add_goals( ecx.add_goals(
GoalSource::Misc, GoalSource::AliasBoundConstCondition,
const_conditions.into_iter().map(|trait_ref| { const_conditions.into_iter().map(|trait_ref| {
goal.with( goal.with(
cx, cx,

View file

@ -737,7 +737,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
applied_do_not_recommend = true; applied_do_not_recommend = true;
} }
} }
if let Some((parent_cause, _parent_pred)) = base_cause.parent() { if let Some(parent_cause) = base_cause.parent() {
base_cause = parent_cause.clone(); base_cause = parent_cause.clone();
} else { } else {
break; break;
@ -797,7 +797,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind() trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
&& !found_kind.extends(expected_kind) && !found_kind.extends(expected_kind)
{ {
if let Some((_, Some(parent))) = obligation.cause.code().parent() { if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal. // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
trait_ref = parent.to_poly_trait_ref(); trait_ref = parent.to_poly_trait_ref();
} else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } = } else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
@ -945,7 +945,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let Some(typeck) = &self.typeck_results else { let Some(typeck) = &self.typeck_results else {
return false; return false;
}; };
let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent() let Some((ObligationCauseCode::QuestionMark, Some(y))) =
obligation.cause.code().parent_with_predicate()
else { else {
return false; return false;
}; };
@ -1198,7 +1199,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut code = obligation.cause.code(); let mut code = obligation.cause.code();
let mut pred = obligation.predicate.as_trait_clause(); let mut pred = obligation.predicate.as_trait_clause();
while let Some((next_code, next_pred)) = code.parent() { while let Some((next_code, next_pred)) = code.parent_with_predicate() {
if let Some(pred) = pred { if let Some(pred) = pred {
self.enter_forall(pred, |pred| { self.enter_forall(pred, |pred| {
diag.note(format!( diag.note(format!(
@ -2114,7 +2115,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut code = obligation.cause.code(); let mut code = obligation.cause.code();
let mut trait_pred = trait_predicate; let mut trait_pred = trait_predicate;
let mut peeled = false; let mut peeled = false;
while let Some((parent_code, parent_trait_pred)) = code.parent() { while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
code = parent_code; code = parent_code;
if let Some(parent_trait_pred) = parent_trait_pred { if let Some(parent_trait_pred) = parent_trait_pred {
trait_pred = parent_trait_pred; trait_pred = parent_trait_pred;

View file

@ -464,7 +464,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Get the root obligation, since the leaf obligation we have may be unhelpful (#87437) // Get the root obligation, since the leaf obligation we have may be unhelpful (#87437)
let mut real_trait_pred = trait_pred; let mut real_trait_pred = trait_pred;
while let Some((parent_code, parent_trait_pred)) = code.parent() { while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
code = parent_code; code = parent_code;
if let Some(parent_trait_pred) = parent_trait_pred { if let Some(parent_trait_pred) = parent_trait_pred {
real_trait_pred = parent_trait_pred; real_trait_pred = parent_trait_pred;
@ -1447,7 +1447,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut span = obligation.cause.span; let mut span = obligation.cause.span;
let mut trait_pred = trait_pred; let mut trait_pred = trait_pred;
let mut code = obligation.cause.code(); let mut code = obligation.cause.code();
while let Some((c, Some(parent_trait_pred))) = code.parent() { while let Some((c, Some(parent_trait_pred))) = code.parent_with_predicate() {
// We want the root obligation, in order to detect properly handle // We want the root obligation, in order to detect properly handle
// `for _ in &mut &mut vec![] {}`. // `for _ in &mut &mut vec![] {}`.
code = c; code = c;
@ -3470,6 +3470,59 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
) )
}); });
} }
ObligationCauseCode::ImplDerivedHost(ref data) => {
let self_ty =
self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty());
let msg = format!(
"required for `{self_ty}` to implement `{} {}`",
data.derived.parent_host_pred.skip_binder().constness,
data.derived
.parent_host_pred
.map_bound(|pred| pred.trait_ref)
.print_only_trait_path(),
);
match tcx.hir().get_if_local(data.impl_def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
..
})) => {
let mut spans = vec![self_ty.span];
spans.extend(of_trait.as_ref().map(|t| t.path.span));
let mut spans: MultiSpan = spans.into();
spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
err.span_note(spans, msg);
}
_ => {
err.note(msg);
}
}
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
body_id,
err,
data.derived.parent_host_pred,
param_env,
&data.derived.parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
ObligationCauseCode::BuiltinDerivedHost(ref data) => {
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
body_id,
err,
data.parent_host_pred,
param_env,
&data.parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
ObligationCauseCode::WellFormedDerived(ref data) => { ObligationCauseCode::WellFormedDerived(ref data) => {
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
let parent_predicate = parent_trait_ref; let parent_predicate = parent_trait_ref;

View file

@ -430,6 +430,7 @@ impl<'tcx> BestObligation<'tcx> {
matches!( matches!(
nested_goal.source(), nested_goal.source(),
GoalSource::ImplWhereBound GoalSource::ImplWhereBound
| GoalSource::AliasBoundConstCondition
| GoalSource::InstantiateHigherRanked | GoalSource::InstantiateHigherRanked
| GoalSource::AliasWellFormed | GoalSource::AliasWellFormed
) && match self.consider_ambiguities { ) && match self.consider_ambiguities {
@ -491,8 +492,11 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
// for normalizes-to. // for normalizes-to.
let pred_kind = goal.goal().predicate.kind(); let pred_kind = goal.goal().predicate.kind();
let child_mode = match pred_kind.skip_binder() { let child_mode = match pred_kind.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(parent_trait_pred)) => { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
ChildMode::Trait(pred_kind.rebind(parent_trait_pred)) ChildMode::Trait(pred_kind.rebind(pred))
}
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => {
ChildMode::Host(pred_kind.rebind(pred))
} }
ty::PredicateKind::NormalizesTo(normalizes_to) ty::PredicateKind::NormalizesTo(normalizes_to)
if matches!( if matches!(
@ -521,7 +525,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
let obligation; let obligation;
match (child_mode, nested_goal.source()) { match (child_mode, nested_goal.source()) {
(ChildMode::Trait(_), GoalSource::Misc) => { (ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => {
continue; continue;
} }
(ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => { (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
@ -534,11 +538,25 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
)); ));
impl_where_bound_count += 1; impl_where_bound_count += 1;
} }
(
ChildMode::Host(parent_host_pred),
GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
) => {
obligation = make_obligation(derive_host_cause(
tcx,
candidate.kind(),
self.obligation.cause.clone(),
impl_where_bound_count,
parent_host_pred,
));
impl_where_bound_count += 1;
}
// Skip over a higher-ranked predicate. // Skip over a higher-ranked predicate.
(_, GoalSource::InstantiateHigherRanked) => { (_, GoalSource::InstantiateHigherRanked) => {
obligation = self.obligation.clone(); obligation = self.obligation.clone();
} }
(ChildMode::PassThrough, _) | (_, GoalSource::AliasWellFormed) => { (ChildMode::PassThrough, _)
| (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
obligation = make_obligation(self.obligation.cause.clone()); obligation = make_obligation(self.obligation.cause.clone());
} }
} }
@ -592,6 +610,10 @@ enum ChildMode<'tcx> {
// and skip all `GoalSource::Misc`, which represent useless obligations // and skip all `GoalSource::Misc`, which represent useless obligations
// such as alias-eq which may not hold. // such as alias-eq which may not hold.
Trait(ty::PolyTraitPredicate<'tcx>), Trait(ty::PolyTraitPredicate<'tcx>),
// Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
// and skip all `GoalSource::Misc`, which represent useless obligations
// such as alias-eq which may not hold.
Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
// Skip trying to derive an `ObligationCause` from this obligation, and // Skip trying to derive an `ObligationCause` from this obligation, and
// report *all* sub-obligations as if they came directly from the parent // report *all* sub-obligations as if they came directly from the parent
// obligation. // obligation.
@ -633,3 +655,52 @@ fn derive_cause<'tcx>(
}; };
cause cause
} }
fn derive_host_cause<'tcx>(
tcx: TyCtxt<'tcx>,
candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
mut cause: ObligationCause<'tcx>,
idx: usize,
parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
) -> ObligationCause<'tcx> {
match candidate_kind {
inspect::ProbeKind::TraitCandidate {
source: CandidateSource::Impl(impl_def_id),
result: _,
} => {
if let Some((_, span)) = tcx
.predicates_of(impl_def_id)
.instantiate_identity(tcx)
.into_iter()
.chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
|(trait_ref, span)| {
(
trait_ref.to_host_effect_clause(
tcx,
parent_host_pred.skip_binder().constness,
),
span,
)
},
))
.nth(idx)
{
cause =
cause.derived_host_cause(parent_host_pred, |derived| {
ObligationCauseCode::ImplDerivedHost(Box::new(
traits::ImplDerivedHostCause { derived, impl_def_id, span },
))
})
}
}
inspect::ProbeKind::TraitCandidate {
source: CandidateSource::BuiltinImpl(..),
result: _,
} => {
cause =
cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
}
_ => {}
};
cause
}

View file

@ -1,6 +1,8 @@
use rustc_hir as hir; use rustc_hir as hir;
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation}; use rustc_infer::traits::{
ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation,
};
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::{self, TypingMode}; use rustc_middle::ty::{self, TypingMode};
@ -248,9 +250,22 @@ fn evaluate_host_effect_from_selection_candiate<'tcx>(
tcx.const_conditions(impl_.impl_def_id) tcx.const_conditions(impl_.impl_def_id)
.instantiate(tcx, impl_.args) .instantiate(tcx, impl_.args)
.into_iter() .into_iter()
.map(|(trait_ref, _)| { .map(|(trait_ref, span)| {
obligation.with( Obligation::new(
tcx, tcx,
obligation.cause.clone().derived_host_cause(
ty::Binder::dummy(obligation.predicate),
|derived| {
ObligationCauseCode::ImplDerivedHost(Box::new(
ImplDerivedHostCause {
derived,
impl_def_id: impl_.impl_def_id,
span,
},
))
},
),
obligation.param_env,
trait_ref trait_ref
.to_host_effect_clause(tcx, obligation.predicate.constness), .to_host_effect_clause(tcx, obligation.predicate.constness),
) )

View file

@ -89,6 +89,7 @@ impl_binder_encode_decode! {
ty::ExistentialPredicate<I>, ty::ExistentialPredicate<I>,
ty::TraitRef<I>, ty::TraitRef<I>,
ty::ExistentialTraitRef<I>, ty::ExistentialTraitRef<I>,
ty::HostEffectPredicate<I>,
} }
impl<I: Interner, T> Binder<I, T> impl<I: Interner, T> Binder<I, T>

View file

@ -68,6 +68,10 @@ pub enum GoalSource {
/// FIXME(-Znext-solver=coinductive): Explain how and why this /// FIXME(-Znext-solver=coinductive): Explain how and why this
/// changes whether cycles are coinductive. /// changes whether cycles are coinductive.
ImplWhereBound, ImplWhereBound,
/// Const conditions that need to hold for `~const` alias bounds to hold.
///
/// FIXME(-Znext-solver=coinductive): Are these even coinductive?
AliasBoundConstCondition,
/// Instantiating a higher-ranked goal and re-proving it. /// Instantiating a higher-ranked goal and re-proving it.
InstantiateHigherRanked, InstantiateHigherRanked,
/// Predicate required for an alias projection to be well-formed. /// Predicate required for an alias projection to be well-formed.

View file

@ -11,12 +11,30 @@ error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{con
| |
LL | impl<T: ?Sized + ConstName> const ConstName for &T LL | impl<T: ?Sized + ConstName> const ConstName for &T
| ^^ cannot normalize `<&T as ConstName>::{constant#0}` | ^^ cannot normalize `<&T as ConstName>::{constant#0}`
|
note: required for `&T` to implement `~const ConstName`
--> $DIR/issue-88119.rs:19:35
|
LL | impl<T: ?Sized + ConstName> const ConstName for &T
| ^^^^^^^^^ ^^
LL | where
LL | [(); name_len::<T>()]:,
| --------------------- unsatisfied trait bound introduced here
error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}` error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}`
--> $DIR/issue-88119.rs:26:49 --> $DIR/issue-88119.rs:26:49
| |
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
| ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}` | ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}`
|
note: required for `&mut T` to implement `~const ConstName`
--> $DIR/issue-88119.rs:26:35
|
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
| ^^^^^^^^^ ^^^^^^
LL | where
LL | [(); name_len::<T>()]:,
| --------------------- unsatisfied trait bound introduced here
error: aborting due to 3 previous errors error: aborting due to 3 previous errors

View file

@ -5,7 +5,7 @@ LL | T::Assoc::<U>::func();
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error[E0277]: the trait bound `U: ~const Other` is not satisfied error[E0277]: the trait bound `U: ~const Other` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:27:5 --> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5
| |
LL | <T as Trait>::Assoc::<U>::func(); LL | <T as Trait>::Assoc::<U>::func();
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,11 +1,11 @@
error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied error[E0277]: the trait bound `U: ~const Other` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5 --> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5
| |
LL | T::Assoc::<U>::func(); LL | T::Assoc::<U>::func();
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied error[E0277]: the trait bound `U: ~const Other` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:27:5 --> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5
| |
LL | <T as Trait>::Assoc::<U>::func(); LL | <T as Trait>::Assoc::<U>::func();
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -22,11 +22,9 @@ trait Other {}
const fn fails<T: ~const Trait, U: Other>() { const fn fails<T: ~const Trait, U: Other>() {
T::Assoc::<U>::func(); T::Assoc::<U>::func();
//[current]~^ ERROR the trait bound `U: ~const Other` is not satisfied //~^ ERROR the trait bound `U: ~const Other` is not satisfied
//[next]~^^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
<T as Trait>::Assoc::<U>::func(); <T as Trait>::Assoc::<U>::func();
//[current]~^ ERROR the trait bound `U: ~const Other` is not satisfied //~^ ERROR the trait bound `U: ~const Other` is not satisfied
//[next]~^^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
} }
const fn works<T: ~const Trait, U: ~const Other>() { const fn works<T: ~const Trait, U: ~const Other>() {

View file

@ -16,6 +16,11 @@ error[E0277]: the trait bound `T: ~const Bar` is not satisfied
LL | type Assoc<T> = C<T> LL | type Assoc<T> = C<T>
| ^^^^ | ^^^^
| |
note: required for `C<T>` to implement `~const Bar`
--> $DIR/item-bound-entailment-fails.rs:14:15
|
LL | impl<T> const Bar for C<T> where T: ~const Bar {}
| ^^^ ^^^^ ------ unsatisfied trait bound introduced here
note: required by a bound in `Foo::Assoc` note: required by a bound in `Foo::Assoc`
--> $DIR/item-bound-entailment-fails.rs:5:20 --> $DIR/item-bound-entailment-fails.rs:5:20
| |