auto merge of #17669 : nikomatsakis/rust/multidispatch, r=pcwalton
Implement multidispatch and conditional dispatch. Because we do not attempt to preserve crate concatenation, this is a backwards compatible change. This is not yet fully integrated into method dispatch, so "UFCS"-style wrappers must be used to take advantage of the new features (see the run-pass tests). cc #17307 (multidispatch) cc #5527 (trait reform -- conditional dispatch) Because we no longer preserve crate concatenability, this deviates slightly from what was specified in the RFC. The motivation for this change is described in [this blog post](http://smallcultfollowing.com/babysteps/blog/2014/09/30/multi-and-conditional-dispatch-in-traits/). I will post an amendment to the RFC in due course but do not anticipate great controversy on this point -- particularly as the RFCs more important features (e.g., conditional dispatch) just don't work without the change.
This commit is contained in:
commit
b74208bc12
35 changed files with 1589 additions and 757 deletions
|
@ -417,6 +417,10 @@ impl<T> VecPerParamSpace<T> {
|
||||||
self.content.iter()
|
self.content.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_slice(&self) -> &[T] {
|
||||||
|
self.content.as_slice()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn all_vecs(&self, pred: |&[T]| -> bool) -> bool {
|
pub fn all_vecs(&self, pred: |&[T]| -> bool) -> bool {
|
||||||
let spaces = [TypeSpace, SelfSpace, FnSpace];
|
let spaces = [TypeSpace, SelfSpace, FnSpace];
|
||||||
spaces.iter().all(|&space| { pred(self.get_slice(space)) })
|
spaces.iter().all(|&space| { pred(self.get_slice(space)) })
|
||||||
|
|
|
@ -10,9 +10,8 @@
|
||||||
|
|
||||||
/*! See `doc.rs` for high-level documentation */
|
/*! See `doc.rs` for high-level documentation */
|
||||||
|
|
||||||
use super::{EvaluatedToMatch, EvaluatedToAmbiguity, EvaluatedToUnmatch};
|
use super::SelectionContext;
|
||||||
use super::{evaluate_impl};
|
use super::Obligation;
|
||||||
use super::ObligationCause;
|
|
||||||
use super::util;
|
use super::util;
|
||||||
|
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
|
@ -28,22 +27,26 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
|
||||||
impl2_def_id: ast::DefId)
|
impl2_def_id: ast::DefId)
|
||||||
-> bool
|
-> bool
|
||||||
{
|
{
|
||||||
|
debug!("impl_can_satisfy(\
|
||||||
|
impl1_def_id={}, \
|
||||||
|
impl2_def_id={})",
|
||||||
|
impl1_def_id.repr(infcx.tcx),
|
||||||
|
impl2_def_id.repr(infcx.tcx));
|
||||||
|
|
||||||
// `impl1` provides an implementation of `Foo<X,Y> for Z`.
|
// `impl1` provides an implementation of `Foo<X,Y> for Z`.
|
||||||
let impl1_substs =
|
let impl1_substs =
|
||||||
util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id);
|
util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id);
|
||||||
let impl1_self_ty =
|
let impl1_trait_ref =
|
||||||
ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()
|
ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()
|
||||||
.self_ty()
|
|
||||||
.subst(infcx.tcx, &impl1_substs);
|
.subst(infcx.tcx, &impl1_substs);
|
||||||
|
|
||||||
// Determine whether `impl2` can provide an implementation for those
|
// Determine whether `impl2` can provide an implementation for those
|
||||||
// same types.
|
// same types.
|
||||||
let param_env = ty::empty_parameter_environment();
|
let param_env = ty::empty_parameter_environment();
|
||||||
match evaluate_impl(infcx, ¶m_env, infcx.tcx, ObligationCause::dummy(),
|
let mut selcx = SelectionContext::new(infcx, ¶m_env, infcx.tcx);
|
||||||
impl2_def_id, impl1_self_ty) {
|
let obligation = Obligation::misc(DUMMY_SP, impl1_trait_ref);
|
||||||
EvaluatedToMatch | EvaluatedToAmbiguity => true,
|
debug!("impl_can_satisfy obligation={}", obligation.repr(infcx.tcx));
|
||||||
EvaluatedToUnmatch => false,
|
selcx.evaluate_impl(impl2_def_id, &obligation)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn impl_is_local(tcx: &ty::ctxt,
|
pub fn impl_is_local(tcx: &ty::ctxt,
|
||||||
|
|
|
@ -57,7 +57,8 @@ Trait resolution consists of three major parts:
|
||||||
resolved by employing an impl which matches the self type, or by
|
resolved by employing an impl which matches the self type, or by
|
||||||
using a parameter bound. In the case of an impl, Selecting one
|
using a parameter bound. In the case of an impl, Selecting one
|
||||||
obligation can create *nested obligations* because of where clauses
|
obligation can create *nested obligations* because of where clauses
|
||||||
on the impl itself.
|
on the impl itself. It may also require evaluating those nested
|
||||||
|
obligations to resolve ambiguities.
|
||||||
|
|
||||||
- FULFILLMENT: The fulfillment code is what tracks that obligations
|
- FULFILLMENT: The fulfillment code is what tracks that obligations
|
||||||
are completely fulfilled. Basically it is a worklist of obligations
|
are completely fulfilled. Basically it is a worklist of obligations
|
||||||
|
@ -100,80 +101,88 @@ candidate that is definitively applicable. In some cases, we may not
|
||||||
know whether an impl/where-clause applies or not -- this occurs when
|
know whether an impl/where-clause applies or not -- this occurs when
|
||||||
the obligation contains unbound inference variables.
|
the obligation contains unbound inference variables.
|
||||||
|
|
||||||
One important point is that candidate assembly considers *only the
|
The basic idea for candidate assembly is to do a first pass in which
|
||||||
input types* of the obligation when deciding whether an impl applies
|
we identify all possible candidates. During this pass, all that we do
|
||||||
or not. Consider the following example:
|
is try and unify the type parameters. (In particular, we ignore any
|
||||||
|
nested where clauses.) Presuming that this unification succeeds, the
|
||||||
|
impl is added as a candidate.
|
||||||
|
|
||||||
trait Convert<T> { // T is output, Self is input
|
Once this first pass is done, we can examine the set of candidates. If
|
||||||
fn convert(&self) -> T;
|
it is a singleton set, then we are done: this is the only impl in
|
||||||
|
scope that could possibly apply. Otherwise, we can winnow down the set
|
||||||
|
of candidates by using where clauses and other conditions. If this
|
||||||
|
reduced set yields a single, unambiguous entry, we're good to go,
|
||||||
|
otherwise the result is considered ambiguous.
|
||||||
|
|
||||||
|
#### The basic process: Inferring based on the impls we see
|
||||||
|
|
||||||
|
This process is easier if we work through some examples. Consider
|
||||||
|
the following trait:
|
||||||
|
|
||||||
|
```
|
||||||
|
trait Convert<Target> {
|
||||||
|
fn convert(&self) -> Target;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This trait just has one method. It's about as simple as it gets. It
|
||||||
|
converts from the (implicit) `Self` type to the `Target` type. If we
|
||||||
|
wanted to permit conversion between `int` and `uint`, we might
|
||||||
|
implement `Convert` like so:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
impl Convert<uint> for int { ... } // int -> uint
|
||||||
|
impl Convert<int> for uint { ... } // uint -> uint
|
||||||
|
```
|
||||||
|
|
||||||
|
Now imagine there is some code like the following:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let x: int = ...;
|
||||||
|
let y = x.convert();
|
||||||
|
```
|
||||||
|
|
||||||
|
The call to convert will generate a trait reference `Convert<$Y> for
|
||||||
|
int`, where `$Y` is the type variable representing the type of
|
||||||
|
`y`. When we match this against the two impls we can see, we will find
|
||||||
|
that only one remains: `Convert<uint> for int`. Therefore, we can
|
||||||
|
select this impl, which will cause the type of `$Y` to be unified to
|
||||||
|
`uint`. (Note that while assembling candidates, we do the initial
|
||||||
|
unifications in a transaction, so that they don't affect one another.)
|
||||||
|
|
||||||
|
There are tests to this effect in src/test/run-pass:
|
||||||
|
|
||||||
|
traits-multidispatch-infer-convert-source-and-target.rs
|
||||||
|
traits-multidispatch-infer-convert-target.rs
|
||||||
|
|
||||||
|
#### Winnowing: Resolving ambiguities
|
||||||
|
|
||||||
|
But what happens if there are multiple impls where all the types
|
||||||
|
unify? Consider this example:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
trait Get {
|
||||||
|
fn get(&self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Convert<uint> for int { ... }
|
impl<T:Copy> Get for T {
|
||||||
|
fn get(&self) -> T { *self }
|
||||||
Now assume we have an obligation `int : Convert<char>`. During
|
|
||||||
candidate assembly, the impl above would be considered a definitively
|
|
||||||
applicable candidate, because it has the same self type (`int`). The
|
|
||||||
fact that the output type parameter `T` is `uint` on the impl and
|
|
||||||
`char` in the obligation is not considered.
|
|
||||||
|
|
||||||
#### Skolemization
|
|
||||||
|
|
||||||
We (at least currently) wish to guarantee "crate concatenability" --
|
|
||||||
which basically means that you could take two crates, concatenate
|
|
||||||
them textually, and the combined crate would continue to compile. The
|
|
||||||
only real way that this relates to trait matching is with
|
|
||||||
inference. We have to be careful not to influence unbound type
|
|
||||||
variables during the selection process, basically.
|
|
||||||
|
|
||||||
Here is an example:
|
|
||||||
|
|
||||||
trait Foo { fn method() { ... }}
|
|
||||||
impl Foo for int { ... }
|
|
||||||
|
|
||||||
fn something() {
|
|
||||||
let mut x = None; // `x` has type `Option<?>`
|
|
||||||
loop {
|
|
||||||
match x {
|
|
||||||
Some(ref y) => { // `y` has type ?
|
|
||||||
y.method(); // (*)
|
|
||||||
...
|
|
||||||
}}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
The question is, can we resolve the call to `y.method()`? We don't yet
|
impl<T:Get> Get for Box<T> {
|
||||||
know what type `y` has. However, there is only one impl in scope, and
|
fn get(&self) -> Box<T> { box get_it(&**self) }
|
||||||
it is for `int`, so perhaps we could deduce that `y` *must* have type
|
}
|
||||||
`int` (and hence the type of `x` is `Option<int>`)? This is actually
|
```
|
||||||
sound reasoning: `int` is the only type in scope that could possibly
|
|
||||||
make this program type check. However, this deduction is a bit
|
|
||||||
"unstable", though, because if we concatenated with another crate that
|
|
||||||
defined a newtype and implemented `Foo` for this newtype, then the
|
|
||||||
inference would fail, because there would be two potential impls, not
|
|
||||||
one.
|
|
||||||
|
|
||||||
It is unclear how important this property is. It might be nice to drop it.
|
What happens when we invoke `get_it(&box 1_u16)`, for example? In this
|
||||||
But for the time being we maintain it.
|
case, the `Self` type is `Box<u16>` -- that unifies with both impls,
|
||||||
|
because the first applies to all types, and the second to all
|
||||||
The way we do this is by *skolemizing* the obligation self type during
|
boxes. In the olden days we'd have called this ambiguous. But what we
|
||||||
the selection process -- skolemizing means, basically, replacing all
|
do now is do a second *winnowing* pass that considers where clauses
|
||||||
unbound type variables with a new "skolemized" type. Each skolemized
|
and attempts to remove candidates -- in this case, the first impl only
|
||||||
type is basically considered "as if" it were some fresh type that is
|
applies if `Box<u16> : Copy`, which doesn't hold. After winnowing,
|
||||||
distinct from all other types. The skolemization process also replaces
|
then, we are left with just one candidate, so we can proceed. There is
|
||||||
lifetimes with `'static`, see the section on lifetimes below for an
|
a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`.
|
||||||
explanation.
|
|
||||||
|
|
||||||
In the example above, this means that when matching `y.method()` we
|
|
||||||
would convert the type of `y` from a type variable `?` to a skolemized
|
|
||||||
type `X`. Then, since `X` cannot unify with `int`, the match would
|
|
||||||
fail. Special code exists to check that the match failed because a
|
|
||||||
skolemized type could not be unified with another kind of type -- this is
|
|
||||||
not considered a definitive failure, but rather an ambiguous result,
|
|
||||||
since if the type variable were later to be unified with int, then this
|
|
||||||
obligation could be resolved then.
|
|
||||||
|
|
||||||
*Note:* Currently, method matching does not use the trait resolution
|
|
||||||
code, so if you in fact type in the example above, it may
|
|
||||||
compile. Hopefully this will be fixed in later patches.
|
|
||||||
|
|
||||||
#### Matching
|
#### Matching
|
||||||
|
|
||||||
|
@ -187,11 +196,9 @@ consider some of the nested obligations, in the case of an impl.
|
||||||
Because of how that lifetime inference works, it is not possible to
|
Because of how that lifetime inference works, it is not possible to
|
||||||
give back immediate feedback as to whether a unification or subtype
|
give back immediate feedback as to whether a unification or subtype
|
||||||
relationship between lifetimes holds or not. Therefore, lifetime
|
relationship between lifetimes holds or not. Therefore, lifetime
|
||||||
matching is *not* considered during selection. This is achieved by
|
matching is *not* considered during selection. This is reflected in
|
||||||
having the skolemization process just replace *ALL* lifetimes with
|
the fact that subregion assignment is infallible. This may yield
|
||||||
`'static`. Later, during confirmation, the non-skolemized self-type
|
lifetime constraints that will later be found to be in error (in
|
||||||
will be unified with the type from the impl (or whatever). This may
|
|
||||||
yield lifetime constraints that will later be found to be in error (in
|
|
||||||
contrast, the non-lifetime-constraints have already been checked
|
contrast, the non-lifetime-constraints have already been checked
|
||||||
during selection and can never cause an error, though naturally they
|
during selection and can never cause an error, though naturally they
|
||||||
may lead to other errors downstream).
|
may lead to other errors downstream).
|
||||||
|
|
|
@ -17,6 +17,7 @@ use middle::subst;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::infer::InferCtxt;
|
use middle::typeck::infer::InferCtxt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::slice::Items;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::{Span, DUMMY_SP};
|
use syntax::codemap::{Span, DUMMY_SP};
|
||||||
|
|
||||||
|
@ -123,13 +124,6 @@ pub enum FulfillmentErrorCode {
|
||||||
*/
|
*/
|
||||||
pub type SelectionResult<T> = Result<Option<T>, SelectionError>;
|
pub type SelectionResult<T> = Result<Option<T>, SelectionError>;
|
||||||
|
|
||||||
#[deriving(PartialEq,Eq,Show)]
|
|
||||||
pub enum EvaluationResult {
|
|
||||||
EvaluatedToMatch,
|
|
||||||
EvaluatedToAmbiguity,
|
|
||||||
EvaluatedToUnmatch
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the successful resolution of an obligation, the `Vtable`
|
* Given the successful resolution of an obligation, the `Vtable`
|
||||||
* indicates where the vtable comes from. Note that while we call this
|
* indicates where the vtable comes from. Note that while we call this
|
||||||
|
@ -186,7 +180,7 @@ pub enum Vtable<N> {
|
||||||
VtableParam(VtableParamData),
|
VtableParam(VtableParamData),
|
||||||
|
|
||||||
/// Successful resolution for a builtin trait.
|
/// Successful resolution for a builtin trait.
|
||||||
VtableBuiltin,
|
VtableBuiltin(VtableBuiltinData<N>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -208,12 +202,17 @@ pub struct VtableImplData<N> {
|
||||||
pub nested: subst::VecPerParamSpace<N>
|
pub nested: subst::VecPerParamSpace<N>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Show,Clone)]
|
||||||
|
pub struct VtableBuiltinData<N> {
|
||||||
|
pub nested: subst::VecPerParamSpace<N>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A vtable provided as a parameter by the caller. For example, in a
|
* A vtable provided as a parameter by the caller. For example, in a
|
||||||
* function like `fn foo<T:Eq>(...)`, if the `eq()` method is invoked
|
* function like `fn foo<T:Eq>(...)`, if the `eq()` method is invoked
|
||||||
* on an instance of `T`, the vtable would be of type `VtableParam`.
|
* on an instance of `T`, the vtable would be of type `VtableParam`.
|
||||||
*/
|
*/
|
||||||
#[deriving(Clone)]
|
#[deriving(PartialEq,Eq,Clone)]
|
||||||
pub struct VtableParamData {
|
pub struct VtableParamData {
|
||||||
// In the above example, this would `Eq`
|
// In the above example, this would `Eq`
|
||||||
pub bound: Rc<ty::TraitRef>,
|
pub bound: Rc<ty::TraitRef>,
|
||||||
|
@ -223,7 +222,7 @@ pub fn evaluate_obligation<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||||
param_env: &ty::ParameterEnvironment,
|
param_env: &ty::ParameterEnvironment,
|
||||||
obligation: &Obligation,
|
obligation: &Obligation,
|
||||||
typer: &Typer<'tcx>)
|
typer: &Typer<'tcx>)
|
||||||
-> EvaluationResult
|
-> bool
|
||||||
{
|
{
|
||||||
/*!
|
/*!
|
||||||
* Attempts to resolve the obligation given. Returns `None` if
|
* Attempts to resolve the obligation given. Returns `None` if
|
||||||
|
@ -235,29 +234,6 @@ pub fn evaluate_obligation<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||||
selcx.evaluate_obligation(obligation)
|
selcx.evaluate_obligation(obligation)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evaluate_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
|
||||||
param_env: &ty::ParameterEnvironment,
|
|
||||||
typer: &Typer<'tcx>,
|
|
||||||
cause: ObligationCause,
|
|
||||||
impl_def_id: ast::DefId,
|
|
||||||
self_ty: ty::t)
|
|
||||||
-> EvaluationResult
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
* Tests whether the impl `impl_def_id` can be applied to the self
|
|
||||||
* type `self_ty`. This is similar to "selection", but simpler:
|
|
||||||
*
|
|
||||||
* - It does not take a full trait-ref as input, so it skips over
|
|
||||||
* the "confirmation" step which would reconcile output type
|
|
||||||
* parameters.
|
|
||||||
* - It returns an `EvaluationResult`, which is a tri-value return
|
|
||||||
* (yes/no/unknown).
|
|
||||||
*/
|
|
||||||
|
|
||||||
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
|
|
||||||
selcx.evaluate_impl(impl_def_id, cause, self_ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||||
param_env: &ty::ParameterEnvironment,
|
param_env: &ty::ParameterEnvironment,
|
||||||
typer: &Typer<'tcx>,
|
typer: &Typer<'tcx>,
|
||||||
|
@ -372,12 +348,21 @@ impl ObligationCause {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N> Vtable<N> {
|
impl<N> Vtable<N> {
|
||||||
|
pub fn iter_nested(&self) -> Items<N> {
|
||||||
|
match *self {
|
||||||
|
VtableImpl(ref i) => i.iter_nested(),
|
||||||
|
VtableUnboxedClosure(_) => (&[]).iter(),
|
||||||
|
VtableParam(_) => (&[]).iter(),
|
||||||
|
VtableBuiltin(ref i) => i.iter_nested(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn map_nested<M>(&self, op: |&N| -> M) -> Vtable<M> {
|
pub fn map_nested<M>(&self, op: |&N| -> M) -> Vtable<M> {
|
||||||
match *self {
|
match *self {
|
||||||
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
|
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
|
||||||
VtableUnboxedClosure(d) => VtableUnboxedClosure(d),
|
VtableUnboxedClosure(d) => VtableUnboxedClosure(d),
|
||||||
VtableParam(ref p) => VtableParam((*p).clone()),
|
VtableParam(ref p) => VtableParam((*p).clone()),
|
||||||
VtableBuiltin => VtableBuiltin,
|
VtableBuiltin(ref i) => VtableBuiltin(i.map_nested(op)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,12 +371,16 @@ impl<N> Vtable<N> {
|
||||||
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
|
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
|
||||||
VtableUnboxedClosure(d) => VtableUnboxedClosure(d),
|
VtableUnboxedClosure(d) => VtableUnboxedClosure(d),
|
||||||
VtableParam(p) => VtableParam(p),
|
VtableParam(p) => VtableParam(p),
|
||||||
VtableBuiltin => VtableBuiltin,
|
VtableBuiltin(i) => VtableBuiltin(i.map_move_nested(op)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N> VtableImplData<N> {
|
impl<N> VtableImplData<N> {
|
||||||
|
pub fn iter_nested(&self) -> Items<N> {
|
||||||
|
self.nested.iter()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn map_nested<M>(&self,
|
pub fn map_nested<M>(&self,
|
||||||
op: |&N| -> M)
|
op: |&N| -> M)
|
||||||
-> VtableImplData<M>
|
-> VtableImplData<M>
|
||||||
|
@ -413,11 +402,23 @@ impl<N> VtableImplData<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EvaluationResult {
|
impl<N> VtableBuiltinData<N> {
|
||||||
pub fn potentially_applicable(&self) -> bool {
|
pub fn iter_nested(&self) -> Items<N> {
|
||||||
match *self {
|
self.nested.iter()
|
||||||
EvaluatedToMatch | EvaluatedToAmbiguity => true,
|
}
|
||||||
EvaluatedToUnmatch => false
|
|
||||||
|
pub fn map_nested<M>(&self,
|
||||||
|
op: |&N| -> M)
|
||||||
|
-> VtableBuiltinData<M>
|
||||||
|
{
|
||||||
|
VtableBuiltinData {
|
||||||
|
nested: self.nested.map(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_move_nested<M>(self, op: |N| -> M) -> VtableBuiltinData<M> {
|
||||||
|
VtableBuiltinData {
|
||||||
|
nested: self.nested.map_move(op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,4 +429,12 @@ impl FulfillmentError {
|
||||||
{
|
{
|
||||||
FulfillmentError { obligation: obligation, code: code }
|
FulfillmentError { obligation: obligation, code: code }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_overflow(&self) -> bool {
|
||||||
|
match self.code {
|
||||||
|
CodeAmbiguity => false,
|
||||||
|
CodeSelectionError(Overflow) => true,
|
||||||
|
CodeSelectionError(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -319,8 +319,8 @@ impl<N:Repr> Repr for super::Vtable<N> {
|
||||||
super::VtableParam(ref v) =>
|
super::VtableParam(ref v) =>
|
||||||
format!("VtableParam({})", v.repr(tcx)),
|
format!("VtableParam({})", v.repr(tcx)),
|
||||||
|
|
||||||
super::VtableBuiltin =>
|
super::VtableBuiltin(ref d) =>
|
||||||
format!("Builtin"),
|
d.repr(tcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,6 +334,13 @@ impl<N:Repr> Repr for super::VtableImplData<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N:Repr> Repr for super::VtableBuiltinData<N> {
|
||||||
|
fn repr(&self, tcx: &ty::ctxt) -> String {
|
||||||
|
format!("VtableBuiltin(nested={})",
|
||||||
|
self.nested.repr(tcx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Repr for super::VtableParamData {
|
impl Repr for super::VtableParamData {
|
||||||
fn repr(&self, tcx: &ty::ctxt) -> String {
|
fn repr(&self, tcx: &ty::ctxt) -> String {
|
||||||
format!("VtableParam(bound={})",
|
format!("VtableParam(bound={})",
|
||||||
|
@ -344,12 +351,12 @@ impl Repr for super::VtableParamData {
|
||||||
impl Repr for super::SelectionError {
|
impl Repr for super::SelectionError {
|
||||||
fn repr(&self, tcx: &ty::ctxt) -> String {
|
fn repr(&self, tcx: &ty::ctxt) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
super::Unimplemented =>
|
|
||||||
format!("Unimplemented"),
|
|
||||||
|
|
||||||
super::Overflow =>
|
super::Overflow =>
|
||||||
format!("Overflow"),
|
format!("Overflow"),
|
||||||
|
|
||||||
|
super::Unimplemented =>
|
||||||
|
format!("Unimplemented"),
|
||||||
|
|
||||||
super::OutputTypeParameterMismatch(ref t, ref e) =>
|
super::OutputTypeParameterMismatch(ref t, ref e) =>
|
||||||
format!("OutputTypeParameterMismatch({}, {})",
|
format!("OutputTypeParameterMismatch({}, {})",
|
||||||
t.repr(tcx),
|
t.repr(tcx),
|
||||||
|
|
|
@ -800,10 +800,18 @@ pub fn fulfill_obligation(ccx: &CrateContext,
|
||||||
let selection = match selcx.select(&obligation) {
|
let selection = match selcx.select(&obligation) {
|
||||||
Ok(Some(selection)) => selection,
|
Ok(Some(selection)) => selection,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
tcx.sess.span_bug(
|
// Ambiguity can happen when monomorphizing during trans
|
||||||
|
// expands to some humongo type that never occurred
|
||||||
|
// statically -- this humongo type can then overflow,
|
||||||
|
// leading to an ambiguous result. So report this as an
|
||||||
|
// overflow bug, since I believe this is the only case
|
||||||
|
// where ambiguity can result.
|
||||||
|
debug!("Encountered ambiguity selecting `{}` during trans, \
|
||||||
|
presuming due to overflow",
|
||||||
|
trait_ref.repr(tcx));
|
||||||
|
ccx.sess().span_fatal(
|
||||||
span,
|
span,
|
||||||
format!("Encountered ambiguity selecting `{}` during trans",
|
"reached the recursion limit during monomorphization");
|
||||||
trait_ref.repr(tcx)).as_slice())
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tcx.sess.span_bug(
|
tcx.sess.span_bug(
|
||||||
|
@ -826,14 +834,21 @@ pub fn fulfill_obligation(ccx: &CrateContext,
|
||||||
});
|
});
|
||||||
match fulfill_cx.select_all_or_error(&infcx, ¶m_env, tcx) {
|
match fulfill_cx.select_all_or_error(&infcx, ¶m_env, tcx) {
|
||||||
Ok(()) => { }
|
Ok(()) => { }
|
||||||
Err(e) => {
|
Err(errors) => {
|
||||||
|
if errors.iter().all(|e| e.is_overflow()) {
|
||||||
|
// See Ok(None) case above.
|
||||||
|
ccx.sess().span_fatal(
|
||||||
|
span,
|
||||||
|
"reached the recursion limit during monomorphization");
|
||||||
|
} else {
|
||||||
tcx.sess.span_bug(
|
tcx.sess.span_bug(
|
||||||
span,
|
span,
|
||||||
format!("Encountered errors `{}` fulfilling `{}` during trans",
|
format!("Encountered errors `{}` fulfilling `{}` during trans",
|
||||||
e.repr(tcx),
|
errors.repr(tcx),
|
||||||
trait_ref.repr(tcx)).as_slice());
|
trait_ref.repr(tcx)).as_slice());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Use skolemize to simultaneously replace all type variables with
|
// Use skolemize to simultaneously replace all type variables with
|
||||||
// their bindings and replace all regions with 'static. This is
|
// their bindings and replace all regions with 'static. This is
|
||||||
|
|
|
@ -247,7 +247,7 @@ static FLAGS_NONE: c_uint = 0;
|
||||||
// Public Interface of debuginfo module
|
// Public Interface of debuginfo module
|
||||||
//=-----------------------------------------------------------------------------
|
//=-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[deriving(Copy, Show, Hash, Eq, PartialEq, Clone)]
|
#[deriving(Show, Hash, Eq, PartialEq, Clone)]
|
||||||
struct UniqueTypeId(ast::Name);
|
struct UniqueTypeId(ast::Name);
|
||||||
|
|
||||||
// The TypeMap is where the CrateDebugContext holds the type metadata nodes
|
// The TypeMap is where the CrateDebugContext holds the type metadata nodes
|
||||||
|
|
|
@ -561,7 +561,7 @@ pub fn get_vtable(bcx: Block,
|
||||||
DUMMY_SP,
|
DUMMY_SP,
|
||||||
trait_ref.clone());
|
trait_ref.clone());
|
||||||
match vtable {
|
match vtable {
|
||||||
traits::VtableBuiltin => {
|
traits::VtableBuiltin(_) => {
|
||||||
Vec::new().into_iter()
|
Vec::new().into_iter()
|
||||||
}
|
}
|
||||||
traits::VtableImpl(
|
traits::VtableImpl(
|
||||||
|
|
|
@ -390,13 +390,21 @@ impl<N:TypeFoldable> TypeFoldable for traits::VtableImplData<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N:TypeFoldable> TypeFoldable for traits::VtableBuiltinData<N> {
|
||||||
|
fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableBuiltinData<N> {
|
||||||
|
traits::VtableBuiltinData {
|
||||||
|
nested: self.nested.fold_with(folder),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<N:TypeFoldable> TypeFoldable for traits::Vtable<N> {
|
impl<N:TypeFoldable> TypeFoldable for traits::Vtable<N> {
|
||||||
fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<N> {
|
fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<N> {
|
||||||
match *self {
|
match *self {
|
||||||
traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
|
traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
|
||||||
traits::VtableUnboxedClosure(d) => traits::VtableUnboxedClosure(d),
|
traits::VtableUnboxedClosure(d) => traits::VtableUnboxedClosure(d),
|
||||||
traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)),
|
traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)),
|
||||||
traits::VtableBuiltin => traits::VtableBuiltin,
|
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,7 @@
|
||||||
|
|
||||||
use middle::subst::{SelfSpace};
|
use middle::subst::{SelfSpace};
|
||||||
use middle::traits;
|
use middle::traits;
|
||||||
use middle::traits::{SelectionError, Overflow,
|
use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented};
|
||||||
OutputTypeParameterMismatch, Unimplemented};
|
|
||||||
use middle::traits::{Obligation, obligation_for_builtin_bound};
|
use middle::traits::{Obligation, obligation_for_builtin_bound};
|
||||||
use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity};
|
use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity};
|
||||||
use middle::traits::{ObligationCause};
|
use middle::traits::{ObligationCause};
|
||||||
|
@ -233,6 +232,16 @@ pub fn report_selection_error(fcx: &FnCtxt,
|
||||||
error: &SelectionError)
|
error: &SelectionError)
|
||||||
{
|
{
|
||||||
match *error {
|
match *error {
|
||||||
|
Overflow => {
|
||||||
|
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
|
||||||
|
fcx.tcx().sess.span_err(
|
||||||
|
obligation.cause.span,
|
||||||
|
format!(
|
||||||
|
"overflow evaluating the trait `{}` for the type `{}`",
|
||||||
|
trait_ref.user_string(fcx.tcx()),
|
||||||
|
self_ty.user_string(fcx.tcx())).as_slice());
|
||||||
|
note_obligation_cause(fcx, obligation);
|
||||||
|
}
|
||||||
Unimplemented => {
|
Unimplemented => {
|
||||||
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
|
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
|
||||||
if !ty::type_is_error(self_ty) {
|
if !ty::type_is_error(self_ty) {
|
||||||
|
@ -245,9 +254,6 @@ pub fn report_selection_error(fcx: &FnCtxt,
|
||||||
note_obligation_cause(fcx, obligation);
|
note_obligation_cause(fcx, obligation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Overflow => {
|
|
||||||
report_overflow(fcx, obligation);
|
|
||||||
}
|
|
||||||
OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => {
|
OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => {
|
||||||
let expected_trait_ref =
|
let expected_trait_ref =
|
||||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
|
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
|
||||||
|
@ -269,21 +275,6 @@ pub fn report_selection_error(fcx: &FnCtxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_overflow(fcx: &FnCtxt, obligation: &Obligation) {
|
|
||||||
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
|
|
||||||
if ty::type_is_error(self_ty) {
|
|
||||||
fcx.tcx().sess.span_err(
|
|
||||||
obligation.cause.span,
|
|
||||||
format!(
|
|
||||||
"could not locate an impl of the trait `{}` for \
|
|
||||||
the type `{}` due to overflow; possible cyclic \
|
|
||||||
dependency between impls",
|
|
||||||
trait_ref.user_string(fcx.tcx()),
|
|
||||||
self_ty.user_string(fcx.tcx())).as_slice());
|
|
||||||
note_obligation_cause(fcx, obligation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) {
|
pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) {
|
||||||
// Unable to successfully determine, probably means
|
// Unable to successfully determine, probably means
|
||||||
// insufficient type information, but could mean
|
// insufficient type information, but could mean
|
||||||
|
@ -294,8 +285,9 @@ pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) {
|
||||||
trait_ref.repr(fcx.tcx()),
|
trait_ref.repr(fcx.tcx()),
|
||||||
self_ty.repr(fcx.tcx()),
|
self_ty.repr(fcx.tcx()),
|
||||||
obligation.repr(fcx.tcx()));
|
obligation.repr(fcx.tcx()));
|
||||||
if ty::type_is_error(self_ty) {
|
let all_types = &trait_ref.substs.types;
|
||||||
} else if ty::type_needs_infer(self_ty) {
|
if all_types.iter().any(|&t| ty::type_is_error(t)) {
|
||||||
|
} else if all_types.iter().any(|&t| ty::type_needs_infer(t)) {
|
||||||
// This is kind of a hack: it frequently happens that some earlier
|
// This is kind of a hack: it frequently happens that some earlier
|
||||||
// error prevents types from being fully inferred, and then we get
|
// error prevents types from being fully inferred, and then we get
|
||||||
// a bunch of uninteresting errors saying something like "<generic
|
// a bunch of uninteresting errors saying something like "<generic
|
||||||
|
@ -321,7 +313,7 @@ pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) {
|
||||||
self_ty.user_string(fcx.tcx())).as_slice());
|
self_ty.user_string(fcx.tcx())).as_slice());
|
||||||
note_obligation_cause(fcx, obligation);
|
note_obligation_cause(fcx, obligation);
|
||||||
}
|
}
|
||||||
} else if fcx.tcx().sess.err_count() == 0 {
|
} else if !fcx.tcx().sess.has_errors() {
|
||||||
// Ambiguity. Coherence should have reported an error.
|
// Ambiguity. Coherence should have reported an error.
|
||||||
fcx.tcx().sess.span_bug(
|
fcx.tcx().sess.span_bug(
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
|
|
|
@ -35,8 +35,16 @@ struct OverlapChecker<'cx, 'tcx:'cx> {
|
||||||
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||||
fn check_for_overlapping_impls(&self) {
|
fn check_for_overlapping_impls(&self) {
|
||||||
debug!("check_for_overlapping_impls");
|
debug!("check_for_overlapping_impls");
|
||||||
let trait_impls = self.tcx.trait_impls.borrow();
|
|
||||||
for trait_def_id in trait_impls.keys() {
|
// Collect this into a vector to avoid holding the
|
||||||
|
// refcell-lock during the
|
||||||
|
// check_for_overlapping_impls_of_trait() check, since that
|
||||||
|
// check can populate this table further with impls from other
|
||||||
|
// crates.
|
||||||
|
let trait_def_ids: Vec<ast::DefId> =
|
||||||
|
self.tcx.trait_impls.borrow().keys().map(|&d| d).collect();
|
||||||
|
|
||||||
|
for trait_def_id in trait_def_ids.iter() {
|
||||||
self.check_for_overlapping_impls_of_trait(*trait_def_id);
|
self.check_for_overlapping_impls_of_trait(*trait_def_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,18 +27,8 @@ use middle::subst::Substs;
|
||||||
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
|
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold;
|
use middle::ty_fold;
|
||||||
use middle::ty_fold::TypeFolder;
|
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||||
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
|
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
|
||||||
use middle::typeck::infer::coercion::Coerce;
|
|
||||||
use middle::typeck::infer::combine::{Combine, CombineFields};
|
|
||||||
use middle::typeck::infer::region_inference::{RegionVarBindings,
|
|
||||||
RegionSnapshot};
|
|
||||||
use middle::typeck::infer::resolve::{resolver};
|
|
||||||
use middle::typeck::infer::equate::Equate;
|
|
||||||
use middle::typeck::infer::sub::Sub;
|
|
||||||
use middle::typeck::infer::lub::Lub;
|
|
||||||
use middle::typeck::infer::unify::{UnificationTable};
|
|
||||||
use middle::typeck::infer::error_reporting::ErrorReporting;
|
|
||||||
use std::cell::{RefCell};
|
use std::cell::{RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -48,6 +38,16 @@ use syntax::codemap::Span;
|
||||||
use util::common::indent;
|
use util::common::indent;
|
||||||
use util::ppaux::{bound_region_to_string, ty_to_string, trait_ref_to_string, Repr};
|
use util::ppaux::{bound_region_to_string, ty_to_string, trait_ref_to_string, Repr};
|
||||||
|
|
||||||
|
use self::coercion::Coerce;
|
||||||
|
use self::combine::{Combine, CombineFields};
|
||||||
|
use self::region_inference::{RegionVarBindings, RegionSnapshot};
|
||||||
|
use self::resolve::{resolver};
|
||||||
|
use self::equate::Equate;
|
||||||
|
use self::sub::Sub;
|
||||||
|
use self::lub::Lub;
|
||||||
|
use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes};
|
||||||
|
use self::error_reporting::ErrorReporting;
|
||||||
|
|
||||||
pub mod coercion;
|
pub mod coercion;
|
||||||
pub mod combine;
|
pub mod combine;
|
||||||
pub mod doc;
|
pub mod doc;
|
||||||
|
@ -503,6 +503,10 @@ pub struct CombinedSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
pub fn skolemize<T:TypeFoldable>(&self, t: T) -> T {
|
||||||
|
t.fold_with(&mut self.skolemizer())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn skolemizer<'a>(&'a self) -> TypeSkolemizer<'a, 'tcx> {
|
pub fn skolemizer<'a>(&'a self) -> TypeSkolemizer<'a, 'tcx> {
|
||||||
skolemize::TypeSkolemizer::new(self)
|
skolemize::TypeSkolemizer::new(self)
|
||||||
}
|
}
|
||||||
|
@ -630,11 +634,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
-> ures
|
-> ures
|
||||||
{
|
{
|
||||||
debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx));
|
debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx));
|
||||||
|
self.commit_if_ok(|| {
|
||||||
let trace = TypeTrace {
|
let trace = TypeTrace {
|
||||||
origin: origin,
|
origin: origin,
|
||||||
values: Types(expected_found(a_is_expected, a, b))
|
values: Types(expected_found(a_is_expected, a, b))
|
||||||
};
|
};
|
||||||
self.sub(a_is_expected, trace).tys(a, b).to_ures()
|
self.sub(a_is_expected, trace).tys(a, b).to_ures()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq_types(&self,
|
pub fn eq_types(&self,
|
||||||
|
@ -644,11 +650,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
b: ty::t)
|
b: ty::t)
|
||||||
-> ures
|
-> ures
|
||||||
{
|
{
|
||||||
|
self.commit_if_ok(|| {
|
||||||
let trace = TypeTrace {
|
let trace = TypeTrace {
|
||||||
origin: origin,
|
origin: origin,
|
||||||
values: Types(expected_found(a_is_expected, a, b))
|
values: Types(expected_found(a_is_expected, a, b))
|
||||||
};
|
};
|
||||||
self.equate(a_is_expected, trace).tys(a, b).to_ures()
|
self.equate(a_is_expected, trace).tys(a, b).to_ures()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_trait_refs(&self,
|
pub fn sub_trait_refs(&self,
|
||||||
|
@ -661,13 +669,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
debug!("sub_trait_refs({} <: {})",
|
debug!("sub_trait_refs({} <: {})",
|
||||||
a.repr(self.tcx),
|
a.repr(self.tcx),
|
||||||
b.repr(self.tcx));
|
b.repr(self.tcx));
|
||||||
|
self.commit_if_ok(|| {
|
||||||
let trace = TypeTrace {
|
let trace = TypeTrace {
|
||||||
origin: origin,
|
origin: origin,
|
||||||
values: TraitRefs(expected_found(a_is_expected,
|
values: TraitRefs(expected_found(a_is_expected,
|
||||||
a.clone(), b.clone()))
|
a.clone(), b.clone()))
|
||||||
};
|
};
|
||||||
let suber = self.sub(a_is_expected, trace);
|
self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures()
|
||||||
suber.trait_refs(&*a, &*b).to_ures()
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -789,6 +798,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn shallow_resolve(&self, typ: ty::t) -> ty::t {
|
||||||
|
match ty::get(typ).sty {
|
||||||
|
ty::ty_infer(ty::TyVar(v)) => {
|
||||||
|
self.type_variables.borrow()
|
||||||
|
.probe(v)
|
||||||
|
.unwrap_or(typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::ty_infer(ty::IntVar(v)) => {
|
||||||
|
self.probe_var(v)
|
||||||
|
.unwrap_or(typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::ty_infer(ty::FloatVar(v)) => {
|
||||||
|
self.probe_var(v)
|
||||||
|
.unwrap_or(typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
typ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resolve_type_vars_if_possible(&self, typ: ty::t) -> ty::t {
|
pub fn resolve_type_vars_if_possible(&self, typ: ty::t) -> ty::t {
|
||||||
match resolve_type(self,
|
match resolve_type(self,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -12,17 +12,18 @@
|
||||||
* Skolemization is the process of replacing unknown variables with
|
* Skolemization is the process of replacing unknown variables with
|
||||||
* fresh types. The idea is that the type, after skolemization,
|
* fresh types. The idea is that the type, after skolemization,
|
||||||
* contains no inference variables but instead contains either a value
|
* contains no inference variables but instead contains either a value
|
||||||
* for each variable (if the variable had already fresh "arbitrary"
|
* for each variable or fresh "arbitrary" types wherever a variable
|
||||||
* types wherever a variable would have been.
|
* would have been.
|
||||||
*
|
*
|
||||||
* Skolemization is used wherever we want to test what the type
|
* Skolemization is used primarily to get a good type for inserting
|
||||||
* inferencer knows "so far". The primary place it is used right now
|
* into a cache. The result summarizes what the type inferencer knows
|
||||||
* is in the trait matching algorithm, which needs to be able to test
|
* "so far". The primary place it is used right now is in the trait
|
||||||
* whether an `impl` self type matches some other type X -- *without*
|
* matching algorithm, which needs to be able to cache whether an
|
||||||
* affecting `X`. That means if that if the type `X` is in fact an
|
* `impl` self type matches some other type X -- *without* affecting
|
||||||
* unbound type variable, we want the match to be regarded as
|
* `X`. That means if that if the type `X` is in fact an unbound type
|
||||||
* ambiguous, because depending on what type that type variable is
|
* variable, we want the match to be regarded as ambiguous, because
|
||||||
* ultimately assigned, the match may or may not succeed.
|
* depending on what type that type variable is ultimately assigned,
|
||||||
|
* the match may or may not succeed.
|
||||||
*
|
*
|
||||||
* Note that you should be careful not to allow the output of
|
* Note that you should be careful not to allow the output of
|
||||||
* skolemization to leak to the user in error messages or in any other
|
* skolemization to leak to the user in error messages or in any other
|
||||||
|
@ -43,39 +44,45 @@ use middle::ty;
|
||||||
use middle::ty_fold;
|
use middle::ty_fold;
|
||||||
use middle::ty_fold::TypeFoldable;
|
use middle::ty_fold::TypeFoldable;
|
||||||
use middle::ty_fold::TypeFolder;
|
use middle::ty_fold::TypeFolder;
|
||||||
|
use std::collections::hashmap;
|
||||||
|
|
||||||
use super::InferCtxt;
|
use super::InferCtxt;
|
||||||
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
|
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
|
||||||
use super::unify::SimplyUnifiable;
|
|
||||||
use super::unify::UnifyKey;
|
|
||||||
|
|
||||||
pub struct TypeSkolemizer<'a, 'tcx:'a> {
|
pub struct TypeSkolemizer<'a, 'tcx:'a> {
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
skolemization_count: uint
|
skolemization_count: uint,
|
||||||
|
skolemization_map: hashmap::HashMap<ty::InferTy, ty::t>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> {
|
impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> {
|
||||||
pub fn new<'tcx>(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeSkolemizer<'a, 'tcx> {
|
pub fn new<'tcx>(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeSkolemizer<'a, 'tcx> {
|
||||||
TypeSkolemizer { infcx: infcx, skolemization_count: 0 }
|
TypeSkolemizer {
|
||||||
|
infcx: infcx,
|
||||||
|
skolemization_count: 0,
|
||||||
|
skolemization_map: hashmap::HashMap::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn probe_ty(&mut self, v: ty::TyVid) -> ty::t {
|
fn skolemize(&mut self,
|
||||||
self.skolemize_if_none(self.infcx.type_variables.borrow().probe(v), ty::SkolemizedTy)
|
opt_ty: Option<ty::t>,
|
||||||
}
|
key: ty::InferTy,
|
||||||
|
|
||||||
fn probe_unifiable<V:SimplyUnifiable,K:UnifyKey<Option<V>>>(&mut self, k: K) -> ty::t {
|
|
||||||
self.skolemize_if_none(self.infcx.probe_var(k), ty::SkolemizedIntTy)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn skolemize_if_none(&mut self, o: Option<ty::t>,
|
|
||||||
skolemizer: |uint| -> ty::InferTy)
|
skolemizer: |uint| -> ty::InferTy)
|
||||||
-> ty::t {
|
-> ty::t
|
||||||
match o {
|
{
|
||||||
Some(t) => t.fold_with(self),
|
match opt_ty {
|
||||||
None => {
|
Some(ty) => { return ty.fold_with(self); }
|
||||||
|
None => { }
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.skolemization_map.entry(key) {
|
||||||
|
hashmap::Occupied(entry) => *entry.get(),
|
||||||
|
hashmap::Vacant(entry) => {
|
||||||
let index = self.skolemization_count;
|
let index = self.skolemization_count;
|
||||||
self.skolemization_count += 1;
|
self.skolemization_count += 1;
|
||||||
ty::mk_infer(self.tcx(), skolemizer(index))
|
let t = ty::mk_infer(self.infcx.tcx, skolemizer(index));
|
||||||
|
entry.set(t);
|
||||||
|
t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,15 +115,21 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> {
|
||||||
fn fold_ty(&mut self, t: ty::t) -> ty::t {
|
fn fold_ty(&mut self, t: ty::t) -> ty::t {
|
||||||
match ty::get(t).sty {
|
match ty::get(t).sty {
|
||||||
ty::ty_infer(ty::TyVar(v)) => {
|
ty::ty_infer(ty::TyVar(v)) => {
|
||||||
self.probe_ty(v)
|
self.skolemize(self.infcx.type_variables.borrow().probe(v),
|
||||||
|
ty::TyVar(v),
|
||||||
|
ty::SkolemizedTy)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_infer(ty::IntVar(v)) => {
|
ty::ty_infer(ty::IntVar(v)) => {
|
||||||
self.probe_unifiable(v)
|
self.skolemize(self.infcx.probe_var(v),
|
||||||
|
ty::IntVar(v),
|
||||||
|
ty::SkolemizedIntTy)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_infer(ty::FloatVar(v)) => {
|
ty::ty_infer(ty::FloatVar(v)) => {
|
||||||
self.probe_unifiable(v)
|
self.skolemize(self.infcx.probe_var(v),
|
||||||
|
ty::FloatVar(v),
|
||||||
|
ty::SkolemizedIntTy)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_infer(ty::SkolemizedTy(c)) |
|
ty::ty_infer(ty::SkolemizedTy(c)) |
|
||||||
|
|
51
src/test/auxiliary/go_trait.rs
Normal file
51
src/test/auxiliary/go_trait.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Common code used for tests that model the Fn/FnMut/FnOnce hierarchy.
|
||||||
|
|
||||||
|
pub trait Go {
|
||||||
|
fn go(&self, arg: int);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn go<G:Go>(this: &G, arg: int) {
|
||||||
|
this.go(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GoMut {
|
||||||
|
fn go_mut(&mut self, arg: int);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn go_mut<G:GoMut>(this: &mut G, arg: int) {
|
||||||
|
this.go_mut(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GoOnce {
|
||||||
|
fn go_once(self, arg: int);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn go_once<G:GoOnce>(this: G, arg: int) {
|
||||||
|
this.go_once(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G> GoMut for G
|
||||||
|
where G : Go
|
||||||
|
{
|
||||||
|
fn go_mut(&mut self, arg: int) {
|
||||||
|
go(&*self, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G> GoOnce for G
|
||||||
|
where G : GoMut
|
||||||
|
{
|
||||||
|
fn go_once(mut self, arg: int) {
|
||||||
|
go_mut(&mut self, arg)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// aux-build:go_trait.rs
|
||||||
|
|
||||||
|
extern crate go_trait;
|
||||||
|
|
||||||
|
use go_trait::{Go,GoMut};
|
||||||
|
use std::fmt::Show;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
struct MyThingy;
|
||||||
|
|
||||||
|
impl Go for MyThingy {
|
||||||
|
fn go(&self, arg: int) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GoMut for MyThingy { //~ ERROR conflicting implementations
|
||||||
|
fn go_mut(&mut self, arg: int) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -0,0 +1,36 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use std::fmt::Show;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
// Test that a blank impl for all T conflicts with an impl for some
|
||||||
|
// specific T, even when there are multiple type parameters involved.
|
||||||
|
|
||||||
|
trait MyTrait<T> {
|
||||||
|
fn get(&self) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MyTrait<T> for T { //~ ERROR E0119
|
||||||
|
fn get(&self) -> T {
|
||||||
|
fail!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone)]
|
||||||
|
struct MyType {
|
||||||
|
dummy: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait<MyType> for MyType {
|
||||||
|
fn get(&self) -> uint { (*self).clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -0,0 +1,38 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Test that a blank impl for all T:PartialEq conflicts with an impl for some
|
||||||
|
// specific T when T:PartialEq.
|
||||||
|
|
||||||
|
trait OtherTrait {
|
||||||
|
fn noop(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
trait MyTrait {
|
||||||
|
fn get(&self) -> uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:OtherTrait> MyTrait for T { //~ ERROR E0119
|
||||||
|
fn get(&self) -> uint { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyType {
|
||||||
|
dummy: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait for MyType {
|
||||||
|
fn get(&self) -> uint { self.dummy }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OtherTrait for MyType {
|
||||||
|
fn noop(&self) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -0,0 +1,33 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use std::fmt::Show;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
// Test that a blank impl for all T conflicts with an impl for some
|
||||||
|
// specific T.
|
||||||
|
|
||||||
|
trait MyTrait {
|
||||||
|
fn get(&self) -> uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MyTrait for T { //~ ERROR E0119
|
||||||
|
fn get(&self) -> uint { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyType {
|
||||||
|
dummy: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait for MyType {
|
||||||
|
fn get(&self) -> uint { self.dummy }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
BIN
src/test/compile-fail/coherence-multidispatch-tuple
Executable file
BIN
src/test/compile-fail/coherence-multidispatch-tuple
Executable file
Binary file not shown.
29
src/test/compile-fail/coherence-tuple-conflict.rs
Normal file
29
src/test/compile-fail/coherence-tuple-conflict.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use std::fmt::Show;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
// Test that a blank impl for all T conflicts with an impl for some
|
||||||
|
// specific T.
|
||||||
|
|
||||||
|
trait MyTrait {
|
||||||
|
fn get(&self) -> uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MyTrait for (T,T) { //~ ERROR E0119
|
||||||
|
fn get(&self) -> uint { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A,B> MyTrait for (A,B) {
|
||||||
|
fn get(&self) -> uint { self.dummy }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -20,9 +20,8 @@ impl<T:Dot> Dot for Cons<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn test<T:Dot> (n:int, i:int, first:T, second:T) ->int {
|
fn test<T:Dot> (n:int, i:int, first:T, second:T) ->int {
|
||||||
|
match n { 0 => {first.dot(second)}
|
||||||
//~^ ERROR: reached the recursion limit during monomorphization
|
//~^ ERROR: reached the recursion limit during monomorphization
|
||||||
match n {
|
|
||||||
0 => {first.dot(second)}
|
|
||||||
// Error message should be here. It should be a type error
|
// Error message should be here. It should be a type error
|
||||||
// to instantiate `test` at a type other than T. (See #4287)
|
// to instantiate `test` at a type other than T. (See #4287)
|
||||||
_ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
|
_ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
|
||||||
|
|
|
@ -25,6 +25,6 @@ impl Trait<&'static str> for Struct {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let s: Box<Trait<int>> = box Struct { person: "Fred" };
|
let s: Box<Trait<int>> = box Struct { person: "Fred" };
|
||||||
//~^ ERROR type mismatch
|
//~^ ERROR the trait `Trait<int>` is not implemented for the type `Struct`
|
||||||
s.f(1);
|
s.f(1);
|
||||||
}
|
}
|
||||||
|
|
32
src/test/compile-fail/traits-multidispatch-bad.rs
Normal file
32
src/test/compile-fail/traits-multidispatch-bad.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Test that we detect an illegal combination of types.
|
||||||
|
|
||||||
|
trait Convert<Target> {
|
||||||
|
fn convert(&self) -> Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Convert<uint> for int {
|
||||||
|
fn convert(&self) -> uint {
|
||||||
|
*self as uint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test<T,U>(_: T, _: U)
|
||||||
|
where T : Convert<U>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() {
|
||||||
|
test(22i, 44i); //~ ERROR not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,39 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Check that we get an error in a multidisptach scenario where the
|
||||||
|
// set of impls is ambiguous.
|
||||||
|
|
||||||
|
trait Convert<Target> {
|
||||||
|
fn convert(&self) -> Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Convert<i8> for i32 {
|
||||||
|
fn convert(&self) -> i8 {
|
||||||
|
*self as i8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Convert<i16> for i32 {
|
||||||
|
fn convert(&self) -> i16 {
|
||||||
|
*self as i16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test<T,U>(_: T, _: U)
|
||||||
|
where T : Convert<U>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() {
|
||||||
|
test(22_i32, 44); //~ ERROR unable to infer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -15,12 +15,12 @@ trait Tr<T> {
|
||||||
// these compile as if Self: Tr<U>, even tho only Self: Tr<Self or T>
|
// these compile as if Self: Tr<U>, even tho only Self: Tr<Self or T>
|
||||||
trait A: Tr<Self> {
|
trait A: Tr<Self> {
|
||||||
fn test<U>(u: U) -> Self {
|
fn test<U>(u: U) -> Self {
|
||||||
Tr::op(u) //~ ERROR type mismatch
|
Tr::op(u) //~ ERROR not implemented
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trait B<T>: Tr<T> {
|
trait B<T>: Tr<T> {
|
||||||
fn test<U>(u: U) -> Self {
|
fn test<U>(u: U) -> Self {
|
||||||
Tr::op(u) //~ ERROR type mismatch
|
Tr::op(u) //~ ERROR not implemented
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
|
@ -8,15 +8,22 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
trait Foo {
|
use std::fmt::Show;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
// Test that an impl for homogeneous pairs does not conflict with a
|
||||||
|
// heterogeneous pair.
|
||||||
|
|
||||||
|
trait MyTrait {
|
||||||
|
fn get(&self) -> uint;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Foo for int { //~ ERROR conflicting implementations
|
impl<T> MyTrait for (T,T) {
|
||||||
|
fn get(&self) -> uint { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Foo for A { //~ NOTE conflicting implementation here
|
impl MyTrait for (uint,int) {
|
||||||
|
fn get(&self) -> uint { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
46
src/test/run-pass/coherence-where-clause.rs
Normal file
46
src/test/run-pass/coherence-where-clause.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use std::fmt::Show;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
trait MyTrait {
|
||||||
|
fn get(&self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MyTrait for T
|
||||||
|
where T : Default
|
||||||
|
{
|
||||||
|
fn get(&self) -> T {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone,Show,PartialEq)]
|
||||||
|
struct MyType {
|
||||||
|
dummy: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait for MyType {
|
||||||
|
fn get(&self) -> MyType { (*self).clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_eq<M>(m: M, n: M)
|
||||||
|
where M : MyTrait + Show + PartialEq
|
||||||
|
{
|
||||||
|
assert_eq!(m.get(), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
test_eq(0u, 0u);
|
||||||
|
|
||||||
|
let value = MyType { dummy: 256 + 22 };
|
||||||
|
test_eq(value, value);
|
||||||
|
}
|
40
src/test/run-pass/multidispatch1.rs
Normal file
40
src/test/run-pass/multidispatch1.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use std::fmt::Show;
|
||||||
|
|
||||||
|
trait MyTrait<T> {
|
||||||
|
fn get(&self) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyType {
|
||||||
|
dummy: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait<uint> for MyType {
|
||||||
|
fn get(&self) -> uint { self.dummy }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait<u8> for MyType {
|
||||||
|
fn get(&self) -> u8 { self.dummy as u8 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_eq<T,M>(m: M, v: T)
|
||||||
|
where T : Eq + Show,
|
||||||
|
M : MyTrait<T>
|
||||||
|
{
|
||||||
|
assert_eq!(m.get(), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let value = MyType { dummy: 256 + 22 };
|
||||||
|
test_eq::<uint, _>(value, value.dummy);
|
||||||
|
test_eq::<u8, _>(value, value.dummy as u8);
|
||||||
|
}
|
46
src/test/run-pass/multidispatch2.rs
Normal file
46
src/test/run-pass/multidispatch2.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use std::fmt::Show;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
trait MyTrait<T> {
|
||||||
|
fn get(&self) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MyTrait<T> for T
|
||||||
|
where T : Default
|
||||||
|
{
|
||||||
|
fn get(&self) -> T {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyType {
|
||||||
|
dummy: uint
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait<uint> for MyType {
|
||||||
|
fn get(&self) -> uint { self.dummy }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_eq<T,M>(m: M, v: T)
|
||||||
|
where T : Eq + Show,
|
||||||
|
M : MyTrait<T>
|
||||||
|
{
|
||||||
|
assert_eq!(m.get(), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
test_eq(22u, 0u);
|
||||||
|
|
||||||
|
let value = MyType { dummy: 256 + 22 };
|
||||||
|
test_eq(value, value.dummy);
|
||||||
|
}
|
36
src/test/run-pass/traits-conditional-dispatch.rs
Normal file
36
src/test/run-pass/traits-conditional-dispatch.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Test that we are able to resolve conditional dispatch. Here, the
|
||||||
|
// blanket impl for T:Copy coexists with an impl for Box<T>, because
|
||||||
|
// Box does not impl Copy.
|
||||||
|
|
||||||
|
trait Get {
|
||||||
|
fn get(&self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:Copy> Get for T {
|
||||||
|
fn get(&self) -> T { *self }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:Get> Get for Box<T> {
|
||||||
|
fn get(&self) -> Box<T> { box get_it(&**self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_it<T:Get>(t: &T) -> T {
|
||||||
|
(*t).get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(get_it(&1_u32), 1_u32);
|
||||||
|
assert_eq!(get_it(&1_u16), 1_u16);
|
||||||
|
assert_eq!(get_it(&Some(1_u16)), Some(1_u16));
|
||||||
|
assert_eq!(get_it(&box 1i), box 1i);
|
||||||
|
}
|
67
src/test/run-pass/traits-conditional-model-fn.rs
Normal file
67
src/test/run-pass/traits-conditional-model-fn.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// A model for how the `Fn` traits could work. You can implement at
|
||||||
|
// most one of `Go`, `GoMut`, or `GoOnce`, and then the others follow
|
||||||
|
// automatically.
|
||||||
|
|
||||||
|
// aux-build:go_trait.rs
|
||||||
|
|
||||||
|
extern crate go_trait;
|
||||||
|
|
||||||
|
use go_trait::{Go, GoMut, GoOnce, go, go_mut, go_once};
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct SomeGoableThing {
|
||||||
|
counter: Rc<Cell<int>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Go for SomeGoableThing {
|
||||||
|
fn go(&self, arg: int) {
|
||||||
|
self.counter.set(self.counter.get() + arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct SomeGoOnceableThing {
|
||||||
|
counter: Rc<Cell<int>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GoOnce for SomeGoOnceableThing {
|
||||||
|
fn go_once(self, arg: int) {
|
||||||
|
self.counter.set(self.counter.get() + arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let counter = Rc::new(Cell::new(0));
|
||||||
|
let mut x = SomeGoableThing { counter: counter.clone() };
|
||||||
|
|
||||||
|
go(&x, 10);
|
||||||
|
assert_eq!(counter.get(), 10);
|
||||||
|
|
||||||
|
go_mut(&mut x, 100);
|
||||||
|
assert_eq!(counter.get(), 110);
|
||||||
|
|
||||||
|
go_once(x, 1_000);
|
||||||
|
assert_eq!(counter.get(), 1_110);
|
||||||
|
|
||||||
|
let x = SomeGoOnceableThing { counter: counter.clone() };
|
||||||
|
|
||||||
|
go_once(x, 10_000);
|
||||||
|
assert_eq!(counter.get(), 11_110);
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Test that if there is one impl we can infer everything.
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
trait Convert<Target> {
|
||||||
|
fn convert(&self) -> Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Convert<u32> for i16 {
|
||||||
|
fn convert(&self) -> u32 {
|
||||||
|
*self as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test<T,U>(_: T, _: U, t_size: uint, u_size: uint)
|
||||||
|
where T : Convert<U>
|
||||||
|
{
|
||||||
|
assert_eq!(mem::size_of::<T>(), t_size);
|
||||||
|
assert_eq!(mem::size_of::<U>(), u_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// T = i16, U = u32
|
||||||
|
test(22, 44, 2, 4);
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Test that we can infer the Target based on the Self or vice versa.
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
trait Convert<Target> {
|
||||||
|
fn convert(&self) -> Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Convert<u32> for i16 {
|
||||||
|
fn convert(&self) -> u32 {
|
||||||
|
*self as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Convert<i16> for u32 {
|
||||||
|
fn convert(&self) -> i16 {
|
||||||
|
*self as i16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test<T,U>(_: T, _: U, t_size: uint, u_size: uint)
|
||||||
|
where T : Convert<U>
|
||||||
|
{
|
||||||
|
assert_eq!(mem::size_of::<T>(), t_size);
|
||||||
|
assert_eq!(mem::size_of::<U>(), u_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// T = i16, U = u32
|
||||||
|
test(22_i16, 44, 2, 4);
|
||||||
|
test(22, 44_u32, 2, 4);
|
||||||
|
|
||||||
|
// T = u32, U = i16
|
||||||
|
test(22_u32, 44, 4, 2);
|
||||||
|
test(22, 44_i16, 4, 2);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue