Skip to content

Commit 56733bc

Browse files
committed
Auto merge of #47738 - nikomatsakis:issue-47139-master, r=arielb1
remove intercrate ambiguity hints The scheme was causing overflows during coherence checking (e.g. #47139). This is sort of a temporary fix; the proper fix I think involves reworking trait selection in deeper ways. cc @sgrif -- this *should* fix diesel cc @qnighy -- I'd like to discuss you with alternative techniques for achieving the same end. =) Actually, it might be good to put some energy into refactoring traits first. r? @eddyb
2 parents 26792f0 + 2fc5739 commit 56733bc

File tree

7 files changed

+307
-93
lines changed

7 files changed

+307
-93
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
#![feature(specialization)]
6767
#![feature(unboxed_closures)]
6868
#![feature(underscore_lifetimes)]
69+
#![feature(universal_impl_trait)]
6970
#![feature(trace_macros)]
7071
#![feature(catch_expr)]
7172
#![feature(test)]

src/librustc/traits/coherence.rs

+36-14
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use ty::{self, Ty, TyCtxt};
1919
use ty::fold::TypeFoldable;
2020
use ty::subst::Subst;
2121

22-
use infer::{InferCtxt, InferOk};
22+
use infer::{InferOk};
2323

2424
/// Whether we do the orphan check relative to this crate or
2525
/// to some remote crate.
@@ -40,13 +40,20 @@ pub struct OverlapResult<'tcx> {
4040
pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
4141
}
4242

43-
/// If there are types that satisfy both impls, returns a suitably-freshened
44-
/// `ImplHeader` with those types substituted
45-
pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
46-
impl1_def_id: DefId,
47-
impl2_def_id: DefId,
48-
intercrate_mode: IntercrateMode)
49-
-> Option<OverlapResult<'tcx>>
43+
/// If there are types that satisfy both impls, invokes `on_overlap`
44+
/// with a suitably-freshened `ImplHeader` with those types
45+
/// substituted. Otherwise, invokes `no_overlap`.
46+
pub fn overlapping_impls<'gcx, F1, F2, R>(
47+
tcx: TyCtxt<'_, 'gcx, 'gcx>,
48+
impl1_def_id: DefId,
49+
impl2_def_id: DefId,
50+
intercrate_mode: IntercrateMode,
51+
on_overlap: F1,
52+
no_overlap: F2,
53+
) -> R
54+
where
55+
F1: FnOnce(OverlapResult<'_>) -> R,
56+
F2: FnOnce() -> R,
5057
{
5158
debug!("impl_can_satisfy(\
5259
impl1_def_id={:?}, \
@@ -56,8 +63,23 @@ pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
5663
impl2_def_id,
5764
intercrate_mode);
5865

59-
let selcx = &mut SelectionContext::intercrate(infcx, intercrate_mode);
60-
overlap(selcx, impl1_def_id, impl2_def_id)
66+
let overlaps = tcx.infer_ctxt().enter(|infcx| {
67+
let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
68+
overlap(selcx, impl1_def_id, impl2_def_id).is_some()
69+
});
70+
71+
if !overlaps {
72+
return no_overlap();
73+
}
74+
75+
// In the case where we detect an error, run the check again, but
76+
// this time tracking intercrate ambuiguity causes for better
77+
// diagnostics. (These take time and can lead to false errors.)
78+
tcx.infer_ctxt().enter(|infcx| {
79+
let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
80+
selcx.enable_tracking_intercrate_ambiguity_causes();
81+
on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap())
82+
})
6183
}
6284

6385
fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
@@ -135,10 +157,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
135157
return None
136158
}
137159

138-
Some(OverlapResult {
139-
impl_header: selcx.infcx().resolve_type_vars_if_possible(&a_impl_header),
140-
intercrate_ambiguity_causes: selcx.intercrate_ambiguity_causes().to_vec(),
141-
})
160+
let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
161+
let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
162+
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
163+
Some(OverlapResult { impl_header, intercrate_ambiguity_causes })
142164
}
143165

144166
pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,

src/librustc/traits/select.rs

+64-40
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
9292

9393
inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>,
9494

95-
intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
95+
intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
9696
}
9797

98-
#[derive(Clone)]
98+
#[derive(Clone, Debug)]
9999
pub enum IntercrateAmbiguityCause {
100100
DownstreamCrate {
101101
trait_desc: String,
@@ -423,7 +423,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
423423
freshener: infcx.freshener(),
424424
intercrate: None,
425425
inferred_obligations: SnapshotVec::new(),
426-
intercrate_ambiguity_causes: Vec::new(),
426+
intercrate_ambiguity_causes: None,
427427
}
428428
}
429429

