Skip to content

Commit 8eb3e0b

Browse files
committed
enforce context effects in typeck
1 parent 1c837cb commit 8eb3e0b

File tree

4 files changed

+81
-4
lines changed

4 files changed

+81
-4
lines changed

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use crate::type_error_struct;
66
use rustc_ast::util::parser::PREC_POSTFIX;
77
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey};
88
use rustc_hir as hir;
9-
use rustc_hir::def::{self, CtorKind, Namespace, Res};
9+
use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res};
1010
use rustc_hir::def_id::DefId;
11+
use rustc_hir::HirId;
1112
use rustc_hir_analysis::autoderef::Autoderef;
1213
use rustc_infer::{
1314
infer,
@@ -376,15 +377,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
376377
expected: Expectation<'tcx>,
377378
) -> Ty<'tcx> {
378379
let (fn_sig, def_id) = match *callee_ty.kind() {
379-
ty::FnDef(def_id, subst) => {
380-
let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst);
380+
ty::FnDef(def_id, substs) => {
381+
self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, substs);
382+
let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs);
381383

382384
// Unit testing: function items annotated with
383385
// `#[rustc_evaluate_where_clauses]` trigger special output
384386
// to let us test the trait evaluation system.
385387
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
386388
let predicates = self.tcx.predicates_of(def_id);
387-
let predicates = predicates.instantiate(self.tcx, subst);
389+
let predicates = predicates.instantiate(self.tcx, substs);
388390
for (predicate, predicate_span) in predicates {
389391
let obligation = Obligation::new(
390392
self.tcx,
@@ -405,6 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
405407
}
406408
(fn_sig, Some(def_id))
407409
}
410+
// FIXME(effects): these arms should error because we can't enforce them
408411
ty::FnPtr(sig) => (sig, None),
409412
_ => {
410413
for arg in arg_exprs {
@@ -739,6 +742,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
739742
fn_sig.output()
740743
}
741744

745+
#[tracing::instrument(level = "debug", skip(self, span))]
746+
pub(super) fn enforce_context_effects(
747+
&self,
748+
call_expr_hir: HirId,
749+
span: Span,
750+
callee_did: DefId,
751+
callee_substs: SubstsRef<'tcx>,
752+
) {
753+
let tcx = self.tcx;
754+
755+
if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
756+
return;
757+
}
758+
759+
// Compute the constness required by the context.
760+
let context = tcx.hir().enclosing_body_owner(call_expr_hir);
761+
let const_context = tcx.hir().body_const_context(context);
762+
763+
let kind = tcx.def_kind(context.to_def_id());
764+
debug_assert_ne!(kind, DefKind::ConstParam);
765+
766+
if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) {
767+
trace!("do not const check this context");
768+
return;
769+
}
770+
771+
let effect = match const_context {
772+
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
773+
Some(hir::ConstContext::ConstFn) => {
774+
let substs = ty::InternalSubsts::identity_for_item(tcx, context);
775+
substs.host_effect_param().expect("ConstContext::Maybe must have host effect param")
776+
}
777+
None => tcx.consts.true_,
778+
};
779+
780+
let identity_substs = ty::InternalSubsts::identity_for_item(tcx, callee_did);
781+
782+
trace!(?effect, ?identity_substs, ?callee_substs);
783+
784+
// FIXME this should be made more efficient
785+
let host_effect_param_index = identity_substs.iter().position(|x| {
786+
matches!(x.unpack(), ty::GenericArgKind::Const(const_) if matches!(const_.kind(), ty::ConstKind::Param(param) if param.name == sym::host))
787+
});
788+
789+
if let Some(idx) = host_effect_param_index {
790+
let param = callee_substs.const_at(idx);
791+
let cause = self.misc(span);
792+
match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
793+
Ok(infer::InferOk { obligations, value: () }) => {
794+
self.register_predicates(obligations);
795+
}
796+
Err(e) => {
797+
self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
798+
}
799+
}
800+
}
801+
}
802+
742803
fn confirm_overloaded_call(
743804
&self,
744805
call_expr: &'tcx hir::Expr<'tcx>,

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12741274
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
12751275
// trigger this codepath causing `structurally_resolve_type` to emit an error.
12761276

1277+
self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.substs);
12771278
self.write_method_call(expr.hir_id, method);
12781279
Ok(method)
12791280
}

compiler/rustc_middle/src/ty/context.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ pub struct CommonLifetimes<'tcx> {
320320

321321
pub struct CommonConsts<'tcx> {
322322
pub unit: Const<'tcx>,
323+
pub true_: Const<'tcx>,
324+
pub false_: Const<'tcx>,
323325
}
324326

325327
impl<'tcx> CommonTypes<'tcx> {
@@ -417,6 +419,14 @@ impl<'tcx> CommonConsts<'tcx> {
417419
kind: ty::ConstKind::Value(ty::ValTree::zst()),
418420
ty: types.unit,
419421
}),
422+
true_: mk_const(ty::ConstData {
423+
kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::TRUE)),
424+
ty: types.bool,
425+
}),
426+
false_: mk_const(ty::ConstData {
427+
kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::FALSE)),
428+
ty: types.bool,
429+
}),
420430
}
421431
}
422432
}

compiler/rustc_middle/src/ty/subst.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
1111
use rustc_hir::def_id::DefId;
1212
use rustc_macros::HashStable;
1313
use rustc_serialize::{self, Decodable, Encodable};
14+
use rustc_span::sym;
1415
use rustc_type_ir::WithCachedTypeInfo;
1516
use smallvec::SmallVec;
1617

@@ -451,6 +452,10 @@ impl<'tcx> InternalSubsts<'tcx> {
451452
pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> {
452453
tcx.mk_substs_from_iter(self.iter().take(generics.count()))
453454
}
455+
456+
pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> {
457+
self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host))
458+
}
454459
}
455460

456461
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> {

0 commit comments

Comments
 (0)