From a40e51c44f0bf80a1fe777103e3609c1c37fb282 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 27 Nov 2023 19:51:00 +0000 Subject: [PATCH] Fix Deref args when #[const_trait] is enabled --- compiler/rustc_hir_analysis/src/autoderef.rs | 22 +++++++++++++++---- compiler/rustc_hir_typeck/src/autoderef.rs | 4 +++- compiler/rustc_middle/src/ty/adjustment.rs | 14 ++++++++++-- compiler/rustc_middle/src/ty/util.rs | 17 +++++++------- .../rustc_mir_build/src/build/matches/test.rs | 7 +++++- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- .../src/traits/error_reporting/suggestions.rs | 3 ++- .../effects/minicore.rs | 16 ++++++-------- .../effects/minicore.stderr | 20 +++++++++++++++++ 9 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 5fc500f480762..ebb8fc45c2372 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -109,14 +109,14 @@ 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>, ) -> Autoderef<'a, 'tcx> { Autoderef { infcx, span, - body_id: body_def_id, + body_id, param_env, state: AutoderefSnapshot { steps: vec![], @@ -135,7 +135,21 @@ 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 let Some(host_param) = deref_generics.host_effect_index { + self.infcx.tcx.mk_args(&[ + ty.into(), + self.infcx.var_for_def(self.span, &deref_generics.params[host_param]), + ]) + } 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_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index 7873257c4e3d1..15c18f355d094 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -20,7 +20,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_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 8b1d33848eab3..fd64d8a1c68cf 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -824,15 +824,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 d1952704da3ce..46fa24bb41d52 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -253,7 +253,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 31874b29bb3b8..d593442171e74 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 9073cd6ac47a1..f6b752d66b7c6 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3906,7 +3906,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/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs index 2a2e8cec3f084..8ce04064be700 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 @@ -233,7 +233,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; @@ -242,7 +242,7 @@ trait Deref { } -impl /* const */ Deref for &T { +impl const Deref for &T { type Target = T; fn deref(&self) -> &T { @@ -250,7 +250,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 { @@ -283,7 +283,6 @@ impl Option { use Option::*; -/* const fn as_deref(opt: &Option) -> Option<&T::Target> where T: ~const Deref, @@ -293,7 +292,6 @@ where Option::None => Option::None, } } -*/ #[const_trait] trait Into: Sized { @@ -398,9 +396,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) } } @@ -432,14 +430,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 {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr new file mode 100644 index 0000000000000..3c1e6dda85caa --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr @@ -0,0 +1,20 @@ +error[E0493]: destructor of `Self` cannot be evaluated at compile-time + --> $DIR/minicore.rs:501:9 + | +LL | *self = source.clone() + | ^^^^^ + | | + | the destructor for this type cannot be evaluated in constant functions + | value is dropped here + +error[E0493]: destructor of `T` cannot be evaluated at compile-time + --> $DIR/minicore.rs:511:35 + | +LL | const fn drop(_: T) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0493`.