rust/src/librustc/traits/coherence.rs

286 lines
9.9 KiB
Rust
Raw Normal View History

// Copyright 2014 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.
//! See `README.md` for high-level documentation
use super::{SelectionContext, Obligation, ObligationCause};
use hir::def_id::{DefId, LOCAL_CRATE};
use ty::{self, Ty, TyCtxt};
use infer::{InferCtxt, InferOk, TypeOrigin};
use syntax_pos::DUMMY_SP;
2015-04-01 18:44:53 -07:00
#[derive(Copy, Clone)]
struct InferIsLocal(bool);
/// If there are types that satisfy both impls, returns a suitably-freshened
/// `ImplHeader` with those types substituted
pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
impl1_def_id: DefId,
impl2_def_id: DefId)
-> Option<ty::ImplHeader<'tcx>>
{
debug!("impl_can_satisfy(\
2015-06-18 20:25:05 +03:00
impl1_def_id={:?}, \
impl2_def_id={:?})",
impl1_def_id,
impl2_def_id);
let selcx = &mut SelectionContext::intercrate(infcx);
overlap(selcx, impl1_def_id, impl2_def_id)
}
/// Can both impl `a` and impl `b` be satisfied by a common type (including
/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls.
fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
a_def_id: DefId,
b_def_id: DefId)
-> Option<ty::ImplHeader<'tcx>>
{
2015-06-18 20:25:05 +03:00
debug!("overlap(a_def_id={:?}, b_def_id={:?})",
a_def_id,
b_def_id);
2015-02-23 13:02:31 -05:00
let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id);
let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id);
debug!("overlap: a_impl_header={:?}", a_impl_header);
debug!("overlap: b_impl_header={:?}", b_impl_header);
2015-02-23 13:02:31 -05:00
// Do `a` and `b` unify? If not, no overlap.
match selcx.infcx().eq_impl_headers(true, TypeOrigin::Misc(DUMMY_SP), &a_impl_header,
&b_impl_header) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
}
Err(_) => return None
}
debug!("overlap: unification check succeeded");
2015-02-23 13:02:31 -05:00
// Are any of the obligations unsatisfiable? If so, no overlap.
let infcx = selcx.infcx();
2015-02-23 13:02:31 -05:00
let opt_failing_obligation =
a_impl_header.predicates
.iter()
.chain(&b_impl_header.predicates)
.map(|p| infcx.resolve_type_vars_if_possible(p))
.map(|p| Obligation { cause: ObligationCause::dummy(),
recursion_depth: 0,
predicate: p })
2015-02-23 13:02:31 -05:00
.find(|o| !selcx.evaluate_obligation(o));
if let Some(failing_obligation) = opt_failing_obligation {
2015-06-18 20:25:05 +03:00
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
return None
2015-02-23 13:02:31 -05:00
}
Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header))
}
pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
trait_ref: &ty::TraitRef<'tcx>) -> bool
{
2015-06-18 20:25:05 +03:00
debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
// 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 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
2015-08-16 06:32:28 -04:00
trait_ref.def_id.krate != LOCAL_CRATE &&
!tcx.has_attr(trait_ref.def_id, "fundamental")
{
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()
}
Implement new orphan rule that requires that impls of remote traits meet the following two criteria: - the self type includes some local type; and, - type parameters in the self type must be constrained by a local type. A type parameter is called *constrained* if it appears in some type-parameter of a local type. Here are some examples that are accepted. In all of these examples, I assume that `Foo` is a trait defined in another crate. If `Foo` were defined in the local crate, then all the examples would be legal. - `impl Foo for LocalType` - `impl<T> Foo<T> for LocalType` -- T does not appear in Self, so it is OK - `impl<T> Foo<T> for LocalType<T>` -- T here is constrained by LocalType - `impl<T> Foo<T> for (LocalType<T>, T)` -- T here is constrained by LocalType Here are some illegal examples (again, these examples assume that `Foo` is not local to the current crate): - `impl Foo for int` -- the Self type is not local - `impl<T> Foo for T` -- T appears in Self unconstrained by a local type - `impl<T> Foo for (LocalType, T)` -- T appears in Self unconstrained by a local type This is a [breaking-change]. For the time being, you can opt out of the new rules by placing `#[old_orphan_check]` on the trait (and enabling the feature gate where the trait is defined). Longer term, you should restructure your traits to avoid the problem. Usually this means changing the order of parameters so that the "central" type parameter is in the `Self` position. As an example of that refactoring, consider the `BorrowFrom` trait: ```rust pub trait BorrowFrom<Sized? Owned> for Sized? { fn borrow_from(owned: &Owned) -> &Self; } ``` As defined, this trait is commonly implemented for custom pointer types, such as `Arc`. Those impls follow the pattern: ```rust impl<T> BorrowFrom<Arc<T>> for T {...} ``` Unfortunately, this impl is illegal because the self type `T` is not local to the current crate. Therefore, we are going to change the order of the parameters, so that `BorrowFrom` becomes `Borrow`: ```rust pub trait Borrow<Sized? Borrowed> for Sized? { fn borrow_from(owned: &Self) -> &Borrowed; } ``` Now the `Arc` impl is written: ```rust impl<T> Borrow<T> for Arc<T> { ... } ``` This impl is legal because the self type (`Arc<T>`) is local.
2015-01-04 20:35:06 -05:00
pub enum OrphanCheckErr<'tcx> {
Fix orphan checking (cc #19470). (This is not a complete fix of #19470 because of the backwards compatibility feature gate.) This is a [breaking-change]. The new rules require that, for an impl of a trait defined in some other crate, two conditions must hold: 1. Some type must be local. 2. Every type parameter must appear "under" some local type. Here are some examples that are legal: ```rust struct MyStruct<T> { ... } // Here `T` appears "under' `MyStruct`. impl<T> Clone for MyStruct<T> { } // Here `T` appears "under' `MyStruct` as well. Note that it also appears // elsewhere. impl<T> Iterator<T> for MyStruct<T> { } ``` Here is an illegal example: ```rust // Here `U` does not appear "under" `MyStruct` or any other local type. // We call `U` "uncovered". impl<T,U> Iterator<U> for MyStruct<T> { } ``` There are a couple of ways to rewrite this last example so that it is legal: 1. In some cases, the uncovered type parameter (here, `U`) should be converted into an associated type. This is however a non-local change that requires access to the original trait. Also, associated types are not fully baked. 2. Add `U` as a type parameter of `MyStruct`: ```rust struct MyStruct<T,U> { ... } impl<T,U> Iterator<U> for MyStruct<T,U> { } ``` 3. Create a newtype wrapper for `U` ```rust impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { } ``` Because associated types are not fully baked, which in the case of the `Hash` trait makes adhering to this rule impossible, you can temporarily disable this rule in your crate by using `#![feature(old_orphan_check)]`. Note that the `old_orphan_check` feature will be removed before 1.0 is released.
2014-12-26 03:30:51 -05:00
NoLocalInputType,
Implement new orphan rule that requires that impls of remote traits meet the following two criteria: - the self type includes some local type; and, - type parameters in the self type must be constrained by a local type. A type parameter is called *constrained* if it appears in some type-parameter of a local type. Here are some examples that are accepted. In all of these examples, I assume that `Foo` is a trait defined in another crate. If `Foo` were defined in the local crate, then all the examples would be legal. - `impl Foo for LocalType` - `impl<T> Foo<T> for LocalType` -- T does not appear in Self, so it is OK - `impl<T> Foo<T> for LocalType<T>` -- T here is constrained by LocalType - `impl<T> Foo<T> for (LocalType<T>, T)` -- T here is constrained by LocalType Here are some illegal examples (again, these examples assume that `Foo` is not local to the current crate): - `impl Foo for int` -- the Self type is not local - `impl<T> Foo for T` -- T appears in Self unconstrained by a local type - `impl<T> Foo for (LocalType, T)` -- T appears in Self unconstrained by a local type This is a [breaking-change]. For the time being, you can opt out of the new rules by placing `#[old_orphan_check]` on the trait (and enabling the feature gate where the trait is defined). Longer term, you should restructure your traits to avoid the problem. Usually this means changing the order of parameters so that the "central" type parameter is in the `Self` position. As an example of that refactoring, consider the `BorrowFrom` trait: ```rust pub trait BorrowFrom<Sized? Owned> for Sized? { fn borrow_from(owned: &Owned) -> &Self; } ``` As defined, this trait is commonly implemented for custom pointer types, such as `Arc`. Those impls follow the pattern: ```rust impl<T> BorrowFrom<Arc<T>> for T {...} ``` Unfortunately, this impl is illegal because the self type `T` is not local to the current crate. Therefore, we are going to change the order of the parameters, so that `BorrowFrom` becomes `Borrow`: ```rust pub trait Borrow<Sized? Borrowed> for Sized? { fn borrow_from(owned: &Self) -> &Borrowed; } ``` Now the `Arc` impl is written: ```rust impl<T> Borrow<T> for Arc<T> { ... } ``` This impl is legal because the self type (`Arc<T>`) is local.
2015-01-04 20:35:06 -05:00
UncoveredTy(Ty<'tcx>),
Fix orphan checking (cc #19470). (This is not a complete fix of #19470 because of the backwards compatibility feature gate.) This is a [breaking-change]. The new rules require that, for an impl of a trait defined in some other crate, two conditions must hold: 1. Some type must be local. 2. Every type parameter must appear "under" some local type. Here are some examples that are legal: ```rust struct MyStruct<T> { ... } // Here `T` appears "under' `MyStruct`. impl<T> Clone for MyStruct<T> { } // Here `T` appears "under' `MyStruct` as well. Note that it also appears // elsewhere. impl<T> Iterator<T> for MyStruct<T> { } ``` Here is an illegal example: ```rust // Here `U` does not appear "under" `MyStruct` or any other local type. // We call `U` "uncovered". impl<T,U> Iterator<U> for MyStruct<T> { } ``` There are a couple of ways to rewrite this last example so that it is legal: 1. In some cases, the uncovered type parameter (here, `U`) should be converted into an associated type. This is however a non-local change that requires access to the original trait. Also, associated types are not fully baked. 2. Add `U` as a type parameter of `MyStruct`: ```rust struct MyStruct<T,U> { ... } impl<T,U> Iterator<U> for MyStruct<T,U> { } ``` 3. Create a newtype wrapper for `U` ```rust impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { } ``` Because associated types are not fully baked, which in the case of the `Hash` trait makes adhering to this rule impossible, you can temporarily disable this rule in your crate by using `#![feature(old_orphan_check)]`. Note that the `old_orphan_check` feature will be removed before 1.0 is released.
2014-12-26 03:30:51 -05:00
}
/// Checks the coherence orphan rules. `impl_def_id` should be the
/// def-id of a trait impl. To pass, either the trait must be local, or else
/// two conditions must be satisfied:
///
Implement new orphan rule that requires that impls of remote traits meet the following two criteria: - the self type includes some local type; and, - type parameters in the self type must be constrained by a local type. A type parameter is called *constrained* if it appears in some type-parameter of a local type. Here are some examples that are accepted. In all of these examples, I assume that `Foo` is a trait defined in another crate. If `Foo` were defined in the local crate, then all the examples would be legal. - `impl Foo for LocalType` - `impl<T> Foo<T> for LocalType` -- T does not appear in Self, so it is OK - `impl<T> Foo<T> for LocalType<T>` -- T here is constrained by LocalType - `impl<T> Foo<T> for (LocalType<T>, T)` -- T here is constrained by LocalType Here are some illegal examples (again, these examples assume that `Foo` is not local to the current crate): - `impl Foo for int` -- the Self type is not local - `impl<T> Foo for T` -- T appears in Self unconstrained by a local type - `impl<T> Foo for (LocalType, T)` -- T appears in Self unconstrained by a local type This is a [breaking-change]. For the time being, you can opt out of the new rules by placing `#[old_orphan_check]` on the trait (and enabling the feature gate where the trait is defined). Longer term, you should restructure your traits to avoid the problem. Usually this means changing the order of parameters so that the "central" type parameter is in the `Self` position. As an example of that refactoring, consider the `BorrowFrom` trait: ```rust pub trait BorrowFrom<Sized? Owned> for Sized? { fn borrow_from(owned: &Owned) -> &Self; } ``` As defined, this trait is commonly implemented for custom pointer types, such as `Arc`. Those impls follow the pattern: ```rust impl<T> BorrowFrom<Arc<T>> for T {...} ``` Unfortunately, this impl is illegal because the self type `T` is not local to the current crate. Therefore, we are going to change the order of the parameters, so that `BorrowFrom` becomes `Borrow`: ```rust pub trait Borrow<Sized? Borrowed> for Sized? { fn borrow_from(owned: &Self) -> &Borrowed; } ``` Now the `Arc` impl is written: ```rust impl<T> Borrow<T> for Arc<T> { ... } ``` This impl is legal because the self type (`Arc<T>`) is local.
2015-01-04 20:35:06 -05:00
/// 1. All type parameters in `Self` must be "covered" by some local type constructor.
/// 2. Some local type must appear in `Self`.
pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
impl_def_id: DefId)
-> Result<(), OrphanCheckErr<'tcx>>
{
2015-06-18 20:25:05 +03:00
debug!("orphan_check({:?})", impl_def_id);
// We only except this routine to be invoked on implementations
// of a trait, not inherent implementations.
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
2015-06-18 20:25:05 +03:00
debug!("orphan_check: trait_ref={:?}", trait_ref);
Fix orphan checking (cc #19470). (This is not a complete fix of #19470 because of the backwards compatibility feature gate.) This is a [breaking-change]. The new rules require that, for an impl of a trait defined in some other crate, two conditions must hold: 1. Some type must be local. 2. Every type parameter must appear "under" some local type. Here are some examples that are legal: ```rust struct MyStruct<T> { ... } // Here `T` appears "under' `MyStruct`. impl<T> Clone for MyStruct<T> { } // Here `T` appears "under' `MyStruct` as well. Note that it also appears // elsewhere. impl<T> Iterator<T> for MyStruct<T> { } ``` Here is an illegal example: ```rust // Here `U` does not appear "under" `MyStruct` or any other local type. // We call `U` "uncovered". impl<T,U> Iterator<U> for MyStruct<T> { } ``` There are a couple of ways to rewrite this last example so that it is legal: 1. In some cases, the uncovered type parameter (here, `U`) should be converted into an associated type. This is however a non-local change that requires access to the original trait. Also, associated types are not fully baked. 2. Add `U` as a type parameter of `MyStruct`: ```rust struct MyStruct<T,U> { ... } impl<T,U> Iterator<U> for MyStruct<T,U> { } ``` 3. Create a newtype wrapper for `U` ```rust impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { } ``` Because associated types are not fully baked, which in the case of the `Hash` trait makes adhering to this rule impossible, you can temporarily disable this rule in your crate by using `#![feature(old_orphan_check)]`. Note that the `old_orphan_check` feature will be removed before 1.0 is released.
2014-12-26 03:30:51 -05:00
// If the *trait* is local to the crate, ok.
if trait_ref.def_id.is_local() {
2015-06-18 20:25:05 +03:00
debug!("trait {:?} is local to current crate",
trait_ref.def_id);
Fix orphan checking (cc #19470). (This is not a complete fix of #19470 because of the backwards compatibility feature gate.) This is a [breaking-change]. The new rules require that, for an impl of a trait defined in some other crate, two conditions must hold: 1. Some type must be local. 2. Every type parameter must appear "under" some local type. Here are some examples that are legal: ```rust struct MyStruct<T> { ... } // Here `T` appears "under' `MyStruct`. impl<T> Clone for MyStruct<T> { } // Here `T` appears "under' `MyStruct` as well. Note that it also appears // elsewhere. impl<T> Iterator<T> for MyStruct<T> { } ``` Here is an illegal example: ```rust // Here `U` does not appear "under" `MyStruct` or any other local type. // We call `U` "uncovered". impl<T,U> Iterator<U> for MyStruct<T> { } ``` There are a couple of ways to rewrite this last example so that it is legal: 1. In some cases, the uncovered type parameter (here, `U`) should be converted into an associated type. This is however a non-local change that requires access to the original trait. Also, associated types are not fully baked. 2. Add `U` as a type parameter of `MyStruct`: ```rust struct MyStruct<T,U> { ... } impl<T,U> Iterator<U> for MyStruct<T,U> { } ``` 3. Create a newtype wrapper for `U` ```rust impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { } ``` Because associated types are not fully baked, which in the case of the `Hash` trait makes adhering to this rule impossible, you can temporarily disable this rule in your crate by using `#![feature(old_orphan_check)]`. Note that the `old_orphan_check` feature will be removed before 1.0 is released.
2014-12-26 03:30:51 -05:00
return Ok(());
}
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>>
{
2015-06-18 20:25:05 +03:00
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.
// Find the first input type that either references a type parameter OR
// some local type.
for input_ty in trait_ref.input_types() {
if ty_is_local(tcx, input_ty, infer_is_local) {
2015-06-18 20:25:05 +03:00
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
// First local input type. Check that there are no
// 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_type_parameter(t)) {
2015-06-18 20:25:05 +03:00
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
return Err(OrphanCheckErr::UncoveredTy(param));
}
}
// OK, found local type, all prior types upheld invariant.
return Ok(());
}
// Otherwise, enforce invariant that there are no type
// parameters reachable.
if !infer_is_local.0 {
if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) {
2015-06-18 20:25:05 +03:00
debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
return Err(OrphanCheckErr::UncoveredTy(param));
}
}
Fix orphan checking (cc #19470). (This is not a complete fix of #19470 because of the backwards compatibility feature gate.) This is a [breaking-change]. The new rules require that, for an impl of a trait defined in some other crate, two conditions must hold: 1. Some type must be local. 2. Every type parameter must appear "under" some local type. Here are some examples that are legal: ```rust struct MyStruct<T> { ... } // Here `T` appears "under' `MyStruct`. impl<T> Clone for MyStruct<T> { } // Here `T` appears "under' `MyStruct` as well. Note that it also appears // elsewhere. impl<T> Iterator<T> for MyStruct<T> { } ``` Here is an illegal example: ```rust // Here `U` does not appear "under" `MyStruct` or any other local type. // We call `U` "uncovered". impl<T,U> Iterator<U> for MyStruct<T> { } ``` There are a couple of ways to rewrite this last example so that it is legal: 1. In some cases, the uncovered type parameter (here, `U`) should be converted into an associated type. This is however a non-local change that requires access to the original trait. Also, associated types are not fully baked. 2. Add `U` as a type parameter of `MyStruct`: ```rust struct MyStruct<T,U> { ... } impl<T,U> Iterator<U> for MyStruct<T,U> { } ``` 3. Create a newtype wrapper for `U` ```rust impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { } ``` Because associated types are not fully baked, which in the case of the `Hash` trait makes adhering to this rule impossible, you can temporarily disable this rule in your crate by using `#![feature(old_orphan_check)]`. Note that the `old_orphan_check` feature will be removed before 1.0 is released.
2014-12-26 03:30:51 -05:00
}
// If we exit above loop, never found a local type.
debug!("orphan_check_trait_ref: no local type");
return Err(OrphanCheckErr::NoLocalInputType);
}
fn uncovered_tys<'tcx>(tcx: TyCtxt, ty: Ty<'tcx>, infer_is_local: InferIsLocal)
-> Vec<Ty<'tcx>> {
if ty_is_local_constructor(tcx, ty, infer_is_local) {
vec![]
} else if fundamental_ty(tcx, ty) {
ty.walk_shallow()
.flat_map(|t| uncovered_tys(tcx, t, infer_is_local))
.collect()
} else {
vec![ty]
}
Fix orphan checking (cc #19470). (This is not a complete fix of #19470 because of the backwards compatibility feature gate.) This is a [breaking-change]. The new rules require that, for an impl of a trait defined in some other crate, two conditions must hold: 1. Some type must be local. 2. Every type parameter must appear "under" some local type. Here are some examples that are legal: ```rust struct MyStruct<T> { ... } // Here `T` appears "under' `MyStruct`. impl<T> Clone for MyStruct<T> { } // Here `T` appears "under' `MyStruct` as well. Note that it also appears // elsewhere. impl<T> Iterator<T> for MyStruct<T> { } ``` Here is an illegal example: ```rust // Here `U` does not appear "under" `MyStruct` or any other local type. // We call `U` "uncovered". impl<T,U> Iterator<U> for MyStruct<T> { } ``` There are a couple of ways to rewrite this last example so that it is legal: 1. In some cases, the uncovered type parameter (here, `U`) should be converted into an associated type. This is however a non-local change that requires access to the original trait. Also, associated types are not fully baked. 2. Add `U` as a type parameter of `MyStruct`: ```rust struct MyStruct<T,U> { ... } impl<T,U> Iterator<U> for MyStruct<T,U> { } ``` 3. Create a newtype wrapper for `U` ```rust impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { } ``` Because associated types are not fully baked, which in the case of the `Hash` trait makes adhering to this rule impossible, you can temporarily disable this rule in your crate by using `#![feature(old_orphan_check)]`. Note that the `old_orphan_check` feature will be removed before 1.0 is released.
2014-12-26 03:30:51 -05:00
}
fn is_type_parameter(ty: Ty) -> bool {
match ty.sty {
// FIXME(#20590) straighten story about projection types
ty::TyProjection(..) | ty::TyParam(..) => true,
_ => false,
}
}
fn ty_is_local(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal) -> bool {
ty_is_local_constructor(tcx, ty, infer_is_local) ||
fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, infer_is_local))
}
fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool {
match ty.sty {
ty::TyBox(..) | ty::TyRef(..) =>
true,
ty::TyAdt(def, _) =>
2015-08-07 14:41:33 +03:00
def.is_fundamental(),
ty::TyTrait(ref data) =>
tcx.has_attr(data.principal.def_id(), "fundamental"),
_ =>
false
}
}
fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> bool {
2015-06-18 20:25:05 +03:00
debug!("ty_is_local_constructor({:?})", ty);
match ty.sty {
ty::TyBool |
ty::TyChar |
ty::TyInt(..) |
ty::TyUint(..) |
ty::TyFloat(..) |
2015-10-26 21:10:41 +03:00
ty::TyStr |
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
ty::TyArray(..) |
ty::TySlice(..) |
ty::TyRawPtr(..) |
ty::TyRef(..) |
ty::TyNever |
ty::TyTuple(..) |
ty::TyParam(..) |
ty::TyProjection(..) => {
false
}
ty::TyInfer(..) => {
infer_is_local.0
}
ty::TyAdt(def, _) => {
def.did.is_local()
}
ty::TyBox(_) => { // Box<T>
Fix orphan checking (cc #19470). (This is not a complete fix of #19470 because of the backwards compatibility feature gate.) This is a [breaking-change]. The new rules require that, for an impl of a trait defined in some other crate, two conditions must hold: 1. Some type must be local. 2. Every type parameter must appear "under" some local type. Here are some examples that are legal: ```rust struct MyStruct<T> { ... } // Here `T` appears "under' `MyStruct`. impl<T> Clone for MyStruct<T> { } // Here `T` appears "under' `MyStruct` as well. Note that it also appears // elsewhere. impl<T> Iterator<T> for MyStruct<T> { } ``` Here is an illegal example: ```rust // Here `U` does not appear "under" `MyStruct` or any other local type. // We call `U` "uncovered". impl<T,U> Iterator<U> for MyStruct<T> { } ``` There are a couple of ways to rewrite this last example so that it is legal: 1. In some cases, the uncovered type parameter (here, `U`) should be converted into an associated type. This is however a non-local change that requires access to the original trait. Also, associated types are not fully baked. 2. Add `U` as a type parameter of `MyStruct`: ```rust struct MyStruct<T,U> { ... } impl<T,U> Iterator<U> for MyStruct<T,U> { } ``` 3. Create a newtype wrapper for `U` ```rust impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { } ``` Because associated types are not fully baked, which in the case of the `Hash` trait makes adhering to this rule impossible, you can temporarily disable this rule in your crate by using `#![feature(old_orphan_check)]`. Note that the `old_orphan_check` feature will be removed before 1.0 is released.
2014-12-26 03:30:51 -05:00
let krate = tcx.lang_items.owned_box().map(|d| d.krate);
2015-08-16 06:32:28 -04:00
krate == Some(LOCAL_CRATE)
}
ty::TyTrait(ref tt) => {
tt.principal.def_id().is_local()
}
ty::TyError => {
true
}
ty::TyClosure(..) | ty::TyAnon(..) => {
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
}
}
}