@@ -435,10 +435,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
435435
freshener: infcx.freshener(),
436436
intercrate: Some(mode),
437437
inferred_obligations: SnapshotVec::new(),
438-
intercrate_ambiguity_causes: Vec::new(),
438+
intercrate_ambiguity_causes: None,
439439
}
440440
}
441441

442+
/// Enables tracking of intercrate ambiguity causes. These are
443+
/// used in coherence to give improved diagnostics. We don't do
444+
/// this until we detect a coherence error because it can lead to
445+
/// false overflow results (#47139) and because it costs
446+
/// computation time.
447+
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
448+
assert!(self.intercrate.is_some());
449+
assert!(self.intercrate_ambiguity_causes.is_none());
450+
self.intercrate_ambiguity_causes = Some(vec![]);
451+
debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
452+
}
453+
454+
/// Gets the intercrate ambiguity causes collected since tracking
455+
/// was enabled and disables tracking at the same time. If
456+
/// tracking is not enabled, just returns an empty vector.
457+
pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
458+
assert!(self.intercrate.is_some());
459+
self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
460+
}
461+
442462
pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
443463
self.infcx
444464
}
@@ -451,10 +471,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
451471
self.infcx
452472
}
453473

454-
pub fn intercrate_ambiguity_causes(&self) -> &[IntercrateAmbiguityCause] {
455-
&self.intercrate_ambiguity_causes
456-
}
457-
458474
/// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
459475
/// context's self.
460476
fn in_snapshot<R, F>(&mut self, f: F) -> R
@@ -828,19 +844,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
828844
debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
829845
stack.fresh_trait_ref);
830846
// Heuristics: show the diagnostics when there are no candidates in crate.
831-
if let Ok(candidate_set) = self.assemble_candidates(stack) {
832-
if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
833-
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
834-
let self_ty = trait_ref.self_ty();
835-
let cause = IntercrateAmbiguityCause::DownstreamCrate {
836-
trait_desc: trait_ref.to_string(),
837-
self_desc: if self_ty.has_concrete_skeleton() {
838-
Some(self_ty.to_string())
839-
} else {
840-
None
841-
},
842-
};
843-
self.intercrate_ambiguity_causes.push(cause);
847+
if self.intercrate_ambiguity_causes.is_some() {
848+
debug!("evaluate_stack: intercrate_ambiguity_causes is some");
849+
if let Ok(candidate_set) = self.assemble_candidates(stack) {
850+
if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
851+
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
852+
let self_ty = trait_ref.self_ty();
853+
let cause = IntercrateAmbiguityCause::DownstreamCrate {
854+
trait_desc: trait_ref.to_string(),
855+
self_desc: if self_ty.has_concrete_skeleton() {
856+
Some(self_ty.to_string())
857+
} else {
858+
None
859+
},
860+
};
861+
debug!("evaluate_stack: pushing cause = {:?}", cause);
862+
self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
863+
}
844864
}
845865
}
846866
return EvaluatedToAmbig;
@@ -1092,25 +1112,29 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
10921112
None => {}
10931113
Some(conflict) => {
10941114
debug!("coherence stage: not knowable");
1095-
// Heuristics: show the diagnostics when there are no candidates in crate.
1096-
let candidate_set = self.assemble_candidates(stack)?;
1097-
if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
1098-
!self.evaluate_candidate(stack, &c).may_apply()
1099-
}) {
1100-
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
1101-
let self_ty = trait_ref.self_ty();
1102-
let trait_desc = trait_ref.to_string();
1103-
let self_desc = if self_ty.has_concrete_skeleton() {
1104-
Some(self_ty.to_string())
1105-
} else {
1106-
None
1107-
};
1108-
let cause = if let Conflict::Upstream = conflict {
1109-
IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
1110-
} else {
1111-
IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
1112-
};
1113-
self.intercrate_ambiguity_causes.push(cause);
1115+
if self.intercrate_ambiguity_causes.is_some() {
1116+
debug!("evaluate_stack: intercrate_ambiguity_causes is some");
1117+
// Heuristics: show the diagnostics when there are no candidates in crate.
1118+
let candidate_set = self.assemble_candidates(stack)?;
1119+
if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
1120+
!self.evaluate_candidate(stack, &c).may_apply()
1121+
}) {
1122+
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
1123+
let self_ty = trait_ref.self_ty();
1124+
let trait_desc = trait_ref.to_string();
1125+
let self_desc = if self_ty.has_concrete_skeleton() {
1126+
Some(self_ty.to_string())
1127+
} else {
1128+
None
1129+
};
1130+
let cause = if let Conflict::Upstream = conflict {
1131+
IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
1132+
} else {
1133+
IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
1134+
};
1135+
debug!("evaluate_stack: pushing cause = {:?}", cause);
1136+
self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
1137+
}
11141138
}
11151139
return Ok(None);
11161140
}

