Skip to content

Commit

Permalink
Fix Deref args when #[const_trait] is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Dec 15, 2023
1 parent 4d1bd0d commit a40e51c
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 28 deletions.
22 changes: 18 additions & 4 deletions compiler/rustc_hir_analysis/src/autoderef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![],
Expand All @@ -135,7 +135,21 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
let tcx = self.infcx.tcx;

// <ty as Deref>
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,
Expand All @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir_typeck/src/autoderef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
base_ty: Ty<'tcx>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
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.
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_middle/src/ty/adjustment.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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),
Expand All @@ -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]),
)
}
}

Expand Down
17 changes: 8 additions & 9 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,15 +824,14 @@ impl<'tcx> TyCtxt<'tcx> {
callee_def_id: DefId,
args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
) -> 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()
}
})
}
}

Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_mir_build/src/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3906,7 +3906,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {

// Extract `<U as Deref>::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)
Expand Down
16 changes: 7 additions & 9 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b


#[lang = "deref"]
// #[const_trait] FIXME
#[const_trait]
trait Deref {
#[lang = "deref_target"]
type Target: ?Sized;
Expand All @@ -242,15 +242,15 @@ trait Deref {
}


impl<T: ?Sized> /* const */ Deref for &T {
impl<T: ?Sized> const Deref for &T {
type Target = T;

fn deref(&self) -> &T {
*self
}
}

impl<T: ?Sized> /* const */ Deref for &mut T {
impl<T: ?Sized> const Deref for &mut T {
type Target = T;

fn deref(&self) -> &T {
Expand Down Expand Up @@ -283,7 +283,6 @@ impl<T> Option<T> {

use Option::*;

/*
const fn as_deref<T>(opt: &Option<T>) -> Option<&T::Target>
where
T: ~const Deref,
Expand All @@ -293,7 +292,6 @@ where
Option::None => Option::None,
}
}
*/

#[const_trait]
trait Into<T>: Sized {
Expand Down Expand Up @@ -398,9 +396,9 @@ impl<'a, T: ?Sized> Pin<&'a T> {


impl<P: Deref> Pin<P> {
/* 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) }
}
Expand Down Expand Up @@ -432,14 +430,14 @@ impl<T> Option<T> {
}
*/

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

impl<T> /* const */ Deref for Option<T> {
impl<T> const Deref for Option<T> {
type Target = T;
fn deref(&self) -> &T {
loop {}
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr
Original file line number Diff line number Diff line change
@@ -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: ~const Destruct>(_: 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`.

0 comments on commit a40e51c

Please sign in to comment.