Skip to content

Commit 34aeaa2

Browse files
committed
Auto merge of #118386 - compiler-errors:const-deref, r=<try>
Fix `Deref` args when `#[const_trait]` is enabled Fix `Deref` being a `#[const_trait]`. To fix this fully, we also need to pass the host param to `method_autoderef_steps` and make sure we use it correctly in `Autoderef`.
2 parents 0ee9cfd + a453884 commit 34aeaa2

File tree

13 files changed

+126
-62
lines changed

13 files changed

+126
-62
lines changed

Diff for: compiler/rustc_hir_analysis/src/autoderef.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub struct Autoderef<'a, 'tcx> {
3030
span: Span,
3131
body_id: LocalDefId,
3232
param_env: ty::ParamEnv<'tcx>,
33+
host_effect_param: ty::Const<'tcx>,
3334

3435
// Current state:
3536
state: AutoderefSnapshot<'tcx>,
@@ -109,14 +110,15 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
109110
pub fn new(
110111
infcx: &'a InferCtxt<'tcx>,
111112
param_env: ty::ParamEnv<'tcx>,
112-
body_def_id: LocalDefId,
113+
body_id: LocalDefId,
113114
span: Span,
114115
base_ty: Ty<'tcx>,
116+
host_effect_param: ty::Const<'tcx>,
115117
) -> Autoderef<'a, 'tcx> {
116118
Autoderef {
117119
infcx,
118120
span,
119-
body_id: body_def_id,
121+
body_id,
120122
param_env,
121123
state: AutoderefSnapshot {
122124
steps: vec![],
@@ -127,6 +129,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
127129
},
128130
include_raw_pointers: false,
129131
silence_errors: false,
132+
host_effect_param,
130133
}
131134
}
132135

@@ -135,7 +138,18 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
135138
let tcx = self.infcx.tcx;
136139

137140
// <ty as Deref>
138-
let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
141+
let deref_trait_def_id = tcx.lang_items().deref_trait()?;
142+
143+
// FIXME(effects): This is still broken, since we don't necessarily have a choice of
144+
// `host = true` or `host = host` in `const` functions. This is also busted in `method_autoderef_steps`.
145+
let deref_generics = self.infcx.tcx.generics_of(deref_trait_def_id);
146+
let args = if deref_generics.host_effect_index.is_some() {
147+
self.infcx.tcx.mk_args(&[ty.into(), self.host_effect_param.into()])
148+
} else {
149+
self.infcx.tcx.mk_args(&[ty.into()])
150+
};
151+
152+
let trait_ref = ty::TraitRef::new(tcx, deref_trait_def_id, args);
139153
let cause = traits::ObligationCause::misc(self.span, self.body_id);
140154
let obligation = traits::Obligation::new(
141155
tcx,
@@ -151,7 +165,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
151165
let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection(
152166
tcx,
153167
tcx.lang_items().deref_target()?,
154-
[ty],
168+
trait_ref.args,
155169
))?;
156170
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
157171
self.state.obligations.extend(obligations);

Diff for: compiler/rustc_hir_analysis/src/check/wfcheck.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,14 @@ fn receiver_is_valid<'tcx>(
16481648
return true;
16491649
}
16501650

1651-
let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
1651+
let mut autoderef = Autoderef::new(
1652+
infcx,
1653+
wfcx.param_env,
1654+
wfcx.body_def_id,
1655+
span,
1656+
receiver_ty,
1657+
tcx.expected_host_effect_param_for_body(wfcx.body_def_id),
1658+
);
16521659

16531660
// The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
16541661
if arbitrary_self_types_enabled {

Diff for: compiler/rustc_hir_typeck/src/autoderef.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,24 @@ use std::iter;
1212

1313
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1414
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
15-
Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
15+
Autoderef::new(
16+
self,
17+
self.param_env,
18+
self.body_id,
19+
span,
20+
base_ty,
21+
self.tcx.expected_host_effect_param_for_body(self.body_id),
22+
)
1623
}
1724

