Check const_eval_select intrinsic correctly
This commit is contained in:
parent
69f360d00c
commit
faea6ad579
@ -471,6 +471,65 @@ fn confirm_builtin_call(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(def_id) = def_id
|
||||
&& self.tcx.def_kind(def_id) == hir::def::DefKind::Fn
|
||||
&& self.tcx.is_intrinsic(def_id)
|
||||
&& self.tcx.item_name(def_id) == sym::const_eval_select
|
||||
{
|
||||
let fn_sig = self.resolve_vars_if_possible(fn_sig);
|
||||
for idx in 0..=1 {
|
||||
let arg_ty = fn_sig.inputs()[idx + 1];
|
||||
let span = arg_exprs.get(idx + 1).map_or(call_expr.span, |arg| arg.span);
|
||||
// Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that
|
||||
// the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed
|
||||
// in the function signature (`F: FnOnce<ARG>`), so I did not bother to add another check here.
|
||||
//
|
||||
// This check is here because there is currently no way to express a trait bound for `FnDef` types only.
|
||||
if let ty::FnDef(def_id, _args) = *arg_ty.kind() {
|
||||
let fn_once_def_id =
|
||||
self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span));
|
||||
let fn_once_output_def_id =
|
||||
self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span));
|
||||
if self.tcx.generics_of(fn_once_def_id).host_effect_index.is_none() {
|
||||
if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
|
||||
self.tcx.sess.emit_err(errors::ConstSelectMustBeConst { span });
|
||||
}
|
||||
} else {
|
||||
let const_param: ty::GenericArg<'tcx> =
|
||||
([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into();
|
||||
self.register_predicate(traits::Obligation::new(
|
||||
self.tcx,
|
||||
self.misc(span),
|
||||
self.param_env,
|
||||
ty::TraitRef::new(
|
||||
self.tcx,
|
||||
fn_once_def_id,
|
||||
[arg_ty.into(), fn_sig.inputs()[0].into(), const_param],
|
||||
),
|
||||
));
|
||||
|
||||
self.register_predicate(traits::Obligation::new(
|
||||
self.tcx,
|
||||
self.misc(span),
|
||||
self.param_env,
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: ty::AliasTy::new(
|
||||
self.tcx,
|
||||
fn_once_output_def_id,
|
||||
[arg_ty.into(), fn_sig.inputs()[0].into(), const_param],
|
||||
),
|
||||
term: fn_sig.output().into(),
|
||||
},
|
||||
));
|
||||
|
||||
self.select_obligations_where_possible(|_| {});
|
||||
}
|
||||
} else {
|
||||
self.tcx.sess.emit_err(errors::ConstSelectMustBeFn { span, ty: arg_ty });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn_sig.output()
|
||||
}
|
||||
|
||||
|
@ -230,11 +230,6 @@ pub(in super::super) fn check_argument_types(
|
||||
let minimum_input_count = expected_input_tys.len();
|
||||
let provided_arg_count = provided_args.len();
|
||||
|
||||
let is_const_eval_select = matches!(fn_def_id, Some(def_id) if
|
||||
self.tcx.def_kind(def_id) == hir::def::DefKind::Fn
|
||||
&& self.tcx.is_intrinsic(def_id)
|
||||
&& self.tcx.item_name(def_id) == sym::const_eval_select);
|
||||
|
||||
// We introduce a helper function to demand that a given argument satisfy a given input
|
||||
// This is more complicated than just checking type equality, as arguments could be coerced
|
||||
// This version writes those types back so further type checking uses the narrowed types
|
||||
@ -269,30 +264,6 @@ pub(in super::super) fn check_argument_types(
|
||||
return Compatibility::Incompatible(coerce_error);
|
||||
}
|
||||
|
||||
// Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that
|
||||
// the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed
|
||||
// in the function signature (`F: FnOnce<ARG>`), so I did not bother to add another check here.
|
||||
//
|
||||
// This check is here because there is currently no way to express a trait bound for `FnDef` types only.
|
||||
if is_const_eval_select && (1..=2).contains(&idx) {
|
||||
if let ty::FnDef(def_id, args) = *checked_ty.kind() {
|
||||
if idx == 1 {
|
||||
if !self.tcx.is_const_fn_raw(def_id) {
|
||||
self.tcx.sess.emit_err(errors::ConstSelectMustBeConst {
|
||||
span: provided_arg.span,
|
||||
});
|
||||
} else {
|
||||
self.enforce_context_effects(provided_arg.span, def_id, args)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.tcx.sess.emit_err(errors::ConstSelectMustBeFn {
|
||||
span: provided_arg.span,
|
||||
ty: checked_ty,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Check if the formal type is a supertype of the checked one
|
||||
// and register any such obligations for future type checks
|
||||
let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
|
||||
|
@ -16,15 +16,6 @@ LL | const_eval_select((), || {}, || {});
|
||||
= note: expected a function item, found {closure@$DIR/const-eval-select-bad.rs:7:34: 7:36}
|
||||
= help: consult the documentation on `const_eval_select` for more information
|
||||
|
||||
error: this argument must be a function item
|
||||
--> $DIR/const-eval-select-bad.rs:10:27
|
||||
|
|
||||
LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||
| ^^
|
||||
|
|
||||
= note: expected a function item, found {integer}
|
||||
= help: consult the documentation on `const_eval_select` for more information
|
||||
|
||||
error[E0277]: expected a `FnOnce()` closure, found `{integer}`
|
||||
--> $DIR/const-eval-select-bad.rs:10:27
|
||||
|
|
||||
@ -38,15 +29,6 @@ LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||
note: required by a bound in `const_eval_select`
|
||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
||||
|
||||
error: this argument must be a function item
|
||||
--> $DIR/const-eval-select-bad.rs:10:31
|
||||
|
|
||||
LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: expected a function item, found {integer}
|
||||
= help: consult the documentation on `const_eval_select` for more information
|
||||
|
||||
error[E0277]: expected a `FnOnce()` closure, found `{integer}`
|
||||
--> $DIR/const-eval-select-bad.rs:10:31
|
||||
|
|
||||
@ -60,6 +42,24 @@ LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||
note: required by a bound in `const_eval_select`
|
||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
||||
|
||||
error: this argument must be a function item
|
||||
--> $DIR/const-eval-select-bad.rs:10:27
|
||||
|
|
||||
LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||
| ^^
|
||||
|
|
||||
= note: expected a function item, found {integer}
|
||||
= help: consult the documentation on `const_eval_select` for more information
|
||||
|
||||
error: this argument must be a function item
|
||||
--> $DIR/const-eval-select-bad.rs:10:31
|
||||
|
|
||||
LL | const_eval_select((), 42, 0xDEADBEEF);
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: expected a function item, found {integer}
|
||||
= help: consult the documentation on `const_eval_select` for more information
|
||||
|
||||
error[E0271]: expected `bar` to be a fn item that returns `i32`, but it returns `bool`
|
||||
--> $DIR/const-eval-select-bad.rs:32:34
|
||||
|
|
||||
|
@ -518,5 +518,10 @@ fn const_eval_select<ARG: Tuple, F, G, RET>(
|
||||
arg: ARG,
|
||||
called_in_const: F,
|
||||
called_at_rt: G,
|
||||
) -> RET;
|
||||
) -> RET
|
||||
/* where clauses enforced by built-in method confirmation:
|
||||
where
|
||||
F: const FnOnce<Arg, Output = RET>,
|
||||
G: FnOnce<Arg, Output = RET>,
|
||||
*/;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user