src/librustc/traits/specialize/specialization_graph.rs

+17-20
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ impl<'a, 'gcx, 'tcx> Children {
133133
};
134134

135135
let tcx = tcx.global_tcx();
136-
let (le, ge) = tcx.infer_ctxt().enter(|infcx| {
137-
let overlap = traits::overlapping_impls(&infcx,
138-
possible_sibling,
139-
impl_def_id,
140-
traits::IntercrateMode::Issue43355);
141-
if let Some(overlap) = overlap {
136+
let (le, ge) = traits::overlapping_impls(
137+
tcx,
138+
possible_sibling,
139+
impl_def_id,
140+
traits::IntercrateMode::Issue43355,
141+
|overlap| {
142142
if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
143143
return Ok((false, false));
144144
}
@@ -151,10 +151,9 @@ impl<'a, 'gcx, 'tcx> Children {
151151
} else {
152152
Ok((le, ge))
153153
}
154-
} else {
155-
Ok((false, false))
156-
}
157-
})?;
154+
},
155+
|| Ok((false, false)),
156+
)?;
158157

159158
if le && !ge {
160159
debug!("descending as child of TraitRef {:?}",
@@ -171,16 +170,14 @@ impl<'a, 'gcx, 'tcx> Children {
171170
return Ok(Inserted::Replaced(possible_sibling));
172171
} else {
173172
if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
174-
tcx.infer_ctxt().enter(|infcx| {
175-
if let Some(overlap) = traits::overlapping_impls(
176-
&infcx,
177-
possible_sibling,
178-
impl_def_id,
179-
traits::IntercrateMode::Fixed)
180-
{
181-
last_lint = Some(overlap_error(overlap));
182-
}
183-
});
173+
traits::overlapping_impls(
174+
tcx,
175+
possible_sibling,
176+
impl_def_id,
177+
traits::IntercrateMode::Fixed,
178+
|overlap| last_lint = Some(overlap_error(overlap)),
179+
|| (),
180+
);
184181
}
185182

186183
// no overlap (error bailed already via ?)

src/librustc_typeck/coherence/inherent_impls_overlap.rs

+27-19
Original file line numberDiff line numberDiff line change
@@ -82,29 +82,37 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
8282

8383
for (i, &impl1_def_id) in impls.iter().enumerate() {
8484
for &impl2_def_id in &impls[(i + 1)..] {
85-
let used_to_be_allowed = self.tcx.infer_ctxt().enter(|infcx| {
86-
if let Some(overlap) =
87-
traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
88-
IntercrateMode::Issue43355)
89-
{
85+
let used_to_be_allowed = traits::overlapping_impls(
86+
self.tcx,
87+
impl1_def_id,
88+
impl2_def_id,
89+
IntercrateMode::Issue43355,
90+
|overlap| {
9091
self.check_for_common_items_in_impls(
91-
impl1_def_id, impl2_def_id, overlap, false);
92+
impl1_def_id,
93+
impl2_def_id,
94+
overlap,
95+
false,
96+
);
9297
false
93-
} else {
94-
true
95-
}
96-
});
98+
},
99+
|| true,
100+
);
97101

98102
if used_to_be_allowed {
99-
self.tcx.infer_ctxt().enter(|infcx| {
100-
if let Some(overlap) =
101-
traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
102-
IntercrateMode::Fixed)
103-
{
104-
self.check_for_common_items_in_impls(
105-
impl1_def_id, impl2_def_id, overlap, true);
106-
}
107-
});
103+
traits::overlapping_impls(
104+
self.tcx,
105+
impl1_def_id,
106+
impl2_def_id,
107+
IntercrateMode::Fixed,
108+
|overlap| self.check_for_common_items_in_impls(
109+
impl1_def_id,
110+
impl2_def_id,
111+
overlap,
112+
true,
113+
),
114+
|| (),
115+
);
108116
}
109117
}
110118
}

0 commit comments

Comments
 (0)