Skip to content

Commit 5360699

Browse files
committed
refactor a bit
1 parent 3aacf48 commit 5360699

File tree

4 files changed

+116
-70
lines changed

4 files changed

+116
-70
lines changed

src/librustc/traits/coherence.rs

+51-45
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,17 @@ use ty::subst::Subst;
2020
use infer::{InferCtxt, InferOk};
2121

2222
#[derive(Copy, Clone, Debug)]
23-
enum InferIsLocal {
24-
BrokenYes,
25-
Yes,
26-
No
23+
/// Whether we do the orphan check relative to this crate or
24+
/// to some remote crate.
25+
enum InCrate {
26+
Local,
27+
Remote
2728
}
2829

2930
#[derive(Debug, Copy, Clone)]
3031
pub enum Conflict {
3132
Upstream,
32-
Downstream
33+
Downstream { used_to_be_broken: bool }
3334
}
3435

3536
pub struct OverlapResult<'tcx> {
@@ -136,21 +137,23 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
136137
}
137138

138139
pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
139-
trait_ref: ty::TraitRef<'tcx>,
140-
broken: bool)
140+
trait_ref: ty::TraitRef<'tcx>)
141141
-> Option<Conflict>
142142
{
143-
debug!("trait_ref_is_knowable(trait_ref={:?}, broken={:?})", trait_ref, broken);
144-
let mode = if broken {
145-
InferIsLocal::BrokenYes
146-
} else {
147-
InferIsLocal::Yes
148-
};
149-
if orphan_check_trait_ref(tcx, trait_ref, mode).is_ok() {
143+
debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
144+
if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() {
150145
// A downstream or cousin crate is allowed to implement some
151146
// substitution of this trait-ref.
152-
debug!("trait_ref_is_knowable: downstream crate might implement");
153-
return Some(Conflict::Downstream);
147+
148+
// A trait can be implementable for a trait ref by both the current
149+
// crate and crates downstream of it. Older versions of rustc
150+
// were not aware of this, causing incoherence (issue #43355).
151+
let used_to_be_broken =
152+
orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok();
153+
if used_to_be_broken {
154+
debug!("trait_ref_is_knowable({:?}) - USED TO BE BROKEN", trait_ref);
155+
}
156+
return Some(Conflict::Downstream { used_to_be_broken });
154157
}
155158

156159
if trait_ref_is_local_or_fundamental(tcx, trait_ref) {
@@ -161,6 +164,7 @@ pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
161164
// which we already know about.
162165
return None;
163166
}
167+
164168
// This is a remote non-fundamental trait, so if another crate
165169
// can be the "final owner" of a substitution of this trait-ref,
166170
// they are allowed to implement it future-compatibly.
@@ -169,7 +173,7 @@ pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
169173
// and if we are an intermediate owner, then we don't care
170174
// about future-compatibility, which means that we're OK if
171175
// we are an owner.
172-
if orphan_check_trait_ref(tcx, trait_ref, InferIsLocal::No).is_ok() {
176+
if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() {
173177
debug!("trait_ref_is_knowable: orphan check passed");
174178
return None;
175179
} else {
@@ -213,31 +217,31 @@ pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
213217
return Ok(());
214218
}
215219

216-
orphan_check_trait_ref(tcx, trait_ref, InferIsLocal::No)
220+
orphan_check_trait_ref(tcx, trait_ref, InCrate::Local)
217221
}
218222

219223
fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
220224
trait_ref: ty::TraitRef<'tcx>,
221-
infer_is_local: InferIsLocal)
225+
in_crate: InCrate)
222226
-> Result<(), OrphanCheckErr<'tcx>>
223227
{
224-
debug!("orphan_check_trait_ref(trait_ref={:?}, infer_is_local={:?})",
225-
trait_ref, infer_is_local);
228+
debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})",
229+
trait_ref, in_crate);
226230

