diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 5f5994879126b..9cca3afec79d2 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -30,6 +30,7 @@ pub struct Autoderef<'a, 'tcx> { span: Span, body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, + host_effect_param: ty::Const<'tcx>, // Current state: state: AutoderefSnapshot<'tcx>, @@ -109,14 +110,15 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { pub fn new( infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_def_id: LocalDefId, + body_id: LocalDefId, span: Span, base_ty: Ty<'tcx>, + host_effect_param: ty::Const<'tcx>, ) -> Autoderef<'a, 'tcx> { Autoderef { infcx, span, - body_id: body_def_id, + body_id, param_env, state: AutoderefSnapshot { steps: vec![], @@ -127,6 +129,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { }, include_raw_pointers: false, silence_errors: false, + host_effect_param, } } @@ -135,7 +138,18 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let tcx = self.infcx.tcx; // - let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]); + let deref_trait_def_id = tcx.lang_items().deref_trait()?; + + // FIXME(effects): This is still broken, since we don't necessarily have a choice of + // `host = true` or `host = host` in `const` functions. This is also busted in `method_autoderef_steps`. + let deref_generics = self.infcx.tcx.generics_of(deref_trait_def_id); + let args = if deref_generics.host_effect_index.is_some() { + self.infcx.tcx.mk_args(&[ty.into(), self.host_effect_param.into()]) + } else { + self.infcx.tcx.mk_args(&[ty.into()]) + }; + + let trait_ref = ty::TraitRef::new(tcx, deref_trait_def_id, args); let cause = traits::ObligationCause::misc(self.span, self.body_id); let obligation = traits::Obligation::new( tcx, @@ -151,7 +165,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection( tcx, tcx.lang_items().deref_target()?, - [ty], + trait_ref.args, ))?; debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 5f26da9c87f4d..5f89c213781a8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1648,7 +1648,14 @@ fn receiver_is_valid<'tcx>( return true; } - let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); + let mut autoderef = Autoderef::new( + infcx, + wfcx.param_env, + wfcx.body_def_id, + span, + receiver_ty, + tcx.expected_host_effect_param_for_body(wfcx.body_def_id), + ); // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`. if arbitrary_self_types_enabled { diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index 7873257c4e3d1..4753a4edcb812 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -12,7 +12,14 @@ use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { - Autoderef::new(self, self.param_env, self.body_id, span, base_ty) + Autoderef::new( + self, + self.param_env, + self.body_id, + span, + base_ty, + self.tcx.expected_host_effect_param_for_body(self.body_id), + ) } pub fn try_overloaded_deref( @@ -20,7 +27,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, base_ty: Ty<'tcx>, ) -> Option>> { - self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) + let callee = self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)?; + self.enforce_context_effects(span, callee.value.def_id, callee.value.args); + Some(callee) } /// Returns the adjustment steps. diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 10c31d8c641c7..bf8eef4313ac3 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -17,6 +17,8 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; use rustc_middle::query::Providers; +use rustc_middle::traits::query::type_op::MethodAutoderef; +use rustc_middle::traits::query::CanonicalMethodAutoderefGoal; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::AssocItem; use rustc_middle::ty::GenericParamDefKind; @@ -36,7 +38,6 @@ use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy use rustc_trait_selection::traits::query::method_autoderef::{ CandidateStep, MethodAutoderefStepsResult, }; -use rustc_trait_selection::traits::query::CanonicalTyGoal; use rustc_trait_selection::traits::NormalizeExt; use rustc_trait_selection::traits::{self, ObligationCause}; use std::cell::RefCell; @@ -371,13 +372,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result>, { let mut orig_values = OriginalQueryValues::default(); - let param_env_and_self_ty = self.canonicalize_query( - ParamEnvAnd { param_env: self.param_env, value: self_ty }, - &mut orig_values, - ); + let goal = MethodAutoderef { + self_ty, + host_effect_param: self.tcx.expected_host_effect_param_for_body(self.body_id), + }; + let canonical_goal = self.canonicalize_query(self.param_env.and(goal), &mut orig_values); let steps = match mode { - Mode::MethodCall => self.tcx.method_autoderef_steps(param_env_and_self_ty), + Mode::MethodCall => self.tcx.method_autoderef_steps(canonical_goal), Mode::Path => self.probe(|_| { // Mode::Path - the deref steps is "trivial". This turns // our CanonicalQuery into a "trivial" QueryResponse. This @@ -385,20 +387,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // special handling for this "trivial case" is a good idea. let infcx = &self.infcx; - let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) = - infcx.instantiate_canonical_with_fresh_inference_vars( - span, - ¶m_env_and_self_ty, - ); + let (ParamEnvAnd { param_env: _, value: goal }, canonical_inference_vars) = + infcx.instantiate_canonical_with_fresh_inference_vars(span, &canonical_goal); debug!( - "probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}", - param_env_and_self_ty, self_ty + "probe_op: Mode::Path, canonical_goal={:?} self_ty={:?}", + canonical_goal, self_ty ); MethodAutoderefStepsResult { steps: infcx.tcx.arena.alloc_from_iter([CandidateStep { self_ty: self.make_query_response_ignoring_pending_obligations( canonical_inference_vars, - self_ty, + goal.self_ty, ), autoderefs: 0, from_unsafe_deref: false, @@ -510,17 +509,23 @@ pub fn provide(providers: &mut Providers) { fn method_autoderef_steps<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalTyGoal<'tcx>, + goal: CanonicalMethodAutoderefGoal<'tcx>, ) -> MethodAutoderefStepsResult<'tcx> { debug!("method_autoderef_steps({:?})", goal); let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal); - let ParamEnvAnd { param_env, value: self_ty } = goal; - - let mut autoderef = - Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty) - .include_raw_pointers() - .silence_errors(); + let ParamEnvAnd { param_env, value: MethodAutoderef { self_ty, host_effect_param } } = goal; + + let mut autoderef = Autoderef::new( + infcx, + param_env, + hir::def_id::CRATE_DEF_ID, + DUMMY_SP, + self_ty, + host_effect_param, + ) + .include_raw_pointers() + .silence_errors(); let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef .by_ref() diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7d5abaceb20ac..1656219fe62cb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -30,7 +30,7 @@ use crate::query::plumbing::{ }; use crate::thir; use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalMethodAutoderefGoal, CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, }; @@ -2072,9 +2072,9 @@ rustc_queries! { } query method_autoderef_steps( - goal: CanonicalTyGoal<'tcx> + goal: CanonicalMethodAutoderefGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { - desc { "computing autoderef types for `{}`", goal.value.value } + desc { "computing autoderef types for `{}`", goal.value.value.self_ty } } query supported_target_features(_: CrateNum) -> &'tcx UnordMap> { diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 5f02dd22961c0..134fb2524bb41 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -14,7 +14,7 @@ use rustc_span::Span; pub mod type_op { use crate::ty::fold::TypeFoldable; - use crate::ty::{Predicate, Ty, TyCtxt, UserType}; + use crate::ty::{Const, Predicate, Ty, TyCtxt, UserType}; use std::fmt; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] @@ -65,12 +65,23 @@ pub mod type_op { Self { value } } } + + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] + pub struct MethodAutoderef<'tcx> { + pub self_ty: Ty<'tcx>, + /// Expected host effect value of the caller. For const fns, it's + /// some const param ty, and for normal functions, it's `true`. + pub host_effect_param: Const<'tcx>, + } } pub type CanonicalProjectionGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>; pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; +pub type CanonicalMethodAutoderefGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::MethodAutoderef<'tcx>>>; + pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index c3e8991c63a20..27045ddb1e1df 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -1,5 +1,6 @@ use crate::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; use rustc_span::Span; @@ -121,7 +122,12 @@ pub struct OverloadedDeref<'tcx> { impl<'tcx> OverloadedDeref<'tcx> { /// Get the zst function item type for this method call. - pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> Ty<'tcx> { + pub fn method_call( + &self, + tcx: TyCtxt<'tcx>, + source: Ty<'tcx>, + caller_def_id: LocalDefId, + ) -> Ty<'tcx> { let trait_def_id = match self.mutbl { hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None), hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None), @@ -132,7 +138,11 @@ impl<'tcx> OverloadedDeref<'tcx> { .find(|m| m.kind == ty::AssocKind::Fn) .unwrap() .def_id; - Ty::new_fn_def(tcx, method_def_id, [source]) + Ty::new_fn_def( + tcx, + method_def_id, + tcx.with_opt_host_effect_param(caller_def_id, method_def_id, [source]), + ) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 3a6fbaec9fd46..733aca2b82d99 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -811,10 +811,12 @@ impl<'tcx> TyCtxt<'tcx> { self.consts.false_ } Some(hir::ConstContext::ConstFn) => { - let host_idx = self - .generics_of(def_id) - .host_effect_index - .expect("ConstContext::Maybe must have host effect param"); + let host_idx = self.generics_of(def_id).host_effect_index.unwrap_or_else(|| { + span_bug!( + self.def_span(def_id), + "item with `ConstContext::ConstFn` must have host effect param" + ) + }); ty::GenericArgs::identity_for_item(self, def_id).const_at(host_idx) } None => self.consts.true_, @@ -828,15 +830,14 @@ impl<'tcx> TyCtxt<'tcx> { callee_def_id: DefId, args: impl IntoIterator>>, ) -> ty::GenericArgsRef<'tcx> { - let generics = self.generics_of(callee_def_id); - assert_eq!(generics.parent, None); - - let opt_const_param = generics - .host_effect_index - .is_some() - .then(|| ty::GenericArg::from(self.expected_host_effect_param_for_body(caller_def_id))); - - self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param)) + let mut args = args.into_iter(); + ty::GenericArgs::for_item(self, callee_def_id, |param, _| { + if param.is_host_effect() { + self.expected_host_effect_param_for_body(caller_def_id).into() + } else { + args.next().unwrap().into() + } + }) } } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 53e5d70f946eb..9393f43c7e14a 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -254,7 +254,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_); let ref_str = self.temp(ref_str_ty, test.span); let deref = tcx.require_lang_item(LangItem::Deref, None); - let method = trait_method(tcx, deref, sym::deref, [ty]); + let method = trait_method( + tcx, + deref, + sym::deref, + tcx.with_opt_host_effect_param(self.def_id, deref, [ty]), + ); let eq_block = self.cfg.start_new_block(); self.cfg.push_assign( block, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 78d72b3028416..e1e7d1b138279 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -118,7 +118,7 @@ impl<'tcx> Cx<'tcx> { Adjust::Deref(Some(deref)) => { // We don't need to do call adjust_span here since // deref coercions always start with a built-in deref. - let call = deref.method_call(self.tcx(), expr.ty); + let call = deref.method_call(self.tcx(), expr.ty, self.body_owner.expect_local()); expr = Expr { temp_lifetime, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 58700850a60f8..8409f5a958b12 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4129,7 +4129,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Extract `::Target` assoc type and check that it is `T` && let Some(deref_target_did) = tcx.lang_items().deref_target() - && let projection = Ty::new_projection(tcx,deref_target_did, tcx.mk_args(&[ty::GenericArg::from(found_ty)])) + && let args = tcx.with_opt_host_effect_param(tcx.hir().enclosing_body_owner(expr.hir_id), deref_target_did, [found_ty]) + && let projection = Ty::new_projection(tcx,deref_target_did, args) && let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection) && obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation)) && infcx.can_eq(param_env, deref_target, target_ty) diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs index 7d811a2cc1f35..8a73c29af82fd 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs @@ -1,5 +1,9 @@ -// check-pass -// FIXME(effects) this shouldn't pass +// known-bug: #110395 +// failure-status: 101 +// dont-check-compiler-stderr + +// const closures don't have host params... + #![feature(const_closures, const_trait_impl, effects)] #![allow(incomplete_features)] @@ -13,5 +17,4 @@ impl Foo for () { fn main() { (const || { (()).foo() })(); - // FIXME(effects) ~^ ERROR: cannot call non-const fn } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs index 59fb48e794cc3..8017c0817ad6e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs @@ -235,7 +235,7 @@ impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b #[lang = "deref"] -// #[const_trait] FIXME +#[const_trait] trait Deref { #[lang = "deref_target"] type Target: ?Sized; @@ -244,7 +244,7 @@ trait Deref { } -impl /* const */ Deref for &T { +impl const Deref for &T { type Target = T; fn deref(&self) -> &T { @@ -252,7 +252,7 @@ impl /* const */ Deref for &T { } } -impl /* const */ Deref for &mut T { +impl const Deref for &mut T { type Target = T; fn deref(&self) -> &T { @@ -285,7 +285,6 @@ impl Option { use Option::*; -/* const fn as_deref(opt: &Option) -> Option<&T::Target> where T: ~const Deref, @@ -295,7 +294,6 @@ where Option::None => Option::None, } } -*/ #[const_trait] trait Into: Sized { @@ -400,9 +398,9 @@ impl<'a, T: ?Sized> Pin<&'a T> { impl Pin

{ - /* const */ fn as_ref(&self) -> Pin<&P::Target> + const fn as_ref(&self) -> Pin<&P::Target> where - P: /* ~const */ Deref, + P: ~const Deref, { unsafe { Pin::new_unchecked(&*self.pointer) } } @@ -434,14 +432,14 @@ impl Option { } */ -impl /* const */ Deref for Pin

{ +impl const Deref for Pin

{ type Target = P::Target; fn deref(&self) -> &P::Target { Pin::get_ref(Pin::as_ref(self)) } } -impl /* const */ Deref for Option { +impl const Deref for Option { type Target = T; fn deref(&self) -> &T { loop {}