Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 4c74e03

Browse files
Implement const effect predicate in new solver
1 parent af461e0 commit 4c74e03

File tree

127 files changed

+1715
-1190
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

+1715
-1190
lines changed

compiler/rustc_hir_analysis/src/bounds.rs

Lines changed: 11 additions & 0 deletions
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

Lines changed: 123 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -187,48 +187,64 @@ fn compare_method_predicate_entailment<'tcx>(
187187
let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id);
188188

189189
// Create mapping from trait to placeholder.
190+
let impl_def_id = impl_m.container_id(tcx);
190191
let trait_to_placeholder_args =
191-
impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args);
192+
impl_to_placeholder_args.rebase_onto(tcx, impl_def_id, trait_to_impl_args);
192193
debug!("compare_impl_method: trait_to_placeholder_args={:?}", trait_to_placeholder_args);
193194

194195
let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
195196
let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
196197

197-
// Create obligations for each predicate declared by the impl
198-
// definition in the context of the trait's parameter
199-
// environment. We can't just use `impl_env.caller_bounds`,
200-
// however, because we want to replace all late-bound regions with
201-
// region variables.
202-
let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
203-
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
204-
205-
debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
206-
207198
// This is the only tricky bit of the new way we check implementation methods
208199
// We need to build a set of predicates where only the method-level bounds
209200
// are from the trait and we assume all other bounds from the implementation
210201
// to be previously satisfied.
211202
//
212203
// We then register the obligations from the impl_m and check to see
213204
// if all constraints hold.
214-
hybrid_preds.predicates.extend(
205+
let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
206+
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;
207+
hybrid_preds.extend(
215208
trait_m_predicates
216209
.instantiate_own(tcx, trait_to_placeholder_args)
217210
.map(|(predicate, _)| predicate),
218211
);
219212

213+
// FIXME(effects): This should be replaced with a more dedicated method.
214+
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
215+
if check_const_if_const {
216+
// Augment the hybrid param-env with the const conditions
217+
// of the impl header and the trait method.
218+
hybrid_preds.extend(
219+
tcx.const_conditions(impl_def_id)
220+
.instantiate_identity(tcx)
221+
.into_iter()
222+
.chain(
223+
tcx.const_conditions(trait_m.def_id)
224+
.instantiate_own(tcx, trait_to_placeholder_args),
225+
)
226+
.map(|(trait_ref, _)| {
227+
trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
228+
}),
229+
);
230+
}
231+
220232
// Construct trait parameter environment and then shift it into the placeholder viewpoint.
221233
// The key step here is to update the caller_bounds's predicates to be
222234
// the new hybrid bounds we computed.
223235
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
224-
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
236+
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
225237
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
226238

227239
let infcx = &tcx.infer_ctxt().build();
228240
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
229241

230242
debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
231243

244+
// Create obligations for each predicate declared by the impl
245+
// definition in the context of the hybrid param-env. This makes
246+
// sure that the impl's method's where clauses are not more
247+
// restrictive than the trait's method (and the impl itself).
232248
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_args);
233249
for (predicate, span) in impl_m_own_bounds {
234250
let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
@@ -243,6 +259,34 @@ fn compare_method_predicate_entailment<'tcx>(
243259
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
244260
}
245261

262+
// If we're within a const implementation, we need to make sure that the method
263+
// does not assume stronger `~const` bounds than the trait definition.
264+
//
265+
// This registers the `~const` bounds of the impl method, which we will prove
266+
// using the hybrid param-env that we earlier augmented with the const conditions
267+
// from the impl header and trait method declaration.
268+
if check_const_if_const {
269+
for (const_condition, span) in
270+
tcx.const_conditions(impl_m.def_id).instantiate_own(tcx, impl_to_placeholder_args)
271+
{
272+
let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
273+
let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
274+
275+
let cause =
276+
ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem {
277+
impl_item_def_id: impl_m_def_id,
278+
trait_item_def_id: trait_m.def_id,
279+
kind: impl_m.kind,
280+
});
281+
ocx.register_obligation(traits::Obligation::new(
282+
tcx,
283+
cause,
284+
param_env,
285+
const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
286+
));
287+
}
288+
}
289+
246290
// We now need to check that the signature of the impl method is
247291
// compatible with that of the trait method. We do this by
248292
// checking that `impl_fty <: trait_fty`.
@@ -1759,14 +1803,14 @@ fn compare_const_predicate_entailment<'tcx>(
17591803
// The predicates declared by the impl definition, the trait and the
17601804
// associated const in the trait are assumed.
17611805
let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap());
1762-
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
1763-
hybrid_preds.predicates.extend(
1806+
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;
1807+
hybrid_preds.extend(
17641808
trait_ct_predicates
17651809
.instantiate_own(tcx, trait_to_impl_args)
17661810
.map(|(predicate, _)| predicate),
17671811
);
17681812

1769-
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
1813+
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
17701814
let param_env = traits::normalize_param_env_or_error(
17711815
tcx,
17721816
param_env,
@@ -1871,14 +1915,16 @@ fn compare_type_predicate_entailment<'tcx>(
18711915
impl_trait_ref: ty::TraitRef<'tcx>,
18721916
) -> Result<(), ErrorGuaranteed> {
18731917
let impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id);
1874-
let trait_to_impl_args =
1875-
impl_args.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.args);
1918+
let impl_def_id = impl_ty.container_id(tcx);
1919+
let trait_to_impl_args = impl_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args);
18761920