1825
pub fn try_overloaded_deref(
1926
&self,
2027
span: Span,
2128
base_ty: Ty<'tcx>,
2229
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
23-
self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
30+
let callee = self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)?;
31+
self.enforce_context_effects(span, callee.value.def_id, callee.value.args);
32+
Some(callee)
2433
}
2534

2635
/// Returns the adjustment steps.

Diff for: compiler/rustc_hir_typeck/src/method/probe.rs

+26-21
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use rustc_infer::infer::DefineOpaqueTypes;
1717
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
1818
use rustc_middle::middle::stability;
1919
use rustc_middle::query::Providers;
20+
use rustc_middle::traits::query::type_op::MethodAutoderef;
21+
use rustc_middle::traits::query::CanonicalMethodAutoderefGoal;
2022
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
2123
use rustc_middle::ty::AssocItem;
2224
use rustc_middle::ty::GenericParamDefKind;
@@ -36,7 +38,6 @@ use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy
3638
use rustc_trait_selection::traits::query::method_autoderef::{
3739
CandidateStep, MethodAutoderefStepsResult,
3840
};
39-
use rustc_trait_selection::traits::query::CanonicalTyGoal;
4041
use rustc_trait_selection::traits::NormalizeExt;
4142
use rustc_trait_selection::traits::{self, ObligationCause};
4243
use std::cell::RefCell;
@@ -371,34 +372,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
371372
OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result<R, MethodError<'tcx>>,
372373
{
373374
let mut orig_values = OriginalQueryValues::default();
374-
let param_env_and_self_ty = self.canonicalize_query(
375-
ParamEnvAnd { param_env: self.param_env, value: self_ty },
376-
&mut orig_values,
377-
);
375+
let goal = MethodAutoderef {
376+
self_ty,
377+
host_effect_param: self.tcx.expected_host_effect_param_for_body(self.body_id),
378+
};
379+
let canonical_goal = self.canonicalize_query(self.param_env.and(goal), &mut orig_values);
378380

379381
let steps = match mode {
380-
Mode::MethodCall => self.tcx.method_autoderef_steps(param_env_and_self_ty),
382+
Mode::MethodCall => self.tcx.method_autoderef_steps(canonical_goal),
381383
Mode::Path => self.probe(|_| {
382384
// Mode::Path - the deref steps is "trivial". This turns
383385
// our CanonicalQuery into a "trivial" QueryResponse. This
384386
// is a bit inefficient, but I don't think that writing
385387
// special handling for this "trivial case" is a good idea.
386388

387389
let infcx = &self.infcx;
388-
let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) =
389-
infcx.instantiate_canonical_with_fresh_inference_vars(
390-
span,
391-
&param_env_and_self_ty,
392-
);
390+
let (ParamEnvAnd { param_env: _, value: goal }, canonical_inference_vars) =
391+
infcx.instantiate_canonical_with_fresh_inference_vars(span, &canonical_goal);
393392
debug!(
394-
"probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}",
395-
param_env_and_self_ty, self_ty
393+
"probe_op: Mode::Path, canonical_goal={:?} self_ty={:?}",
394+
canonical_goal, self_ty
396395
);
397396
MethodAutoderefStepsResult {
398397
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
399398
self_ty: self.make_query_response_ignoring_pending_obligations(
400399
canonical_inference_vars,
401-
self_ty,
400+
goal.self_ty,
402401
),
403402
autoderefs: 0,
404403
from_unsafe_deref: false,
@@ -510,17 +509,23 @@ pub fn provide(providers: &mut Providers) {
510509

511510
fn method_autoderef_steps<'tcx>(
512511
tcx: TyCtxt<'tcx>,
513-
goal: CanonicalTyGoal<'tcx>,
512+
goal: CanonicalMethodAutoderefGoal<'tcx>,
514513
) -> MethodAutoderefStepsResult<'tcx> {
515514
debug!("method_autoderef_steps({:?})", goal);
516515

517516
let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
518-
let ParamEnvAnd { param_env, value: self_ty } = goal;
519-
520-
let mut autoderef =
521-
Autoderef::new(infcx, param_env, hir::def_id::CRATE_DEF_ID, DUMMY_SP, self_ty)
522-
.include_raw_pointers()
523-
.silence_errors();
517+
let ParamEnvAnd { param_env, value: MethodAutoderef { self_ty, host_effect_param } } = goal;
518+
519+
let mut autoderef = Autoderef::new(
520+
infcx,
521+
param_env,
522+
hir::def_id::CRATE_DEF_ID,
523+
DUMMY_SP,
524+
self_ty,
525+
host_effect_param,
526+
)
527+
.include_raw_pointers()
528+
.silence_errors();
524529
let mut reached_raw_pointer = false;
525530
let mut steps: Vec<_> = autoderef
526531
.by_ref()

Diff for: compiler/rustc_middle/src/query/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::query::plumbing::{
3030
};
3131
use crate::thir;
3232
use crate::traits::query::{
33-
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
33+
CanonicalMethodAutoderefGoal, CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
3434
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
3535
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
3636
};
@@ -2072,9 +2072,9 @@ rustc_queries! {
20722072
}
20732073

20742074
query method_autoderef_steps(
2075-
goal: CanonicalTyGoal<'tcx>
2075+
goal: CanonicalMethodAutoderefGoal<'tcx>
20762076
) -> MethodAutoderefStepsResult<'tcx> {
2077-
desc { "computing autoderef types for `{}`", goal.value.value }
2077+
desc { "computing autoderef types for `{}`", goal.value.value.self_ty }
20782078
}
20792079

20802080
query supported_target_features(_: CrateNum) -> &'tcx UnordMap<String, Option<Symbol>> {

Diff for: compiler/rustc_middle/src/traits/query.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_span::Span;
1414

1515
pub mod type_op {
1616
use crate::ty::fold::TypeFoldable;
17-
use crate::ty::{Predicate, Ty, TyCtxt, UserType};
17+
use crate::ty::{Const, Predicate, Ty, TyCtxt, UserType};
1818
use std::fmt;
1919

2020
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
@@ -65,12 +65,23 @@ pub mod type_op {
6565
Self { value }
6666
}
6767
}
68+
69+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
70+
pub struct MethodAutoderef<'tcx> {
71+
pub self_ty: Ty<'tcx>,
72+
/// Expected host effect value of the caller. For const fns, it's
73+
/// some const param ty, and for normal functions, it's `true`.
74+
pub host_effect_param: Const<'tcx>,
75+
}
6876
}
6977

7078
pub type CanonicalProjectionGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
7179

7280
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
7381

82+
pub type CanonicalMethodAutoderefGoal<'tcx> =
83+
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::MethodAutoderef<'tcx>>>;
84+
7485
pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
7586

7687
pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> =

Diff for: compiler/rustc_middle/src/ty/adjustment.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::ty::{self, Ty, TyCtxt};
22
use rustc_hir as hir;
3+
use rustc_hir::def_id::LocalDefId;
34
use rustc_hir::lang_items::LangItem;
45
use rustc_macros::HashStable;
56
use rustc_span::Span;
@@ -121,7 +122,12 @@ pub struct OverloadedDeref<'tcx> {
121122

122123
impl<'tcx> OverloadedDeref<'tcx> {
123124
/// Get the zst function item type for this method call.
124-
pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> Ty<'tcx> {
125+
pub fn method_call(
126+
&self,
127+
tcx: TyCtxt<'tcx>,
128+
source: Ty<'tcx>,
129+
caller_def_id: LocalDefId,
130+
) -> Ty<'tcx> {
125131
let trait_def_id = match self.mutbl {
126132
hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None),
127133
hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None),
@@ -132,7 +138,11 @@ impl<'tcx> OverloadedDeref<'tcx> {
132138
.find(|m| m.kind == ty::AssocKind::Fn)
133139
.unwrap()
134140
.def_id;
135-
Ty::new_fn_def(tcx, method_def_id, [source])
141+
Ty::new_fn_def(
142+
tcx,
143+
method_def_id,
144+
tcx.with_opt_host_effect_param(caller_def_id, method_def_id, [source]),
145+
)
136146
}
137147
}
138148

