Skip to content

Commit e5f2fdb

Browse files
committed
Restructure the code leveraging in abilities more than modes
1 parent e2567b0 commit e5f2fdb

File tree

1 file changed

+47
-51
lines changed

1 file changed

+47
-51
lines changed

compiler/rustc_trait_selection/src/traits/coherence.rs

+47-51
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::traits::util::impl_trait_ref_and_oblig;
1111
use crate::traits::SkipLeakCheck;
1212
use crate::traits::{
1313
self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
14-
SelectionContext,
14+
PredicateObligations, SelectionContext,
1515
};
1616
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1717
use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
@@ -137,12 +137,23 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
137137
header
138138
}
139139

140+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
140141
enum OverlapMode {
141142
Stable,
142143
WithNegative,
143144
Strict,
144145
}
145146

147+
impl OverlapMode {
148+
fn use_negative_impl(&self) -> bool {
149+
*self == OverlapMode::Strict || *self == OverlapMode::WithNegative
150+
}
151+
152+
fn use_implicit_negative(&self) -> bool {
153+
*self == OverlapMode::Stable || *self == OverlapMode::WithNegative
154+
}
155+
}
156+
146157
fn overlap_mode<'tcx>(tcx: TyCtxt<'tcx>, impl1_def_id: DefId, impl2_def_id: DefId) -> OverlapMode {
147158
if tcx.has_attr(impl1_def_id, sym::rustc_strict_coherence)
148159
!= tcx.has_attr(impl2_def_id, sym::rustc_strict_coherence)
@@ -190,6 +201,16 @@ fn overlap_within_probe<'cx, 'tcx>(
190201
let infcx = selcx.infcx();
191202
let tcx = infcx.tcx;
192203

204+
let overlap_mode = overlap_mode(tcx, impl1_def_id, impl2_def_id);
205+
206+
if overlap_mode.use_negative_impl() {
207+
if negative_impl(selcx, impl1_def_id, impl2_def_id)
208+
|| negative_impl(selcx, impl2_def_id, impl1_def_id)
209+
{
210+
return None;
211+
}
212+
}
213+
193214
// For the purposes of this check, we don't bring any placeholder
194215
// types into scope; instead, we replace the generic types with
195216
// fresh type variables, and hence we do our evaluations in an
@@ -199,29 +220,15 @@ fn overlap_within_probe<'cx, 'tcx>(
199220
let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
200221
let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
201222

202-
match overlap_mode(tcx, impl1_def_id, impl2_def_id) {
203-
OverlapMode::Stable => {
204-
if stable_disjoint(selcx, param_env, &impl1_header, impl2_header) {
205-
return None;
206-
}
207-
}
208-
OverlapMode::Strict => {
209-
if strict_disjoint(selcx, impl1_def_id, impl2_def_id) {
210-
return None;
211-
}
223+
debug!("overlap: impl1_header={:?}", impl1_header);
224+
debug!("overlap: impl2_header={:?}", impl2_header);
212225

213-
// Equate for error reporting
214-
let _ = selcx
215-
.infcx()
216-
.at(&ObligationCause::dummy(), param_env)
217-
.eq_impl_headers(&impl1_header, &impl2_header);
218-
}
219-
OverlapMode::WithNegative => {
220-
if stable_disjoint(selcx, param_env, &impl1_header, impl2_header)
221-
|| strict_disjoint(selcx, impl1_def_id, impl2_def_id)
222-
{
223-
return None;
224-
}
226+
let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?;
227+
debug!("overlap: unification check succeeded");
228+
229+
if overlap_mode.use_implicit_negative() {
230+
if implicit_negative(selcx, param_env, &impl1_header, impl2_header, obligations) {
231+
return None;
225232
}
226233
}
227234

@@ -242,31 +249,29 @@ fn overlap_within_probe<'cx, 'tcx>(
242249
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
243250
}
244251

252+
fn equate_impl_headers<'cx, 'tcx>(
253+
selcx: &mut SelectionContext<'cx, 'tcx>,
254+
impl1_header: &ty::ImplHeader<'tcx>,
255+
impl2_header: &ty::ImplHeader<'tcx>,
256+
) -> Option<PredicateObligations<'tcx>> {
257+
// Do `a` and `b` unify? If not, no overlap.
258+
selcx
259+
.infcx()
260+
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
261+
.eq_impl_headers(impl1_header, impl2_header)
262+
.map(|infer_ok| infer_ok.obligations)
263+
.ok()
264+
}
265+
245266
/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
246267
/// where-clauses) If so, return false, otherwise return true, they are disjoint.
247-
fn stable_disjoint<'cx, 'tcx>(
268+
fn implicit_negative<'cx, 'tcx>(
248269
selcx: &mut SelectionContext<'cx, 'tcx>,
249270
param_env: ty::ParamEnv<'tcx>,
250271
impl1_header: &ty::ImplHeader<'tcx>,
251272
impl2_header: ty::ImplHeader<'tcx>,
273+
obligations: PredicateObligations<'tcx>,
252274
) -> bool {
253-
debug!("overlap: impl1_header={:?}", impl1_header);
254-
debug!("overlap: impl2_header={:?}", impl2_header);
255-
256-
// Do `a` and `b` unify? If not, no overlap.
257-
let obligations = match selcx
258-
.infcx()
259-
.at(&ObligationCause::dummy(), param_env)
260-
.eq_impl_headers(&impl1_header, &impl2_header)
261-
{
262-
Ok(InferOk { obligations, value: () }) => obligations,
263-
Err(_) => {
264-
return true;
265-
}
266-
};
267-
268-
debug!("overlap: unification check succeeded");
269-
270275
// There's no overlap if obligations are unsatisfiable or if the obligation negated is
271276
// satisfied.
272277
//
@@ -318,16 +323,7 @@ fn stable_disjoint<'cx, 'tcx>(
318323

319324
/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including
320325
/// where-clauses) If so, return true, they are disjoint and false otherwise.
321-
fn strict_disjoint<'cx, 'tcx>(
322-
selcx: &mut SelectionContext<'cx, 'tcx>,
323-
impl1_def_id: DefId,
324-
impl2_def_id: DefId,
325-
) -> bool {
326-
explicit_disjoint(selcx, impl1_def_id, impl2_def_id)
327-
|| explicit_disjoint(selcx, impl2_def_id, impl1_def_id)
328-
}
329-
330-
fn explicit_disjoint<'cx, 'tcx>(
326+
fn negative_impl<'cx, 'tcx>(
331327
selcx: &mut SelectionContext<'cx, 'tcx>,
332328
impl1_def_id: DefId,
333329
impl2_def_id: DefId,

0 commit comments

Comments
 (0)