Rollup merge of #142126 - compiler-errors:normalize-uv-via-relate, r=BoxyUwU
Treat normalizing consts like normalizing types in deeply normalize ...so that we don't end up putting a top-level normalizes-to goal in the fulfillment context, which ICEs. This basically just models the normalize-const code off of the normalize-ty code above it, which uses an alias-relate goal instead. Fixes rust-lang/rust#140571 r? lcnr
This commit is contained in:
@@ -823,6 +823,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
ty::Region::new_var(self.tcx, region_var)
|
||||
}
|
||||
|
||||
pub fn next_term_var_of_kind(&self, term: ty::Term<'tcx>, span: Span) -> ty::Term<'tcx> {
|
||||
match term.kind() {
|
||||
ty::TermKind::Ty(_) => self.next_ty_var(span).into(),
|
||||
ty::TermKind::Const(_) => self.next_const_var(span).into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the universe that the region `r` was created in. For
|
||||
/// most regions (e.g., `'static`, named regions from the user,
|
||||
/// etc) this is the root universe U0. For inference variables or
|
||||
|
||||
@@ -231,10 +231,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
||||
let infcx = self.goal.infcx;
|
||||
match goal.predicate.kind().no_bound_vars() {
|
||||
Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
|
||||
let unconstrained_term = match term.kind() {
|
||||
ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(),
|
||||
ty::TermKind::Const(_) => infcx.next_const_var(span).into(),
|
||||
};
|
||||
let unconstrained_term = infcx.next_term_var_of_kind(term, span);
|
||||
let goal =
|
||||
goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
|
||||
// We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
@@ -16,7 +15,6 @@ use tracing::instrument;
|
||||
use super::{FulfillmentCtxt, NextSolverError};
|
||||
use crate::error_reporting::InferCtxtErrorExt;
|
||||
use crate::error_reporting::traits::OverflowCause;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
|
||||
|
||||
/// Deeply normalize all aliases in `value`. This does not handle inference and expects
|
||||
@@ -97,19 +95,18 @@ impl<'tcx, E> NormalizationFolder<'_, 'tcx, E>
|
||||
where
|
||||
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
|
||||
{
|
||||
fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result<Ty<'tcx>, Vec<E>> {
|
||||
assert_matches!(alias_ty.kind(), ty::Alias(..));
|
||||
|
||||
fn normalize_alias_term(
|
||||
&mut self,
|
||||
alias_term: ty::Term<'tcx>,
|
||||
) -> Result<ty::Term<'tcx>, Vec<E>> {
|
||||
let infcx = self.at.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
let recursion_limit = tcx.recursion_limit();
|
||||
if !recursion_limit.value_within_limit(self.depth) {
|
||||
let ty::Alias(_, data) = *alias_ty.kind() else {
|
||||
unreachable!();
|
||||
};
|
||||
let term = alias_term.to_alias_term().unwrap();
|
||||
|
||||
self.at.infcx.err_ctxt().report_overflow_error(
|
||||
OverflowCause::DeeplyNormalize(data.into()),
|
||||
OverflowCause::DeeplyNormalize(term),
|
||||
self.at.cause.span,
|
||||
true,
|
||||
|_| {},
|
||||
@@ -118,14 +115,14 @@ where
|
||||
|
||||
self.depth += 1;
|
||||
|
||||
let new_infer_ty = infcx.next_ty_var(self.at.cause.span);
|
||||
let infer_term = infcx.next_term_var_of_kind(alias_term, self.at.cause.span);
|
||||
let obligation = Obligation::new(
|
||||
tcx,
|
||||
self.at.cause.clone(),
|
||||
self.at.param_env,
|
||||
ty::PredicateKind::AliasRelate(
|
||||
alias_ty.into(),
|
||||
new_infer_ty.into(),
|
||||
alias_term.into(),
|
||||
infer_term.into(),
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
);
|
||||
@@ -135,50 +132,13 @@ where
|
||||
|
||||
// Alias is guaranteed to be fully structurally resolved,
|
||||
// so we can super fold here.
|
||||
let ty = infcx.resolve_vars_if_possible(new_infer_ty);
|
||||
let result = ty.try_super_fold_with(self)?;
|
||||
self.depth -= 1;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn normalize_unevaluated_const(
|
||||
&mut self,
|
||||
uv: ty::UnevaluatedConst<'tcx>,
|
||||
) -> Result<ty::Const<'tcx>, Vec<E>> {
|
||||
let infcx = self.at.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
let recursion_limit = tcx.recursion_limit();
|
||||
if !recursion_limit.value_within_limit(self.depth) {
|
||||
self.at.infcx.err_ctxt().report_overflow_error(
|
||||
OverflowCause::DeeplyNormalize(uv.into()),
|
||||
self.at.cause.span,
|
||||
true,
|
||||
|_| {},
|
||||
);
|
||||
}
|
||||
|
||||
self.depth += 1;
|
||||
|
||||
let new_infer_ct = infcx.next_const_var(self.at.cause.span);
|
||||
let obligation = Obligation::new(
|
||||
tcx,
|
||||
self.at.cause.clone(),
|
||||
self.at.param_env,
|
||||
ty::NormalizesTo { alias: uv.into(), term: new_infer_ct.into() },
|
||||
);
|
||||
|
||||
let result = if infcx.predicate_may_hold(&obligation) {
|
||||
self.fulfill_cx.register_predicate_obligation(infcx, obligation);
|
||||
let errors = self.fulfill_cx.select_where_possible(infcx);
|
||||
if !errors.is_empty() {
|
||||
return Err(errors);
|
||||
}
|
||||
let ct = infcx.resolve_vars_if_possible(new_infer_ct);
|
||||
ct.try_fold_with(self)?
|
||||
} else {
|
||||
ty::Const::new_unevaluated(tcx, uv).try_super_fold_with(self)?
|
||||
let term = infcx.resolve_vars_if_possible(infer_term);
|
||||
// super-folding the `term` will directly fold the `Ty` or `Const` so
|
||||
// we have to match on the term and super-fold them manually.
|
||||
let result = match term.kind() {
|
||||
ty::TermKind::Ty(ty) => ty.try_super_fold_with(self)?.into(),
|
||||
ty::TermKind::Const(ct) => ct.try_super_fold_with(self)?.into(),
|
||||
};
|
||||
|
||||
self.depth -= 1;
|
||||
Ok(result)
|
||||
}
|
||||
@@ -238,7 +198,8 @@ where
|
||||
if ty.has_escaping_bound_vars() {
|
||||
let (ty, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty);
|
||||
let result = ensure_sufficient_stack(|| self.normalize_alias_ty(ty))?;
|
||||
let result =
|
||||
ensure_sufficient_stack(|| self.normalize_alias_term(ty.into()))?.expect_type();
|
||||
Ok(PlaceholderReplacer::replace_placeholders(
|
||||
infcx,
|
||||
mapped_regions,
|
||||
@@ -248,7 +209,7 @@ where
|
||||
result,
|
||||
))
|
||||
} else {
|
||||
ensure_sufficient_stack(|| self.normalize_alias_ty(ty))
|
||||
Ok(ensure_sufficient_stack(|| self.normalize_alias_term(ty.into()))?.expect_type())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,15 +221,13 @@ where
|
||||
return Ok(ct);
|
||||
}
|
||||
|
||||
let uv = match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(ct) => ct,
|
||||
_ => return ct.try_super_fold_with(self),
|
||||
};
|
||||
let ty::ConstKind::Unevaluated(..) = ct.kind() else { return ct.try_super_fold_with(self) };
|
||||
|
||||
if uv.has_escaping_bound_vars() {
|
||||
let (uv, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv);
|
||||
let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv))?;
|
||||
if ct.has_escaping_bound_vars() {
|
||||
let (ct, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ct);
|
||||
let result =
|
||||
ensure_sufficient_stack(|| self.normalize_alias_term(ct.into()))?.expect_const();
|
||||
Ok(PlaceholderReplacer::replace_placeholders(
|
||||
infcx,
|
||||
mapped_regions,
|
||||
@@ -278,7 +237,7 @@ where
|
||||
result,
|
||||
))
|
||||
} else {
|
||||
ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv))
|
||||
Ok(ensure_sufficient_stack(|| self.normalize_alias_term(ct.into()))?.expect_const())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,7 @@ impl<'tcx> At<'_, 'tcx> {
|
||||
return Ok(term);
|
||||
}
|
||||
|
||||
let new_infer = match term.kind() {
|
||||
ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(),
|
||||
ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(),
|
||||
};
|
||||
let new_infer = self.infcx.next_term_var_of_kind(term, self.cause.span);
|
||||
|
||||
// We simply emit an `alias-eq` goal here, since that will take care of
|
||||
// normalizing the LHS of the projection until it is a rigid projection
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
//@ known-bug: #140571
|
||||
// Regression test for #140571. The compiler used to ICE
|
||||
|
||||
#![feature(associated_const_equality, specialization)]
|
||||
//~^ WARN the feature `specialization` is incomplete
|
||||
|
||||
pub trait IsVoid {
|
||||
const IS_VOID: bool;
|
||||
}
|
||||
impl<T> IsVoid for T {
|
||||
default const IS_VOID: bool = false;
|
||||
}
|
||||
impl<T> Maybe<T> for () where T: NotVoid + ?Sized {}
|
||||
|
||||
pub trait NotVoid {}
|
||||
impl<T> NotVoid for T where T: IsVoid<IS_VOID = false> + ?Sized {}
|
||||
|
||||
pub trait Maybe<T> {}
|
||||
impl<T> Maybe<T> for T {}
|
||||
impl<T> Maybe<T> for () where T: NotVoid + ?Sized {}
|
||||
//~^ ERROR conflicting implementations of trait `Maybe<()>` for type `()`
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,21 @@
|
||||
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:39
|
||||
|
|
||||
LL | #![feature(associated_const_equality, specialization)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
|
||||
= help: consider using `min_specialization` instead, which is more stable and complete
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0119]: conflicting implementations of trait `Maybe<()>` for type `()`
|
||||
--> $DIR/overlap-due-to-unsatisfied-const-bound.rs:18:1
|
||||
|
|
||||
LL | impl<T> Maybe<T> for T {}
|
||||
| ---------------------- first implementation here
|
||||
LL | impl<T> Maybe<T> for () where T: NotVoid + ?Sized {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
||||
Reference in New Issue
Block a user