Diff for: compiler/rustc_middle/src/ty/util.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -811,10 +811,12 @@ impl<'tcx> TyCtxt<'tcx> {
811811
self.consts.false_
812812
}
813813
Some(hir::ConstContext::ConstFn) => {
814-
let host_idx = self
815-
.generics_of(def_id)
816-
.host_effect_index
817-
.expect("ConstContext::Maybe must have host effect param");
814+
let host_idx = self.generics_of(def_id).host_effect_index.unwrap_or_else(|| {
815+
span_bug!(
816+
self.def_span(def_id),
817+
"item with `ConstContext::ConstFn` must have host effect param"
818+
)
819+
});
818820
ty::GenericArgs::identity_for_item(self, def_id).const_at(host_idx)
819821
}
820822
None => self.consts.true_,
@@ -828,15 +830,14 @@ impl<'tcx> TyCtxt<'tcx> {
828830
callee_def_id: DefId,
829831
args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
830832
) -> ty::GenericArgsRef<'tcx> {
831-
let generics = self.generics_of(callee_def_id);
832-
assert_eq!(generics.parent, None);
833-
834-
let opt_const_param = generics
835-
.host_effect_index
836-
.is_some()
837-
.then(|| ty::GenericArg::from(self.expected_host_effect_param_for_body(caller_def_id)));
838-
839-
self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param))
833+
let mut args = args.into_iter();
834+
ty::GenericArgs::for_item(self, callee_def_id, |param, _| {
835+
if param.is_host_effect() {
836+
self.expected_host_effect_param_for_body(caller_def_id).into()
837+
} else {
838+
args.next().unwrap().into()
839+
}
840+
})
840841
}
841842
}
842843

