handle nested obligations in satisfied_from_param_env
This commit is contained in:
parent
5bb1a9febc
commit
8c729bd0f3
7 changed files with 126 additions and 45 deletions
|
@ -18,6 +18,8 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitor};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use crate::traits::ObligationCtxt;
|
||||||
|
|
||||||
/// Check if a given constant can be evaluated.
|
/// Check if a given constant can be evaluated.
|
||||||
#[instrument(skip(infcx), level = "debug")]
|
#[instrument(skip(infcx), level = "debug")]
|
||||||
pub fn is_const_evaluatable<'tcx>(
|
pub fn is_const_evaluatable<'tcx>(
|
||||||
|
@ -71,26 +73,27 @@ pub fn is_const_evaluatable<'tcx>(
|
||||||
// See #74595 for more details about this.
|
// See #74595 for more details about this.
|
||||||
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
||||||
match concrete {
|
match concrete {
|
||||||
// If we're evaluating a generic foreign constant, under a nightly compiler while
|
// If we're evaluating a generic foreign constant, under a nightly compiler while
|
||||||
// the current crate does not enable `feature(generic_const_exprs)`, abort
|
// the current crate does not enable `feature(generic_const_exprs)`, abort
|
||||||
// compilation with a useful error.
|
// compilation with a useful error.
|
||||||
Err(_) if tcx.sess.is_nightly_build()
|
Err(_) if tcx.sess.is_nightly_build()
|
||||||
&& let Ok(Some(ac)) = tcx.expand_abstract_consts(ct)
|
&& let Ok(Some(ac)) = tcx.expand_abstract_consts(ct)
|
||||||
&& let ty::ConstKind::Expr(_) = ac.kind() => {
|
&& let ty::ConstKind::Expr(_) = ac.kind() =>
|
||||||
tcx.sess
|
{
|
||||||
.struct_span_fatal(
|
tcx.sess
|
||||||
// Slightly better span than just using `span` alone
|
.struct_span_fatal(
|
||||||
if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
|
// Slightly better span than just using `span` alone
|
||||||
"failed to evaluate generic const expression",
|
if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
|
||||||
)
|
"failed to evaluate generic const expression",
|
||||||
.note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
|
)
|
||||||
.span_suggestion_verbose(
|
.note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
|
||||||
rustc_span::DUMMY_SP,
|
.span_suggestion_verbose(
|
||||||
"consider enabling this feature",
|
rustc_span::DUMMY_SP,
|
||||||
"#![feature(generic_const_exprs)]\n",
|
"consider enabling this feature",
|
||||||
rustc_errors::Applicability::MaybeIncorrect,
|
"#![feature(generic_const_exprs)]\n",
|
||||||
)
|
rustc_errors::Applicability::MaybeIncorrect,
|
||||||
.emit()
|
)
|
||||||
|
.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(ErrorHandled::TooGeneric) => {
|
Err(ErrorHandled::TooGeneric) => {
|
||||||
|
@ -130,12 +133,17 @@ fn satisfied_from_param_env<'tcx>(
|
||||||
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
||||||
type BreakTy = ();
|
type BreakTy = ();
|
||||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
if c.ty() == self.ct.ty()
|
if let Ok(()) = self.infcx.commit_if_ok(|_| {
|
||||||
&& let Ok(_nested_obligations) = self
|
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
|
||||||
.infcx
|
if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
|
||||||
.at(&ObligationCause::dummy(), self.param_env)
|
&& let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct)
|
||||||
.eq(c, self.ct)
|
&& ocx.select_all_or_error().is_empty()
|
||||||
{
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}) {
|
||||||
ControlFlow::BREAK
|
ControlFlow::BREAK
|
||||||
} else if let ty::ConstKind::Expr(e) = c.kind() {
|
} else if let ty::ConstKind::Expr(e) = c.kind() {
|
||||||
e.visit_with(self)
|
e.visit_with(self)
|
||||||
|
|
|
@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::obligation_forest::ProcessResult;
|
use rustc_data_structures::obligation_forest::ProcessResult;
|
||||||
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
|
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
|
||||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||||
use rustc_hir::def::DefKind;
|
|
||||||
use rustc_infer::traits::ProjectionCacheKey;
|
use rustc_infer::traits::ProjectionCacheKey;
|
||||||
use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation};
|
use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
|
@ -465,6 +464,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||||
// Let's just see where this breaks :shrug:
|
// Let's just see where this breaks :shrug:
|
||||||
match (c1.kind(), c2.kind()) {
|
match (c1.kind(), c2.kind()) {
|
||||||
(ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) => {
|
(ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) => {
|
||||||
|
// FIXME: remove
|
||||||
|
use rustc_hir::def::DefKind;
|
||||||
if tcx.def_kind(a.def.did) == DefKind::AssocConst
|
if tcx.def_kind(a.def.did) == DefKind::AssocConst
|
||||||
|| tcx.def_kind(b.def.did) == DefKind::AssocConst
|
|| tcx.def_kind(b.def.did) == DefKind::AssocConst
|
||||||
{
|
{
|
||||||
|
@ -477,16 +478,17 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let (Ok(Some(a)), Ok(Some(b))) = (
|
|
||||||
tcx.expand_abstract_consts(c1),
|
if let Ok(Some(a)) = tcx.expand_abstract_consts(c1)
|
||||||
tcx.expand_abstract_consts(c2),
|
&& let Ok(Some(b)) = tcx.expand_abstract_consts(c2)
|
||||||
) && a.ty() == b.ty() &&
|
&& a.ty() == b.ty()
|
||||||
let Ok(new_obligations) = infcx
|
&& let Ok(new_obligations) = infcx
|
||||||
.at(&obligation.cause, obligation.param_env)
|
.at(&obligation.cause, obligation.param_env)
|
||||||
.eq(a, b) {
|
.eq(a, b)
|
||||||
return ProcessResult::Changed(mk_pending(
|
{
|
||||||
new_obligations.into_obligations(),
|
return ProcessResult::Changed(mk_pending(
|
||||||
));
|
new_obligations.into_obligations(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#![feature(generic_const_exprs)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
const ASSOC: usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<T: Trait, U: Trait>() where [(); U::ASSOC]:, {
|
||||||
|
bar::<{ T::ASSOC }>();
|
||||||
|
//~^ ERROR: unconstrained generic constant
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar<const N: usize>() {}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
error: unconstrained generic constant
|
||||||
|
--> $DIR/doesnt_unify_evaluatable.rs:9:11
|
||||||
|
|
|
||||||
|
LL | bar::<{ T::ASSOC }>();
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: try adding a `where` bound using this expression: `where [(); { T::ASSOC }]:`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(generic_const_exprs)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
const ASSOC: usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<T: Trait, U: Trait>() where [(); T::ASSOC]:, {
|
||||||
|
bar::<{ T::ASSOC }>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar<const N: usize>() -> [(); N] {
|
||||||
|
[(); N]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -59,9 +59,11 @@ impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T,
|
||||||
assert!(DIM >= T::DIM);
|
assert!(DIM >= T::DIM);
|
||||||
if !self.inbounds(index) {
|
if !self.inbounds(index) {
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
|
//~^^ ERROR unconstrained generic constant
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let size = self.size();
|
let size = self.size();
|
||||||
|
//~^ ERROR unconstrained generic constant
|
||||||
let newindex: [usize; T::DIM] = Default::default();
|
let newindex: [usize; T::DIM] = Default::default();
|
||||||
//~^ ERROR the trait bound
|
//~^ ERROR the trait bound
|
||||||
self.reference.bget(newindex)
|
self.reference.bget(newindex)
|
||||||
|
|
|
@ -17,7 +17,7 @@ LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
|
||||||
found constant `DIM`
|
found constant `DIM`
|
||||||
|
|
||||||
error[E0308]: method not compatible with trait
|
error[E0308]: method not compatible with trait
|
||||||
--> $DIR/issue-83765.rs:84:5
|
--> $DIR/issue-83765.rs:86:5
|
||||||
|
|
|
|
||||||
LL | fn size(&self) -> [usize; DIM] {
|
LL | fn size(&self) -> [usize; DIM] {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
|
||||||
|
@ -26,7 +26,7 @@ LL | fn size(&self) -> [usize; DIM] {
|
||||||
found constant `DIM`
|
found constant `DIM`
|
||||||
|
|
||||||
error[E0308]: method not compatible with trait
|
error[E0308]: method not compatible with trait
|
||||||
--> $DIR/issue-83765.rs:96:5
|
--> $DIR/issue-83765.rs:98:5
|
||||||
|
|
|
|
||||||
LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
|
LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
|
||||||
|
@ -34,6 +34,19 @@ LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
|
||||||
= note: expected constant `Self::DIM`
|
= note: expected constant `Self::DIM`
|
||||||
found constant `DIM`
|
found constant `DIM`
|
||||||
|
|
||||||
|
error: unconstrained generic constant
|
||||||
|
--> $DIR/issue-83765.rs:60:18
|
||||||
|
|
|
||||||
|
LL | if !self.inbounds(index) {
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
|
||||||
|
note: required by a bound in `TensorSize::inbounds`
|
||||||
|
--> $DIR/issue-83765.rs:16:39
|
||||||
|
|
|
||||||
|
LL | fn inbounds(&self, index: [usize; Self::DIM]) -> bool {
|
||||||
|
| ^^^^^^^^^ required by this bound in `TensorSize::inbounds`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-83765.rs:60:27
|
--> $DIR/issue-83765.rs:60:27
|
||||||
|
|
|
|
||||||
|
@ -43,8 +56,21 @@ LL | if !self.inbounds(index) {
|
||||||
= note: expected constant `Self::DIM`
|
= note: expected constant `Self::DIM`
|
||||||
found constant `DIM`
|
found constant `DIM`
|
||||||
|
|
||||||
|
error: unconstrained generic constant
|
||||||
|
--> $DIR/issue-83765.rs:65:25
|
||||||
|
|
|
||||||
|
LL | let size = self.size();
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
|
||||||
|
note: required by a bound in `TensorSize::size`
|
||||||
|
--> $DIR/issue-83765.rs:15:31
|
||||||
|
|
|
||||||
|
LL | fn size(&self) -> [usize; Self::DIM];
|
||||||
|
| ^^^^^^^^^ required by this bound in `TensorSize::size`
|
||||||
|
|
||||||
error[E0277]: the trait bound `[usize; _]: Default` is not satisfied
|
error[E0277]: the trait bound `[usize; _]: Default` is not satisfied
|
||||||
--> $DIR/issue-83765.rs:65:41
|
--> $DIR/issue-83765.rs:67:41
|
||||||
|
|
|
|
||||||
LL | let newindex: [usize; T::DIM] = Default::default();
|
LL | let newindex: [usize; T::DIM] = Default::default();
|
||||||
| ^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; _]`
|
| ^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; _]`
|
||||||
|
@ -55,7 +81,7 @@ LL | impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a
|
||||||
| +++++++++++++++++++++++++
|
| +++++++++++++++++++++++++
|
||||||
|
|
||||||
error: unconstrained generic constant
|
error: unconstrained generic constant
|
||||||
--> $DIR/issue-83765.rs:86:24
|
--> $DIR/issue-83765.rs:88:24
|
||||||
|
|
|
|
||||||
LL | self.reference.size()
|
LL | self.reference.size()
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
@ -68,7 +94,7 @@ LL | fn size(&self) -> [usize; Self::DIM];
|
||||||
| ^^^^^^^^^ required by this bound in `TensorSize::size`
|
| ^^^^^^^^^ required by this bound in `TensorSize::size`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-83765.rs:86:9
|
--> $DIR/issue-83765.rs:88:9
|
||||||
|
|
|
|
||||||
LL | self.reference.size()
|
LL | self.reference.size()
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM`
|
| ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM`
|
||||||
|
@ -77,7 +103,7 @@ LL | self.reference.size()
|
||||||
found constant `Self::DIM`
|
found constant `Self::DIM`
|
||||||
|
|
||||||
error: unconstrained generic constant
|
error: unconstrained generic constant
|
||||||
--> $DIR/issue-83765.rs:98:24
|
--> $DIR/issue-83765.rs:100:24
|
||||||
|
|
|
|
||||||
LL | self.reference.bget(index).map(&self.closure)
|
LL | self.reference.bget(index).map(&self.closure)
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
@ -90,7 +116,7 @@ LL | fn bget(&self, index: [usize; Self::DIM]) -> Option<Self::Element>;
|
||||||
| ^^^^^^^^^ required by this bound in `Broadcastable::bget`
|
| ^^^^^^^^^ required by this bound in `Broadcastable::bget`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-83765.rs:98:29
|
--> $DIR/issue-83765.rs:100:29
|
||||||
|
|
|
|
||||||
LL | self.reference.bget(index).map(&self.closure)
|
LL | self.reference.bget(index).map(&self.closure)
|
||||||
| ^^^^^ expected `Self::DIM`, found `DIM`
|
| ^^^^^ expected `Self::DIM`, found `DIM`
|
||||||
|
@ -98,7 +124,7 @@ LL | self.reference.bget(index).map(&self.closure)
|
||||||
= note: expected constant `Self::DIM`
|
= note: expected constant `Self::DIM`
|
||||||
found constant `DIM`
|
found constant `DIM`
|
||||||
|
|
||||||
error: aborting due to 10 previous errors
|
error: aborting due to 12 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0308.
|
Some errors have detailed explanations: E0277, E0308.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue