Skip to content

Commit cde29b9

Browse files
Implement const effect predicate in new solver
1 parent a16d491 commit cde29b9

File tree

127 files changed

+1702
-1170
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+1702
-1170
lines changed

compiler/rustc_hir_analysis/src/bounds.rs

+11
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ impl<'tcx> Bounds<'tcx> {
8181
self.clauses.insert(0, (trait_ref.upcast(tcx), span));
8282
}
8383

84+
/// Push a `const` or `~const` bound as a `HostEffect` predicate.
85+
pub(crate) fn push_const_bound(
86+
&mut self,
87+
tcx: TyCtxt<'tcx>,
88+
bound_trait_ref: ty::PolyTraitRef<'tcx>,
89+
host: ty::HostPolarity,
90+
span: Span,
91+
) {
92+
self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span));
93+
}
94+
8495
pub(crate) fn clauses(
8596
&self,
8697
// FIXME(effects): remove tcx

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+107-3
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ fn compare_method_predicate_entailment<'tcx>(
181181
});
182182

183183
// Create mapping from trait method to impl method.
184+
let impl_def_id = impl_m.container_id(tcx);
184185
let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto(
185186
tcx,
186187
impl_m.container_id(tcx),
@@ -204,6 +205,24 @@ fn compare_method_predicate_entailment<'tcx>(
204205
trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate),
205206
);
206207

208+
// FIXME(effects): This should be replaced with a more dedicated method.
209+
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
210+
if check_const_if_const {
211+
// Augment the hybrid param-env with the const conditions
212+
// of the impl header and the trait method.
213+
hybrid_preds.extend(
214+
tcx.const_conditions(impl_def_id)
215+
.instantiate_identity(tcx)
216+
.into_iter()
217+
.chain(
218+
tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args),
219+
)
220+
.map(|(trait_ref, _)| {
221+
trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
222+
}),
223+
);
224+
}
225+
207226
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
208227
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
209228
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
@@ -230,6 +249,34 @@ fn compare_method_predicate_entailment<'tcx>(
230249
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
231250
}
232251

252+
// If we're within a const implementation, we need to make sure that the method
253+
// does not assume stronger `~const` bounds than the trait definition.
254+
//
255+
// This registers the `~const` bounds of the impl method, which we will prove
256+
// using the hybrid param-env that we earlier augmented with the const conditions
257+
// from the impl header and trait method declaration.
258+
if check_const_if_const {
259+
for (const_condition, span) in
260+
tcx.const_conditions(impl_m.def_id).instantiate_own_identity()
261+
{
262+
let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
263+
let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
264+
265+
let cause =
266+
ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem {
267+
impl_item_def_id: impl_m_def_id,
268+
trait_item_def_id: trait_m.def_id,
269+
kind: impl_m.kind,
270+
});
271+
ocx.register_obligation(traits::Obligation::new(
272+
tcx,
273+
cause,
274+
param_env,
275+
const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
276+
));
277+
}
278+
}
279+
233280
// We now need to check that the signature of the impl method is
234281
// compatible with that of the trait method. We do this by
235282
// checking that `impl_fty <: trait_fty`.
@@ -1846,17 +1893,20 @@ fn compare_type_predicate_entailment<'tcx>(
18461893
trait_ty: ty::AssocItem,
18471894
impl_trait_ref: ty::TraitRef<'tcx>,
18481895
) -> Result<(), ErrorGuaranteed> {
1896+
let impl_def_id = impl_ty.container_id(tcx);
18491897
let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id).rebase_onto(
18501898
tcx,
1851-
impl_ty.container_id(tcx),
1899+
impl_def_id,
18521900
impl_trait_ref.args,
18531901
);
18541902

18551903
let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
18561904
let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
18571905