Diff for: compiler/rustc_mir_build/src/build/matches/test.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
254254
let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
255255
let ref_str = self.temp(ref_str_ty, test.span);
256256
let deref = tcx.require_lang_item(LangItem::Deref, None);
257-
let method = trait_method(tcx, deref, sym::deref, [ty]);
257+
let method = trait_method(
258+
tcx,
259+
deref,
260+
sym::deref,
261+
tcx.with_opt_host_effect_param(self.def_id, deref, [ty]),
262+
);
258263
let eq_block = self.cfg.start_new_block();
259264
self.cfg.push_assign(
260265
block,

Diff for: compiler/rustc_mir_build/src/thir/cx/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl<'tcx> Cx<'tcx> {
118118
Adjust::Deref(Some(deref)) => {
119119
// We don't need to do call adjust_span here since
120120
// deref coercions always start with a built-in deref.
121-
let call = deref.method_call(self.tcx(), expr.ty);
121+
let call = deref.method_call(self.tcx(), expr.ty, self.body_owner.expect_local());
122122

123123
expr = Expr {
124124
temp_lifetime,

Diff for: compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4129,7 +4129,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
41294129

41304130
// Extract `<U as Deref>::Target` assoc type and check that it is `T`
41314131
&& let Some(deref_target_did) = tcx.lang_items().deref_target()
4132-
&& let projection = Ty::new_projection(tcx,deref_target_did, tcx.mk_args(&[ty::GenericArg::from(found_ty)]))
4132+
&& let args = tcx.with_opt_host_effect_param(tcx.hir().enclosing_body_owner(expr.hir_id), deref_target_did, [found_ty])
4133+
&& let projection = Ty::new_projection(tcx,deref_target_did, args)
41334134
&& let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection)
41344135
&& obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation))
41354136
&& infcx.can_eq(param_env, deref_target, target_ty)

Diff for: tests/ui/rfcs/rfc-2632-const-trait-impl/effects/const_closure-const_trait_impl-ice-113381.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
// check-pass
2-
// FIXME(effects) this shouldn't pass
1+
// known-bug: #110395
2+
// failure-status: 101
3+
// dont-check-compiler-stderr
4+
5+
// const closures don't have host params...
6+
37
#![feature(const_closures, const_trait_impl, effects)]
48
#![allow(incomplete_features)]
59

@@ -13,5 +17,4 @@ impl Foo for () {
1317

1418
fn main() {
1519
(const || { (()).foo() })();
16-
// FIXME(effects) ~^ ERROR: cannot call non-const fn
1720
}

0 commit comments

Comments
 (0)