Skip to content

Commit

Permalink
Revert "fix treatment of local types in "remote coherence" mode"
Browse files Browse the repository at this point in the history
That commit had accidentally snuck in into rust-lang#44884. Revert it.

This reverts commit c48650e.
  • Loading branch information
arielb1 committed Nov 28, 2017
1 parent 7745a7a commit bef4fe9
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 81 deletions.
125 changes: 46 additions & 79 deletions src/librustc/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,8 @@ use ty::subst::Subst;

use infer::{InferCtxt, InferOk};

#[derive(Copy, Clone, Debug)]
enum InferIsLocal {
BrokenYes,
Yes,
No
}

#[derive(Debug, Copy, Clone)]
pub enum Conflict {
Upstream,
Downstream
}
#[derive(Copy, Clone)]
struct InferIsLocal(bool);

pub struct OverlapResult<'tcx> {
pub impl_header: ty::ImplHeader<'tcx>,
Expand Down Expand Up @@ -136,46 +126,32 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
}

pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
trait_ref: ty::TraitRef<'tcx>,
broken: bool)
-> Option<Conflict>
trait_ref: ty::TraitRef<'tcx>) -> bool
{
debug!("trait_ref_is_knowable(trait_ref={:?}, broken={:?})", trait_ref, broken);
let mode = if broken {
InferIsLocal::BrokenYes
} else {
InferIsLocal::Yes
};
if orphan_check_trait_ref(tcx, trait_ref, mode).is_ok() {
// A downstream or cousin crate is allowed to implement some
// substitution of this trait-ref.
debug!("trait_ref_is_knowable: downstream crate might implement");
return Some(Conflict::Downstream);
}
debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);

if trait_ref_is_local_or_fundamental(tcx, trait_ref) {
// This is a local or fundamental trait, so future-compatibility
// is no concern. We know that downstream/cousin crates are not
// allowed to implement a substitution of this trait ref, which
// means impls could only come from dependencies of this crate,
// which we already know about.
return None;
}
// This is a remote non-fundamental trait, so if another crate
// can be the "final owner" of a substitution of this trait-ref,
// they are allowed to implement it future-compatibly.
//
// However, if we are a final owner, then nobody else can be,
// and if we are an intermediate owner, then we don't care
// about future-compatibility, which means that we're OK if
// we are an owner.
if orphan_check_trait_ref(tcx, trait_ref, InferIsLocal::No).is_ok() {
// if the orphan rules pass, that means that no ancestor crate can
// impl this, so it's up to us.
if orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(false)).is_ok() {
debug!("trait_ref_is_knowable: orphan check passed");
return None;
} else {
debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned");
return Some(Conflict::Upstream);
return true;
}

// if the trait is not marked fundamental, then it's always possible that
// an ancestor crate will impl this in the future, if they haven't
// already
if !trait_ref_is_local_or_fundamental(tcx, trait_ref) {
debug!("trait_ref_is_knowable: trait is neither local nor fundamental");
return false;
}

// find out when some downstream (or cousin) crate could impl this
// trait-ref, presuming that all the parameters were instantiated
// with downstream types. If not, then it could only be
// implemented by an upstream crate, which means that the impl
// must be visible to us, and -- since the trait is fundamental
// -- we can test.
orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err()
}

pub fn trait_ref_is_local_or_fundamental<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
Expand Down Expand Up @@ -213,16 +189,16 @@ pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
return Ok(());
}

orphan_check_trait_ref(tcx, trait_ref, InferIsLocal::No)
orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(false))
}

fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
trait_ref: ty::TraitRef<'tcx>,
infer_is_local: InferIsLocal)
-> Result<(), OrphanCheckErr<'tcx>>
{
debug!("orphan_check_trait_ref(trait_ref={:?}, infer_is_local={:?})",
trait_ref, infer_is_local);
debug!("orphan_check_trait_ref(trait_ref={:?}, infer_is_local={})",
trait_ref, infer_is_local.0);

// First, create an ordered iterator over all the type parameters to the trait, with the self
// type appearing first.
Expand All @@ -236,9 +212,7 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
// uncovered type parameters.
let uncovered_tys = uncovered_tys(tcx, input_ty, infer_is_local);
for uncovered_ty in uncovered_tys {
if let Some(param) = uncovered_ty.walk()
.find(|t| is_possibly_remote_type(t, infer_is_local))
{
if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) {
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
return Err(OrphanCheckErr::UncoveredTy(param));
}
Expand All @@ -250,11 +224,11 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,

// Otherwise, enforce invariant that there are no type
// parameters reachable.
if let Some(param) = input_ty.walk()
.find(|t| is_possibly_remote_type(t, infer_is_local))
{
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
return Err(OrphanCheckErr::UncoveredTy(param));
if !infer_is_local.0 {
if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) {
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
return Err(OrphanCheckErr::UncoveredTy(param));
}
}
}

Expand All @@ -276,7 +250,7 @@ fn uncovered_tys<'tcx>(tcx: TyCtxt, ty: Ty<'tcx>, infer_is_local: InferIsLocal)
}
}

fn is_possibly_remote_type(ty: Ty, _infer_is_local: InferIsLocal) -> bool {
fn is_type_parameter(ty: Ty) -> bool {
match ty.sty {
ty::TyProjection(..) | ty::TyParam(..) => true,
_ => false,
Expand All @@ -299,15 +273,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool {
}
}

fn def_id_is_local(def_id: DefId, infer_is_local: InferIsLocal) -> bool {
match infer_is_local {
InferIsLocal::Yes => false,
InferIsLocal::No |
InferIsLocal::BrokenYes => def_id.is_local()
}
}

fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal) -> bool {
fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal)-> bool {
debug!("ty_is_local_constructor({:?})", ty);

match ty.sty {
Expand All @@ -330,19 +296,20 @@ fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal) -> bool {
false
}

ty::TyInfer(..) => match infer_is_local {
InferIsLocal::No => false,
InferIsLocal::Yes |
InferIsLocal::BrokenYes => true
},
ty::TyInfer(..) => {
infer_is_local.0
}

ty::TyAdt(def, _) => {
def.did.is_local()
}

ty::TyAdt(def, _) => def_id_is_local(def.did, infer_is_local),
ty::TyForeign(did) => def_id_is_local(did, infer_is_local),
ty::TyForeign(did) => {
did.is_local()
}

ty::TyDynamic(ref tt, ..) => {
tt.principal().map_or(false, |p| {
def_id_is_local(p.def_id(), infer_is_local)
})
tt.principal().map_or(false, |p| p.def_id().is_local())
}

ty::TyError => {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// terms of `Fn` etc, but we could probably make this more
// precise still.
let unbound_input_types = stack.fresh_trait_ref.input_types().any(|ty| ty.is_fresh());
if unbound_input_types && self.intercrate && false {
if unbound_input_types && self.intercrate {
debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
stack.fresh_trait_ref);
// Heuristics: show the diagnostics when there are no candidates in crate.
Expand Down Expand Up @@ -1221,7 +1221,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// bound regions
let trait_ref = predicate.skip_binder().trait_ref;

coherence::trait_ref_is_knowable(self.tcx(), trait_ref, false).is_none()
coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
}

/// Returns true if the global caches can be used.
Expand Down

0 comments on commit bef4fe9

Please sign in to comment.