1use rustc_infer::infer::InferCtxt;
13use rustc_middle::bug;
14use rustc_middle::traits::ObligationCause;
15use rustc_middle::ty::abstract_const::NotConstEvaluatable;
16use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor};
17use rustc_span::{DUMMY_SP, Span};
18use tracing::{debug, instrument};
19
20use super::EvaluateConstErr;
21use crate::traits::ObligationCtxt;
22
23#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("is_const_evaluatable",
"rustc_trait_selection::traits::const_evaluatable",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"),
::tracing_core::__macro_support::Option::Some(24u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::const_evaluatable"),
::tracing_core::field::FieldSet::new(&["unexpanded_ct",
"param_env", "span"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&unexpanded_ct)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(¶m_env)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&span)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Result<(), NotConstEvaluatable> =
loop {};
return __tracing_attr_fake_return;
}
{
let tcx = infcx.tcx;
match tcx.expand_abstract_consts(unexpanded_ct).kind() {
ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) => (),
ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) |
ty::ConstKind::Placeholder(_) | ty::ConstKind::Value(_) |
ty::ConstKind::Error(_) => return Ok(()),
ty::ConstKind::Infer(_) =>
return Err(NotConstEvaluatable::MentionsInfer),
};
if tcx.features().generic_const_exprs() {
let ct = tcx.expand_abstract_consts(unexpanded_ct);
let is_anon_ct =
#[allow(non_exhaustive_omitted_patterns)] match ct.kind() {
ty::ConstKind::Unevaluated(ty::UnevaluatedConst {
kind: ty::UnevaluatedConstKind::Anon { .. }, .. }) => true,
_ => false,
};
if !is_anon_ct {
if satisfied_from_param_env(tcx, infcx, ct, param_env) {
return Ok(());
}
if ct.has_non_region_infer() {
return Err(NotConstEvaluatable::MentionsInfer);
} else if ct.has_non_region_param() {
return Err(NotConstEvaluatable::MentionsParam);
}
}
match unexpanded_ct.kind() {
ty::ConstKind::Expr(_) => {
tcx.dcx().span_bug(span,
"evaluating `ConstKind::Expr` is not currently supported");
}
ty::ConstKind::Unevaluated(_) => {
match crate::traits::try_evaluate_const(infcx,
unexpanded_ct, param_env) {
Err(EvaluateConstErr::HasGenericsOrInfers) => {
Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug(span,
"Missing value for constant, but no error reported?")))
}
Err(EvaluateConstErr::EvaluationFailure(e) |
EvaluateConstErr::InvalidConstParamTy(e)) =>
Err(NotConstEvaluatable::Error(e)),
Ok(_) => Ok(()),
}
}
_ =>
::rustc_middle::util::bug::bug_fmt(format_args!("unexpected constkind in `is_const_evalautable: {0:?}`",
unexpanded_ct)),
}
} else if tcx.features().min_generic_const_args() {
crate::traits::evaluate_const(infcx, unexpanded_ct,
param_env);
Ok(())
} else {
let uv =
match unexpanded_ct.kind() {
ty::ConstKind::Unevaluated(uv) => uv,
ty::ConstKind::Expr(_) => {
::rustc_middle::util::bug::bug_fmt(format_args!("`ConstKind::Expr` without `feature(generic_const_exprs)` enabled"))
}
_ =>
::rustc_middle::util::bug::bug_fmt(format_args!("unexpected constkind in `is_const_evalautable: {0:?}`",
unexpanded_ct)),
};
match crate::traits::try_evaluate_const(infcx, unexpanded_ct,
param_env) {
Err(_) if
tcx.sess.is_nightly_build() &&
satisfied_from_param_env(tcx, infcx,
tcx.expand_abstract_consts(unexpanded_ct), param_env) => {
tcx.dcx().struct_span_fatal(if span == DUMMY_SP {
uv.kind.def_span(tcx)
} else { span },
"failed to evaluate generic const expression").with_note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`").with_span_suggestion_verbose(DUMMY_SP,
"consider enabling this feature",
"#![feature(generic_const_exprs)]\n",
rustc_errors::Applicability::MaybeIncorrect).emit()
}
Err(EvaluateConstErr::HasGenericsOrInfers) => {
let err =
if uv.has_non_region_infer() {
NotConstEvaluatable::MentionsInfer
} else if uv.has_non_region_param() {
NotConstEvaluatable::MentionsParam
} else {
let guar =
infcx.dcx().span_delayed_bug(span,
"Missing value for constant, but no error reported?");
NotConstEvaluatable::Error(guar)
};
Err(err)
}
Err(EvaluateConstErr::EvaluationFailure(e) |
EvaluateConstErr::InvalidConstParamTy(e)) =>
Err(NotConstEvaluatable::Error(e)),
Ok(_) => Ok(()),
}
}
}
}
}#[instrument(skip(infcx), level = "debug")]
25pub fn is_const_evaluatable<'tcx>(
26 infcx: &InferCtxt<'tcx>,
27 unexpanded_ct: ty::Const<'tcx>,
28 param_env: ty::ParamEnv<'tcx>,
29 span: Span,
30) -> Result<(), NotConstEvaluatable> {
31 let tcx = infcx.tcx;
32 match tcx.expand_abstract_consts(unexpanded_ct).kind() {
33 ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) => (),
34 ty::ConstKind::Param(_)
35 | ty::ConstKind::Bound(_, _)
36 | ty::ConstKind::Placeholder(_)
37 | ty::ConstKind::Value(_)
38 | ty::ConstKind::Error(_) => return Ok(()),
39 ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
40 };
41
42 if tcx.features().generic_const_exprs() {
43 let ct = tcx.expand_abstract_consts(unexpanded_ct);
44
45 let is_anon_ct = matches!(
46 ct.kind(),
47 ty::ConstKind::Unevaluated(ty::UnevaluatedConst {
48 kind: ty::UnevaluatedConstKind::Anon { .. },
49 ..
50 })
51 );
52
53 if !is_anon_ct {
54 if satisfied_from_param_env(tcx, infcx, ct, param_env) {
55 return Ok(());
56 }
57 if ct.has_non_region_infer() {
58 return Err(NotConstEvaluatable::MentionsInfer);
59 } else if ct.has_non_region_param() {
60 return Err(NotConstEvaluatable::MentionsParam);
61 }
62 }
63
64 match unexpanded_ct.kind() {
65 ty::ConstKind::Expr(_) => {
66 tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported");
71 }
72 ty::ConstKind::Unevaluated(_) => {
73 match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
74 Err(EvaluateConstErr::HasGenericsOrInfers) => {
75 Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug(
76 span,
77 "Missing value for constant, but no error reported?",
78 )))
79 }
80 Err(
81 EvaluateConstErr::EvaluationFailure(e)
82 | EvaluateConstErr::InvalidConstParamTy(e),
83 ) => Err(NotConstEvaluatable::Error(e)),
84 Ok(_) => Ok(()),
85 }
86 }
87 _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
88 }
89 } else if tcx.features().min_generic_const_args() {
90 crate::traits::evaluate_const(infcx, unexpanded_ct, param_env);
94 Ok(())
95 } else {
96 let uv = match unexpanded_ct.kind() {
97 ty::ConstKind::Unevaluated(uv) => uv,
98 ty::ConstKind::Expr(_) => {
99 bug!("`ConstKind::Expr` without `feature(generic_const_exprs)` enabled")
100 }
101 _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
102 };
103
104 match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
105 Err(_)
109 if tcx.sess.is_nightly_build()
110 && satisfied_from_param_env(
111 tcx,
112 infcx,
113 tcx.expand_abstract_consts(unexpanded_ct),
114 param_env,
115 ) =>
116 {
117 tcx.dcx()
118 .struct_span_fatal(
119 if span == DUMMY_SP { uv.kind.def_span(tcx) } else { span },
121 "failed to evaluate generic const expression",
122 )
123 .with_note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
124 .with_span_suggestion_verbose(
125 DUMMY_SP,
126 "consider enabling this feature",
127 "#![feature(generic_const_exprs)]\n",
128 rustc_errors::Applicability::MaybeIncorrect,
129 )
130 .emit()
131 }
132
133 Err(EvaluateConstErr::HasGenericsOrInfers) => {
134 let err = if uv.has_non_region_infer() {
135 NotConstEvaluatable::MentionsInfer
136 } else if uv.has_non_region_param() {
137 NotConstEvaluatable::MentionsParam
138 } else {
139 let guar = infcx.dcx().span_delayed_bug(
140 span,
141 "Missing value for constant, but no error reported?",
142 );
143 NotConstEvaluatable::Error(guar)
144 };
145
146 Err(err)
147 }
148 Err(
149 EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e),
150 ) => Err(NotConstEvaluatable::Error(e)),
151 Ok(_) => Ok(()),
152 }
153 }
154}
155
156#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("satisfied_from_param_env",
"rustc_trait_selection::traits::const_evaluatable",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"),
::tracing_core::__macro_support::Option::Some(156u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::const_evaluatable"),
::tracing_core::field::FieldSet::new(&["ct", "param_env"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ct)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(¶m_env)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: bool = loop {};
return __tracing_attr_fake_return;
}
{
struct Visitor<'a, 'tcx> {
ct: ty::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>,
infcx: &'a InferCtxt<'tcx>,
single_match: Option<Result<ty::Const<'tcx>, ()>>,
}
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'a, 'tcx> {
fn visit_const(&mut self, c: ty::Const<'tcx>) {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/const_evaluatable.rs:176",
"rustc_trait_selection::traits::const_evaluatable",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"),
::tracing_core::__macro_support::Option::Some(176u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::const_evaluatable"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("is_const_evaluatable: candidate={0:?}",
c) as &dyn Value))])
});
} else { ; }
};
if self.infcx.probe(|_|
{
let ocx = ObligationCtxt::new(self.infcx);
ocx.eq(&ObligationCause::dummy(), self.param_env, c,
self.ct).is_ok() &&
ocx.evaluate_obligations_error_on_ambiguity().is_empty()
}) {
self.single_match =
match self.single_match {
None => Some(Ok(c)),
Some(Ok(o)) if o == c => Some(Ok(c)),
Some(_) => Some(Err(())),
};
}
if let ty::ConstKind::Expr(e) = c.kind() {
e.visit_with(self);
} else {}
}
}
let mut single_match: Option<Result<ty::Const<'tcx>, ()>> = None;
for pred in param_env.caller_bounds() {
match pred.kind().skip_binder() {
ty::ClauseKind::ConstEvaluatable(ce) => {
let b_ct = tcx.expand_abstract_consts(ce);
let mut v = Visitor { ct, infcx, param_env, single_match };
let _ = b_ct.visit_with(&mut v);
single_match = v.single_match;
}
_ => {}
}
}
if let Some(Ok(c)) = single_match {
let ocx = ObligationCtxt::new(infcx);
if !ocx.eq(&ObligationCause::dummy(), param_env, c,
ct).is_ok() {
::core::panicking::panic("assertion failed: ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok()")
};
if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() {
::core::panicking::panic("assertion failed: ocx.evaluate_obligations_error_on_ambiguity().is_empty()")
};
return true;
}
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/const_evaluatable.rs:225",
"rustc_trait_selection::traits::const_evaluatable",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"),
::tracing_core::__macro_support::Option::Some(225u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::const_evaluatable"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("is_const_evaluatable: no")
as &dyn Value))])
});
} else { ; }
};
false
}
}
}#[instrument(skip(infcx, tcx), level = "debug")]
157fn satisfied_from_param_env<'tcx>(
158 tcx: TyCtxt<'tcx>,
159 infcx: &InferCtxt<'tcx>,
160 ct: ty::Const<'tcx>,
161 param_env: ty::ParamEnv<'tcx>,
162) -> bool {
163 struct Visitor<'a, 'tcx> {
167 ct: ty::Const<'tcx>,
168 param_env: ty::ParamEnv<'tcx>,
169
170 infcx: &'a InferCtxt<'tcx>,
171 single_match: Option<Result<ty::Const<'tcx>, ()>>,
172 }
173
174 impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'a, 'tcx> {
175 fn visit_const(&mut self, c: ty::Const<'tcx>) {
176 debug!("is_const_evaluatable: candidate={:?}", c);
177 if self.infcx.probe(|_| {
178 let ocx = ObligationCtxt::new(self.infcx);
179 ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok()
180 && ocx.evaluate_obligations_error_on_ambiguity().is_empty()
181 }) {
182 self.single_match = match self.single_match {
183 None => Some(Ok(c)),
184 Some(Ok(o)) if o == c => Some(Ok(c)),
185 Some(_) => Some(Err(())),
186 };
187 }
188
189 if let ty::ConstKind::Expr(e) = c.kind() {
190 e.visit_with(self);
191 } else {
192 }
200 }
201 }
202
203 let mut single_match: Option<Result<ty::Const<'tcx>, ()>> = None;
204
205 for pred in param_env.caller_bounds() {
206 match pred.kind().skip_binder() {
207 ty::ClauseKind::ConstEvaluatable(ce) => {
208 let b_ct = tcx.expand_abstract_consts(ce);
209 let mut v = Visitor { ct, infcx, param_env, single_match };
210 let _ = b_ct.visit_with(&mut v);
211
212 single_match = v.single_match;
213 }
214 _ => {} }
216 }
217
218 if let Some(Ok(c)) = single_match {
219 let ocx = ObligationCtxt::new(infcx);
220 assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok());
221 assert!(ocx.evaluate_obligations_error_on_ambiguity().is_empty());
222 return true;
223 }
224
225 debug!("is_const_evaluatable: no");
226 false
227}