Skip to content

Commit 2fc5739

Browse files
committed
track intercrate ambiguity only when there is a coherence error
1 parent 514ae7d commit 2fc5739

File tree

2 files changed

+82
-49
lines changed

2 files changed

+82
-49
lines changed

src/librustc/traits/coherence.rs

+18-9
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,22 @@ where
6363
impl2_def_id,
6464
intercrate_mode);
6565

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.)
6678
tcx.infer_ctxt().enter(|infcx| {
6779
let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
68-
if let Some(r) = overlap(selcx, impl1_def_id, impl2_def_id) {
69-
on_overlap(r)
70-
} else {
71-
no_overlap()
72-
}
80+
selcx.enable_tracking_intercrate_ambiguity_causes();
81+
on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap())
7382
})
7483
}
7584

@@ -148,10 +157,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
148157
return None
149158
}
150159

151-
Some(OverlapResult {
152-
impl_header: selcx.infcx().resolve_type_vars_if_possible(&a_impl_header),
153-
intercrate_ambiguity_causes: selcx.intercrate_ambiguity_causes().to_vec(),
154-
})
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 })
155164
}
156165

157166
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
}

0 commit comments

Comments
 (0)