18771921
let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
18781922
let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
18791923

18801924
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_args);
1881-
if impl_ty_own_bounds.len() == 0 {
1925+
let impl_ty_own_const_conditions =
1926+
tcx.const_conditions(impl_ty.def_id).instantiate_own(tcx, impl_args);
1927+
if impl_ty_own_bounds.len() == 0 && impl_ty_own_const_conditions.len() == 0 {
18821928
// Nothing to check.
18831929
return Ok(());
18841930
}
@@ -1892,18 +1938,35 @@ fn compare_type_predicate_entailment<'tcx>(
18921938
// The predicates declared by the impl definition, the trait and the
18931939
// associated type in the trait are assumed.
18941940
let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
1895-
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
1896-
hybrid_preds.predicates.extend(
1941+
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;
1942+
hybrid_preds.extend(
18971943
trait_ty_predicates
18981944
.instantiate_own(tcx, trait_to_impl_args)
18991945
.map(|(predicate, _)| predicate),
19001946
);
19011947

1948+
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
1949+
if check_const_if_const {
1950+
// Augment the hybrid param-env with the const conditions
1951+
// of the impl header and the trait assoc type.
1952+
hybrid_preds.extend(
1953+
tcx.const_conditions(impl_ty_predicates.parent.unwrap())
1954+
.instantiate_identity(tcx)
1955+
.into_iter()
1956+
.chain(
1957+
tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args),
1958+
)
1959+
.map(|(trait_ref, _)| {
1960+
trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
1961+
}),
1962+
);
1963+
}
1964+
19021965
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
19031966

19041967
let impl_ty_span = tcx.def_span(impl_ty_def_id);
19051968
let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
1906-
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
1969+
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
19071970
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
19081971
let infcx = tcx.infer_ctxt().build();
19091972
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
@@ -1923,6 +1986,27 @@ fn compare_type_predicate_entailment<'tcx>(
19231986
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
19241987
}
19251988

1989+
if check_const_if_const {
1990+
// Validate the const conditions of the impl associated type.
1991+
for (const_condition, span) in impl_ty_own_const_conditions {
1992+
let normalize_cause = traits::ObligationCause::misc(span, impl_ty_def_id);
1993+
let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
1994+
1995+
let cause =
1996+
ObligationCause::new(span, impl_ty_def_id, ObligationCauseCode::CompareImplItem {
1997+
impl_item_def_id: impl_ty_def_id,
1998+
trait_item_def_id: trait_ty.def_id,
1999+
kind: impl_ty.kind,
2000+
});
2001+
ocx.register_obligation(traits::Obligation::new(
2002+
tcx,
2003+
cause,
2004+
param_env,
2005+
const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
2006+
));
2007+
}
2008+
}
2009+
19262010
// Check that all obligations are satisfied by the implementation's
19272011
// version.
19282012
let errors = ocx.select_all_or_error();
@@ -2005,14 +2089,30 @@ pub(super) fn check_type_bounds<'tcx>(
20052089
ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
20062090
};
20072091

2008-
let obligations: Vec<_> = tcx
2092+
let mut obligations: Vec<_> = tcx
20092093
.explicit_item_bounds(trait_ty.def_id)
20102094
.iter_instantiated_copied(tcx, rebased_args)
20112095
.map(|(concrete_ty_bound, span)| {
20122096
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
20132097
traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
20142098
})
20152099
.collect();
2100+
2101+
// Only in a const implementation do we need to check that the `~const` item bounds hold.
2102+
if tcx.constness(container_id) == hir::Constness::Const {
2103+
obligations.extend(
2104+
tcx.implied_const_bounds(trait_ty.def_id)
2105+
.iter_instantiated_copied(tcx, rebased_args)
2106+
.map(|(c, span)| {
2107+
traits::Obligation::new(
2108+
tcx,
2109+
mk_cause(span),
2110+
param_env,
2111+
c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
2112+
)
2113+
}),
2114+
);
2115+
}
20162116
debug!("check_type_bounds: item_bounds={:?}", obligations);
20172117

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

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 31 additions & 6 deletions
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

Lines changed: 2 additions & 0 deletions
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,

0 commit comments

Comments
 (0)