18581906
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own_identity();
1859-
if impl_ty_own_bounds.len() == 0 {
1907+
let impl_ty_own_const_conditions =
1908+
tcx.const_conditions(impl_ty.def_id).instantiate_own_identity();
1909+
if impl_ty_own_bounds.len() == 0 && impl_ty_own_const_conditions.len() == 0 {
18601910
// Nothing to check.
18611911
return Ok(());
18621912
}
@@ -1881,6 +1931,23 @@ fn compare_type_predicate_entailment<'tcx>(
18811931
let impl_ty_span = tcx.def_span(impl_ty_def_id);
18821932
let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
18831933

1934+
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
1935+
if check_const_if_const {
1936+
// Augment the hybrid param-env with the const conditions
1937+
// of the impl header and the trait assoc type.
1938+
hybrid_preds.extend(
1939+
tcx.const_conditions(impl_ty_predicates.parent.unwrap())
1940+
.instantiate_identity(tcx)
1941+
.into_iter()
1942+
.chain(
1943+
tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args),
1944+
)
1945+
.map(|(trait_ref, _)| {
1946+
trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
1947+
}),
1948+
);
1949+
}
1950+
18841951
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
18851952
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
18861953
debug!(caller_bounds=?param_env.caller_bounds());
@@ -1901,6 +1968,27 @@ fn compare_type_predicate_entailment<'tcx>(
19011968
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
19021969
}
19031970

1971+
if check_const_if_const {
1972+
// Validate the const conditions of the impl associated type.
1973+
for (const_condition, span) in impl_ty_own_const_conditions {
1974+
let normalize_cause = traits::ObligationCause::misc(span, impl_ty_def_id);
1975+
let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
1976+
1977+
let cause =
1978+
ObligationCause::new(span, impl_ty_def_id, ObligationCauseCode::CompareImplItem {
1979+
impl_item_def_id: impl_ty_def_id,
1980+
trait_item_def_id: trait_ty.def_id,
1981+
kind: impl_ty.kind,
1982+
});
1983+
ocx.register_obligation(traits::Obligation::new(
1984+
tcx,
1985+
cause,
1986+
param_env,
1987+
const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
1988+
));
1989+
}
1990+
}
1991+
19041992
// Check that all obligations are satisfied by the implementation's
19051993
// version.
19061994
let errors = ocx.select_all_or_error();
@@ -1983,14 +2071,30 @@ pub(super) fn check_type_bounds<'tcx>(
19832071
ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
19842072
};
19852073

1986-
let obligations: Vec<_> = tcx
2074+
let mut obligations: Vec<_> = tcx
19872075
.explicit_item_bounds(trait_ty.def_id)
19882076
.iter_instantiated_copied(tcx, rebased_args)
19892077
.map(|(concrete_ty_bound, span)| {
19902078
debug!(?concrete_ty_bound);
19912079
traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
19922080
})
19932081
.collect();
2082+
2083+
// Only in a const implementation do we need to check that the `~const` item bounds hold.
2084+
if tcx.constness(container_id) == hir::Constness::Const {
2085+
obligations.extend(
2086+
tcx.implied_const_bounds(trait_ty.def_id)
2087+
.iter_instantiated_copied(tcx, rebased_args)
2088+
.map(|(c, span)| {
2089+
traits::Obligation::new(
2090+
tcx,
2091+
mk_cause(span),
2092+
param_env,
2093+
c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
2094+
)
2095+
}),
2096+
);
2097+
}
19942098
debug!(item_bounds=?obligations);
19952099

19962100
// Normalize predicates with the assumption that the GAT may always normalize

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+31-6
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ use rustc_trait_selection::traits::misc::{
3232
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
3333
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
3434
use rustc_trait_selection::traits::{
35-
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
35+
self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
36+
WellFormedLoc,
3637
};
3738
use rustc_type_ir::TypeFlags;
3839
use rustc_type_ir::solve::NoSolution;
@@ -86,7 +87,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
8687
self.body_def_id,
8788
ObligationCauseCode::WellFormed(loc),
8889
);
89-
self.ocx.register_obligation(traits::Obligation::new(
90+
self.ocx.register_obligation(Obligation::new(
9091
self.tcx(),
9192
cause,
9293
self.param_env,
@@ -1173,7 +1174,7 @@ fn check_type_defn<'tcx>(
11731174
wfcx.body_def_id,
11741175
ObligationCauseCode::Misc,
11751176
);
1176-
wfcx.register_obligation(traits::Obligation::new(
1177+
wfcx.register_obligation(Obligation::new(
11771178
tcx,
11781179
cause,
11791180
wfcx.param_env,
@@ -1369,6 +1370,30 @@ fn check_impl<'tcx>(
13691370
obligation.cause.span = hir_self_ty.span;
13701371
}
13711372
}
1373+
1374+
// Ensure that the `~const` where clauses of the trait hold for the impl.
1375+
if tcx.constness(item.owner_id.def_id) == hir::Constness::Const {
1376+
for (bound, _) in
1377+
tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args)
1378+
{
1379+
let bound = wfcx.normalize(
1380+
item.span,
1381+
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
1382+
bound,
1383+
);
1384+
wfcx.register_obligation(Obligation::new(
1385+
tcx,
1386+
ObligationCause::new(
1387+
hir_self_ty.span,
1388+
wfcx.body_def_id,
1389+
ObligationCauseCode::WellFormed(None),
1390+
),
1391+
wfcx.param_env,
1392+
bound.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
1393+
))
1394+
}
1395+
}
1396+
13721397
debug!(?obligations);
13731398
wfcx.register_obligations(obligations);
13741399
}
@@ -1561,7 +1586,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
15611586
wfcx.body_def_id,
15621587
ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP),
15631588
);
1564-
traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
1589+
Obligation::new(tcx, cause, wfcx.param_env, pred)
15651590
});
15661591

