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::Alias(_, _) | 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::Alias(_, ty::AliasConst {
kind: ty::AliasConstKind::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::Alias(_, _) => {
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 alias_const =
match unexpanded_ct.kind() {
ty::ConstKind::Alias(_, alias_const) => alias_const,
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 {
alias_const.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 alias_const.has_non_region_infer() {
NotConstEvaluatable::MentionsInfer
} else if alias_const.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::Alias(_, _) | 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::Alias(_, ty::AliasConst { kind: ty::AliasConstKind::Anon { .. }, .. })
48 );
49
50 if !is_anon_ct {
51 if satisfied_from_param_env(tcx, infcx, ct, param_env) {
52 return Ok(());
53 }
54 if ct.has_non_region_infer() {
55 return Err(NotConstEvaluatable::MentionsInfer);
56 } else if ct.has_non_region_param() {
57 return Err(NotConstEvaluatable::MentionsParam);
58 }
59 }
60
61 match unexpanded_ct.kind() {
62 ty::ConstKind::Expr(_) => {
63 tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported");
68 }
69 ty::ConstKind::Alias(_, _) => {
70 match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
71 Err(EvaluateConstErr::HasGenericsOrInfers) => {
72 Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug(
73 span,
74 "Missing value for constant, but no error reported?",
75 )))
76 }
77 Err(
78 EvaluateConstErr::EvaluationFailure(e)
79 | EvaluateConstErr::InvalidConstParamTy(e),
80 ) => Err(NotConstEvaluatable::Error(e)),
81 Ok(_) => Ok(()),
82 }
83 }
84 _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
85 }
86 } else if tcx.features().min_generic_const_args() {
87 crate::traits::evaluate_const(infcx, unexpanded_ct, param_env);
91 Ok(())
92 } else {
93 let alias_const = match unexpanded_ct.kind() {
94 ty::ConstKind::Alias(_, alias_const) => alias_const,
95 ty::ConstKind::Expr(_) => {
96 bug!("`ConstKind::Expr` without `feature(generic_const_exprs)` enabled")
97 }
98 _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
99 };
100
101 match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
102 Err(_)
106 if tcx.sess.is_nightly_build()
107 && satisfied_from_param_env(
108 tcx,
109 infcx,
110 tcx.expand_abstract_consts(unexpanded_ct),
111 param_env,
112 ) =>
113 {
114 tcx.dcx()
115 .struct_span_fatal(
116 if span == DUMMY_SP { alias_const.kind.def_span(tcx) } else { span },
118 "failed to evaluate generic const expression",
119 )
120 .with_note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
121 .with_span_suggestion_verbose(
122 DUMMY_SP,
123 "consider enabling this feature",
124 "#![feature(generic_const_exprs)]\n",
125 rustc_errors::Applicability::MaybeIncorrect,
126 )
127 .emit()
128 }
129
130 Err(EvaluateConstErr::HasGenericsOrInfers) => {
131 let err = if alias_const.has_non_region_infer() {
132 NotConstEvaluatable::MentionsInfer
133 } else if alias_const.has_non_region_param() {
134 NotConstEvaluatable::MentionsParam
135 } else {
136 let guar = infcx.dcx().span_delayed_bug(
137 span,
138 "Missing value for constant, but no error reported?",
139 );
140 NotConstEvaluatable::Error(guar)
141 };
142
143 Err(err)
144 }
145 Err(
146 EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e),
147 ) => Err(NotConstEvaluatable::Error(e)),
148 Ok(_) => Ok(()),
149 }
150 }
151}
152
153#[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(153u32),
::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:173",
"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(173u32),
::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 clause in param_env.caller_bounds() {
match clause.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:222",
"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(222u32),
::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")]
154fn satisfied_from_param_env<'tcx>(
155 tcx: TyCtxt<'tcx>,
156 infcx: &InferCtxt<'tcx>,
157 ct: ty::Const<'tcx>,
158 param_env: ty::ParamEnv<'tcx>,
159) -> bool {
160 struct Visitor<'a, 'tcx> {
164 ct: ty::Const<'tcx>,
165 param_env: ty::ParamEnv<'tcx>,
166
167 infcx: &'a InferCtxt<'tcx>,
168 single_match: Option<Result<ty::Const<'tcx>, ()>>,
169 }
170
171 impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'a, 'tcx> {
172 fn visit_const(&mut self, c: ty::Const<'tcx>) {
173 debug!("is_const_evaluatable: candidate={:?}", c);
174 if self.infcx.probe(|_| {
175 let ocx = ObligationCtxt::new(self.infcx);
176 ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok()
177 && ocx.evaluate_obligations_error_on_ambiguity().is_empty()
178 }) {
179 self.single_match = match self.single_match {
180 None => Some(Ok(c)),
181 Some(Ok(o)) if o == c => Some(Ok(c)),
182 Some(_) => Some(Err(())),
183 };
184 }
185
186 if let ty::ConstKind::Expr(e) = c.kind() {
187 e.visit_with(self);
188 } else {
189 }
197 }
198 }
199
200 let mut single_match: Option<Result<ty::Const<'tcx>, ()>> = None;
201
202 for clause in param_env.caller_bounds() {
203 match clause.kind().skip_binder() {
204 ty::ClauseKind::ConstEvaluatable(ce) => {
205 let b_ct = tcx.expand_abstract_consts(ce);
206 let mut v = Visitor { ct, infcx, param_env, single_match };
207 let _ = b_ct.visit_with(&mut v);
208
209 single_match = v.single_match;
210 }
211 _ => {} }
213 }
214
215 if let Some(Ok(c)) = single_match {
216 let ocx = ObligationCtxt::new(infcx);
217 assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok());
218 assert!(ocx.evaluate_obligations_error_on_ambiguity().is_empty());
219 return true;
220 }
221
222 debug!("is_const_evaluatable: no");
223 false
224}