227231
// First, create an ordered iterator over all the type parameters to the trait, with the self
228232
// type appearing first.
229233
// Find the first input type that either references a type parameter OR
230234
// some local type.
231235
for input_ty in trait_ref.input_types() {
232-
if ty_is_local(tcx, input_ty, infer_is_local) {
236+
if ty_is_local(tcx, input_ty, in_crate) {
233237
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
234238

235239
// First local input type. Check that there are no
236240
// uncovered type parameters.
237-
let uncovered_tys = uncovered_tys(tcx, input_ty, infer_is_local);
241+
let uncovered_tys = uncovered_tys(tcx, input_ty, in_crate);
238242
for uncovered_ty in uncovered_tys {
239243
if let Some(param) = uncovered_ty.walk()
240-
.find(|t| is_possibly_remote_type(t, infer_is_local))
244+
.find(|t| is_possibly_remote_type(t, in_crate))
241245
{
242246
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
243247
return Err(OrphanCheckErr::UncoveredTy(param));
@@ -251,7 +255,7 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
251255
// Otherwise, enforce invariant that there are no type
252256
// parameters reachable.
253257
if let Some(param) = input_ty.walk()
254-
.find(|t| is_possibly_remote_type(t, infer_is_local))
258+
.find(|t| is_possibly_remote_type(t, in_crate))
255259
{
256260
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
257261
return Err(OrphanCheckErr::UncoveredTy(param));
@@ -263,29 +267,29 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
263267
return Err(OrphanCheckErr::NoLocalInputType);
264268
}
265269

266-
fn uncovered_tys<'tcx>(tcx: TyCtxt, ty: Ty<'tcx>, infer_is_local: InferIsLocal)
270+
fn uncovered_tys<'tcx>(tcx: TyCtxt, ty: Ty<'tcx>, in_crate: InCrate)
267271
-> Vec<Ty<'tcx>> {
268-
if ty_is_local_constructor(ty, infer_is_local) {
272+
if ty_is_local_constructor(ty, in_crate) {
269273
vec![]
270274
} else if fundamental_ty(tcx, ty) {
271275
ty.walk_shallow()
272-
.flat_map(|t| uncovered_tys(tcx, t, infer_is_local))
276+
.flat_map(|t| uncovered_tys(tcx, t, in_crate))
273277
.collect()
274278
} else {
275279
vec![ty]
276280
}
277281
}
278282

279-
fn is_possibly_remote_type(ty: Ty, _infer_is_local: InferIsLocal) -> bool {
283+
fn is_possibly_remote_type(ty: Ty, _in_crate: InCrate) -> bool {
280284
match ty.sty {
281285
ty::TyProjection(..) | ty::TyParam(..) => true,
282286
_ => false,
283287
}
284288
}
285289

286-
fn ty_is_local(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal) -> bool {
287-
ty_is_local_constructor(ty, infer_is_local) ||
288-
fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, infer_is_local))
290+
fn ty_is_local(tcx: TyCtxt, ty: Ty, in_crate: InCrate) -> bool {
291+
ty_is_local_constructor(ty, in_crate) ||
292+
fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, in_crate))
289293
}
290294

291295
fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool {
@@ -299,15 +303,16 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool {
299303
}
300304
}
301305

302-
fn def_id_is_local(def_id: DefId, infer_is_local: InferIsLocal) -> bool {
303-
match infer_is_local {
304-
InferIsLocal::Yes => false,
305-
InferIsLocal::No |
306-
InferIsLocal::BrokenYes => def_id.is_local()
306+
fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
307+
match in_crate {
308+
// The type is local to *this* crate - it will not be
309+
// local in any other crate.
310+
InCrate::Remote => false,
311+
InCrate::Local => def_id.is_local()
307312
}
308313
}
309314

310-
fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal) -> bool {
315+
fn ty_is_local_constructor(ty: Ty, in_crate: InCrate) -> bool {
311316
debug!("ty_is_local_constructor({:?})", ty);
312317

313318
match ty.sty {
@@ -330,18 +335,19 @@ fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal) -> bool {
330335
false
331336
}
332337

333-
ty::TyInfer(..) => match infer_is_local {
334-
InferIsLocal::No => false,
335-
InferIsLocal::Yes |
336-
InferIsLocal::BrokenYes => true
338+
ty::TyInfer(..) => match in_crate {
339+
InCrate::Local => false,
340+
// The inference variable might be unified with a local
341+
// type in that remote crate.
342+
InCrate::Remote => true,
337343
},
338344

339-
ty::TyAdt(def, _) => def_id_is_local(def.did, infer_is_local),
340-
ty::TyForeign(did) => def_id_is_local(did, infer_is_local),
345+
ty::TyAdt(def, _) => def_id_is_local(def.did, in_crate),
346+
ty::TyForeign(did) => def_id_is_local(did, in_crate),
341347

342348
ty::TyDynamic(ref tt, ..) => {
343349
tt.principal().map_or(false, |p| {
344-
def_id_is_local(p.def_id(), infer_is_local)
350+
def_id_is_local(p.def_id(), in_crate)
345351
})
346352
}
347353

src/librustc/traits/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ mod structural_impls;
6060
pub mod trans;
6161
mod util;
6262

63+
#[derive(Copy, Clone, Debug)]
64+
pub enum IntercrateMode {
65+
Issue43355,
66+
Fixed
67+
}
68+
6369
/// An `Obligation` represents some trait reference (e.g. `int:Eq`) for
6470
/// which the vtable must be found. The process of finding a vtable is
6571
/// called "resolving" the `Obligation`. This process consists of

src/librustc/traits/select.rs

+30-25
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use self::SelectionCandidate::*;
1414
use self::EvaluationResult::*;
1515

16-
use super::coherence;
16+
use super::coherence::{self, Conflict};
1717
use super::DerivedObligationCause;
1818
use super::project;
1919
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
@@ -1077,28 +1077,33 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
10771077
return Ok(None);
10781078
}
10791079

1080-
if !self.is_knowable(stack) {
1081-
debug!("coherence stage: not knowable");
1082-
// Heuristics: show the diagnostics when there are no candidates in crate.
1083-
let candidate_set = self.assemble_candidates(stack)?;
1084-
if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
1085-
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
1086-
let self_ty = trait_ref.self_ty();
1087-
let trait_desc = trait_ref.to_string();
1088-
let self_desc = if self_ty.has_concrete_skeleton() {
1089-
Some(self_ty.to_string())
1090-
} else {
1091-
None
1092-
};
1093-
let cause = if !coherence::trait_ref_is_local_or_fundamental(self.tcx(),
1094-
trait_ref) {
1095-
IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
1096-
} else {
1097-
IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
1098-
};
1099-
self.intercrate_ambiguity_causes.push(cause);
1080+
match self.is_knowable(stack) {
1081+
Some(Conflict::Downstream { used_to_be_broken: true }) if false => {
1082+
// ignore this for future-compat.
1083+
}
1084+
None => {}
1085+
Some(conflict) => {
1086+
debug!("coherence stage: not knowable");
1087+
// Heuristics: show the diagnostics when there are no candidates in crate.
1088+
let candidate_set = self.assemble_candidates(stack)?;
1089+
if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
1090+
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
1091+
let self_ty = trait_ref.self_ty();
1092+
let trait_desc = trait_ref.to_string();
1093+
let self_desc = if self_ty.has_concrete_skeleton() {
1094+
Some(self_ty.to_string())
1095+
} else {
1096+
None
1097+
};
1098+
let cause = if let Conflict::Upstream = conflict {
1099+
IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
1100+
} else {
1101+
IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
1102+
};
1103+
self.intercrate_ambiguity_causes.push(cause);
1104+
}
1105+
return Ok(None);
11001106
}
1101-
return Ok(None);
11021107
}
11031108

11041109
let candidate_set = self.assemble_candidates(stack)?;
@@ -1205,12 +1210,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
12051210

12061211
fn is_knowable<'o>(&mut self,
12071212
stack: &TraitObligationStack<'o, 'tcx>)
1208-
-> bool
1213+
-> Option<Conflict>
12091214
{
12101215
debug!("is_knowable(intercrate={})", self.intercrate);
12111216

12121217
if !self.intercrate {
1213-
return true;
1218+
return None;
12141219
}
12151220

12161221
let obligation = &stack.obligation;
@@ -1221,7 +1226,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
12211226
// bound regions
12221227
let trait_ref = predicate.skip_binder().trait_ref;
12231228

1224-
coherence::trait_ref_is_knowable(self.tcx(), trait_ref, false).is_none()
1229+
coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
12251230
}
12261231

12271232
/// Returns true if the global caches can be used.

src/test/compile-fail/issue-43355.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub trait Trait1<X> {
12+
type Output;
13+
}
14+
15+
pub trait Trait2<X> {}
16+
17+
pub struct A;
18+
19+
impl<X, T> Trait1<X> for T where T: Trait2<X> {
20+
type Output = ();
21+
}
22+
23+
impl<X> Trait1<Box<X>> for A {
24+
//~^ ERROR conflicting implementations of trait
25+
//~| downstream crates may implement trait `Trait2<std::boxed::Box<_>>` for type `A`
26+
type Output = i32;
27+
}
28+
29+
fn main() {}

0 commit comments

Comments
 (0)