Skip to content

Commit

Permalink
do not propagate Err when determing causal info
Browse files Browse the repository at this point in the history
In intercrate mode, if we determine that a particular `T: Trait` is
unknowable, we sometimes also go and get extra causal information. An
errant `?` was causing us to propagate an error found in that process
out as if `T: Trait` was not unknowable but rather not provable. This
led to an ICE.
  • Loading branch information
nikomatsakis committed Apr 6, 2018
1 parent 9428a3c commit 939bb32
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 19 deletions.
62 changes: 43 additions & 19 deletions src/librustc/traits/select.rs
Expand Up @@ -959,11 +959,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
if self.can_use_global_caches(param_env) {
let mut cache = self.tcx().evaluation_cache.hashmap.borrow_mut();
if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) {
debug!(
"insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global",
trait_ref,
result,
);
cache.insert(trait_ref, WithDepNode::new(dep_node, result));
return;
}
}

debug!(
"insert_evaluation_cache(trait_ref={:?}, candidate={:?})",
trait_ref,
result,
);
self.infcx.evaluation_cache.hashmap
.borrow_mut()
.insert(trait_ref, WithDepNode::new(dep_node, result));
Expand Down Expand Up @@ -1067,25 +1077,29 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
if self.intercrate_ambiguity_causes.is_some() {
debug!("evaluate_stack: intercrate_ambiguity_causes is some");
// Heuristics: show the diagnostics when there are no candidates in crate.
let candidate_set = self.assemble_candidates(stack)?;
if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
!self.evaluate_candidate(stack, &c).may_apply()
}) {
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
let self_ty = trait_ref.self_ty();
let trait_desc = trait_ref.to_string();
let self_desc = if self_ty.has_concrete_skeleton() {
Some(self_ty.to_string())
} else {
None
};
let cause = if let Conflict::Upstream = conflict {
IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
} else {
IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
};
debug!("evaluate_stack: pushing cause = {:?}", cause);
self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
if let Ok(candidate_set) = self.assemble_candidates(stack) {
if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
!self.evaluate_candidate(stack, &c).may_apply()
}) {
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
let self_ty = trait_ref.self_ty();
let trait_desc = trait_ref.to_string();
let self_desc = if self_ty.has_concrete_skeleton() {
Some(self_ty.to_string())
} else {
None
};
let cause = if let Conflict::Upstream = conflict {
IntercrateAmbiguityCause::UpstreamCrateUpdate {
trait_desc,
self_desc,
}
} else {
IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
};
debug!("evaluate_stack: pushing cause = {:?}", cause);
self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
}
}
}
return Ok(None);
Expand Down Expand Up @@ -1283,12 +1297,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let mut cache = tcx.selection_cache.hashmap.borrow_mut();
if let Some(trait_ref) = tcx.lift_to_global(&trait_ref) {
if let Some(candidate) = tcx.lift_to_global(&candidate) {
debug!(
"insert_candidate_cache(trait_ref={:?}, candidate={:?}) global",
trait_ref,
candidate,
);
cache.insert(trait_ref, WithDepNode::new(dep_node, candidate));
return;
}
}
}

debug!(
"insert_candidate_cache(trait_ref={:?}, candidate={:?}) local",
trait_ref,
candidate,
);
self.infcx.selection_cache.hashmap
.borrow_mut()
.insert(trait_ref, WithDepNode::new(dep_node, candidate));
Expand Down
23 changes: 23 additions & 0 deletions src/test/ui/issue-48728.rs
@@ -0,0 +1,23 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Regression test for #48728, an ICE that occurred computing
// coherence "help" information.

#[derive(Clone)] //~ ERROR conflicting implementations of trait `std::clone::Clone`
struct Node<T: ?Sized>(Box<T>);

impl<T: Clone + ?Sized> Clone for Node<[T]> {
fn clone(&self) -> Self {
Node(Box::clone(&self.0))
}
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/issue-48728.stderr
@@ -0,0 +1,12 @@
error[E0119]: conflicting implementations of trait `std::clone::Clone` for type `Node<[_]>`:
--> $DIR/issue-48728.rs:14:10
|
LL | #[derive(Clone)] //~ ERROR conflicting implementations of trait `std::clone::Clone`
| ^^^^^ conflicting implementation for `Node<[_]>`
...
LL | impl<T: Clone + ?Sized> Clone for Node<[T]> {
| ------------------------------------------- first implementation here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0119`.

0 comments on commit 939bb32

Please sign in to comment.