15671592
let predicates = predicates.instantiate_identity(tcx);
@@ -1852,7 +1877,7 @@ fn receiver_is_implemented<'tcx>(
18521877
let tcx = wfcx.tcx();
18531878
let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
18541879

1855-
let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
1880+
let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
18561881

18571882
if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
18581883
true
@@ -2188,7 +2213,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
21882213
.unwrap_or(obligation_span);
21892214
}
21902215

2191-
let obligation = traits::Obligation::new(
2216+
let obligation = Obligation::new(
21922217
tcx,
21932218
traits::ObligationCause::new(
21942219
span,

compiler/rustc_hir_analysis/src/collect.rs

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ pub fn provide(providers: &mut Providers) {
7777
explicit_supertraits_containing_assoc_item:
7878
predicates_of::explicit_supertraits_containing_assoc_item,
7979
trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
80+
const_conditions: predicates_of::const_conditions,
81+
implied_const_bounds: predicates_of::implied_const_bounds,
8082
type_param_predicates: predicates_of::type_param_predicates,
8183
trait_def,
8284
adt_def,

compiler/rustc_hir_analysis/src/collect/item_bounds.rs

+32-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,16 @@ fn associated_type_bounds<'tcx>(
4040
let mut bounds = Bounds::default();
4141
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
4242
// Associated types are implicitly sized unless a `?Sized` bound is found
43-
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
43+
match filter {
44+
PredicateFilter::All
45+
| PredicateFilter::SelfOnly
46+
| PredicateFilter::SelfThatDefines(_)
47+
| PredicateFilter::SelfAndAssociatedTypeBounds => {
48+
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
49+
}
50+
// `ConstIfConst` is only interested in `~const` bounds.
51+
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
52+
}
4453

4554
let trait_def_id = tcx.local_parent(assoc_item_def_id);
4655
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
@@ -109,10 +118,19 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
109118
} else {
110119
// Only collect *self* type bounds if the filter is for self.
111120
match filter {
112-
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
121+
PredicateFilter::All => {}
122+
PredicateFilter::SelfOnly => {
113123
return None;
114124
}
115-
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {}
125+
PredicateFilter::SelfThatDefines(_)
126+
| PredicateFilter::SelfConstIfConst
127+
| PredicateFilter::SelfAndAssociatedTypeBounds
128+
| PredicateFilter::ConstIfConst => {
129+
unreachable!(
130+
"invalid predicate filter for \
131+
`remap_gat_vars_and_recurse_into_nested_projections`"
132+
)
133+
}
116134
}
117135

118136
clause_ty = alias_ty.self_ty();
@@ -308,7 +326,17 @@ fn opaque_type_bounds<'tcx>(
308326
let mut bounds = Bounds::default();
309327
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
310328
// Opaque types are implicitly sized unless a `?Sized` bound is found
311-
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
329+
match filter {
330+
PredicateFilter::All
331+
| PredicateFilter::SelfOnly
332+
| PredicateFilter::SelfThatDefines(_)
333+
| PredicateFilter::SelfAndAssociatedTypeBounds => {
334+
// Associated types are implicitly sized unless a `?Sized` bound is found
335+
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
336+
}
337+
//`ConstIfConst` is only interested in `~const` bounds.
338+
PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
339+
}
312340
debug!(?bounds);
313341

314342
tcx.arena.alloc_from_iter(bounds.clauses(tcx))

0 commit comments

Comments
 (0)