diff options
| author | Deadbeef <ent3rm4n@gmail.com> | 2023-06-30 15:21:35 +0000 |
|---|---|---|
| committer | Deadbeef <ent3rm4n@gmail.com> | 2023-07-04 11:47:46 +0000 |
| commit | 8eb3e0bf30ac1b9fe27441fcad045ce54304ac37 (patch) | |
| tree | ac6d063363ed8be33171dc257d8a21ecd06769ef | |
| parent | 1c837cb6f7347b257ea42b8587a7c84bd13c92c9 (diff) | |
| download | rust-8eb3e0bf30ac1b9fe27441fcad045ce54304ac37.tar.gz rust-8eb3e0bf30ac1b9fe27441fcad045ce54304ac37.zip | |
enforce context effects in typeck
| -rw-r--r-- | compiler/rustc_hir_typeck/src/callee.rs | 69 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/expr.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/context.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/subst.rs | 5 |
4 files changed, 81 insertions, 4 deletions
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index be908c41c94..7d6f6ad5e05 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -6,8 +6,9 @@ use crate::type_error_struct; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey}; use rustc_hir as hir; -use rustc_hir::def::{self, CtorKind, Namespace, Res}; +use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::HirId; use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::{ infer, @@ -376,15 +377,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { - ty::FnDef(def_id, subst) => { - let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst); + ty::FnDef(def_id, substs) => { + self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, substs); + let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs); // Unit testing: function items annotated with // `#[rustc_evaluate_where_clauses]` trigger special output // to let us test the trait evaluation system. if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) { let predicates = self.tcx.predicates_of(def_id); - let predicates = predicates.instantiate(self.tcx, subst); + let predicates = predicates.instantiate(self.tcx, substs); for (predicate, predicate_span) in predicates { let obligation = Obligation::new( self.tcx, @@ -405,6 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } (fn_sig, Some(def_id)) } + // FIXME(effects): these arms should error because we can't enforce them ty::FnPtr(sig) => (sig, None), _ => { for arg in arg_exprs { @@ -739,6 +742,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_sig.output() } + #[tracing::instrument(level = "debug", skip(self, span))] + pub(super) fn enforce_context_effects( + &self, + call_expr_hir: HirId, + span: Span, + callee_did: DefId, + callee_substs: SubstsRef<'tcx>, + ) { + let tcx = self.tcx; + + if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { + return; + } + + // Compute the constness required by the context. + let context = tcx.hir().enclosing_body_owner(call_expr_hir); + let const_context = tcx.hir().body_const_context(context); + + let kind = tcx.def_kind(context.to_def_id()); + debug_assert_ne!(kind, DefKind::ConstParam); + + if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) { + trace!("do not const check this context"); + return; + } + + let effect = match const_context { + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_, + Some(hir::ConstContext::ConstFn) => { + let substs = ty::InternalSubsts::identity_for_item(tcx, context); + substs.host_effect_param().expect("ConstContext::Maybe must have host effect param") + } + None => tcx.consts.true_, + }; + + let identity_substs = ty::InternalSubsts::identity_for_item(tcx, callee_did); + + trace!(?effect, ?identity_substs, ?callee_substs); + + // FIXME this should be made more efficient + let host_effect_param_index = identity_substs.iter().position(|x| { + matches!(x.unpack(), ty::GenericArgKind::Const(const_) if matches!(const_.kind(), ty::ConstKind::Param(param) if param.name == sym::host)) + }); + + if let Some(idx) = host_effect_param_index { + let param = callee_substs.const_at(idx); + let cause = self.misc(span); + match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) { + Ok(infer::InferOk { obligations, value: () }) => { + self.register_predicates(obligations); + } + Err(e) => { + self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit(); + } + } + } + } + fn confirm_overloaded_call( &self, call_expr: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 52e3779cd41..265cacaf6c2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1274,6 +1274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to // trigger this codepath causing `structurally_resolve_type` to emit an error. + self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.substs); self.write_method_call(expr.hir_id, method); Ok(method) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1c610d6891b..53786fb5582 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -320,6 +320,8 @@ pub struct CommonLifetimes<'tcx> { pub struct CommonConsts<'tcx> { pub unit: Const<'tcx>, + pub true_: Const<'tcx>, + pub false_: Const<'tcx>, } impl<'tcx> CommonTypes<'tcx> { @@ -417,6 +419,14 @@ impl<'tcx> CommonConsts<'tcx> { kind: ty::ConstKind::Value(ty::ValTree::zst()), ty: types.unit, }), + true_: mk_const(ty::ConstData { + kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::TRUE)), + ty: types.bool, + }), + false_: mk_const(ty::ConstData { + kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::FALSE)), + ty: types.bool, + }), } } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 111b1d009b3..4d5f5b8658c 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -11,6 +11,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; +use rustc_span::sym; use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; @@ -451,6 +452,10 @@ impl<'tcx> InternalSubsts<'tcx> { pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> { tcx.mk_substs_from_iter(self.iter().take(generics.count())) } + + pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> { + self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host)) + } } impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> { |
