auto merge of #18121 : nikomatsakis/rust/method-call-use-trait-matching-infrastructure-2, r=pcwalton

Convert trait method dispatch to use new trait matching machinery.

This fixes about 90% of #17918. What remains to be done is to make inherent dispatch work with conditional dispatch as well. I plan to do this in a future patch by generalizing the "method match" code slightly to work for inherent impls as well (the basic algorithm is precisely the same).

Fixes #17178.

This is a [breaking-change] for two reasons:

1. The old code was a bit broken. I found various minor cases, particularly around operators, where the old code incorrectly matched, but an extra `*` or other change is now required. (See commit e8cef25 ("Correct case where the old version of method lookup...") for examples.)
2. The old code didn't type check calls against the method signature from the *trait* but rather the *impl*. The two can be different in subtle ways. This makes the new method dispatch both more liberal and more conservative than the original. (See commit 8308332 ("The new method lookup mechanism typechecks...") for examples.)

r? @pcwalton since he's been reviewing most of this series of changes
f? @nick29581 for commit 39df55f ("Permit DST types to unify like other types")
cc @aturon as this relates to library stabilization
This commit is contained in:
bors 2014-10-22 00:22:04 +00:00
commit 3d2cf60631
38 changed files with 1465 additions and 865 deletions

View File

@ -1374,7 +1374,7 @@ macro_rules! checkeddiv_int_impl(
if *v == 0 || (*self == $min && *v == -1) {
None
} else {
Some(self / *v)
Some(*self / *v)
}
}
}
@ -1395,7 +1395,7 @@ macro_rules! checkeddiv_uint_impl(
if *v == 0 {
None
} else {
Some(self / *v)
Some(*self / *v)
}
}
}

View File

@ -638,7 +638,7 @@ shr_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64)
* ```
*/
#[lang="index"]
pub trait Index<Index, Result> {
pub trait Index<Index, Sized? Result> {
/// The method for the indexing (`Foo[Bar]`) operation
fn index<'a>(&'a self, index: &Index) -> &'a Result;
}

View File

@ -142,8 +142,8 @@ impl<'a, 'tcx> dot::Labeller<'a, Node<'a>, Edge<'a>> for DataflowLabeller<'a, 't
}
impl<'a, 'tcx> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for DataflowLabeller<'a, 'tcx> {
fn nodes(&self) -> dot::Nodes<'a, Node<'a>> { self.inner.nodes() }
fn edges(&self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() }
fn source(&self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) }
fn target(&self, edge: &Edge<'a>) -> Node<'a> { self.inner.target(edge) }
fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.inner.nodes() }
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() }
fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) }
fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.target(edge) }
}

View File

@ -91,19 +91,19 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
}
impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for &'a cfg::CFG {
fn nodes(&self) -> dot::Nodes<'a, Node<'a>> {
fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> {
let mut v = Vec::new();
self.graph.each_node(|i, nd| { v.push((i, nd)); true });
dot::maybe_owned_vec::Growable(v)
}
fn edges(&self) -> dot::Edges<'a, Edge<'a>> {
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> {
self.graph.all_edges().iter().collect()
}
fn source(&self, edge: &Edge<'a>) -> Node<'a> {
fn source(&'a self, edge: &Edge<'a>) -> Node<'a> {
let i = edge.source();
(i, self.graph.node(i))
}
fn target(&self, edge: &Edge<'a>) -> Node<'a> {
fn target(&'a self, edge: &Edge<'a>) -> Node<'a> {
let i = edge.target();
(i, self.graph.node(i))
}
@ -111,9 +111,9 @@ impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for &'a cfg::CFG {
impl<'a, 'ast> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast>
{
fn nodes(&self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() }
fn edges(&self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() }
fn source(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) }
fn target(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) }
fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() }
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() }
fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) }
fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) }
}

View File

@ -272,4 +272,11 @@ nested obligation `int : Bar<U>` to find out that `U=uint`.
It would be good to only do *just as much* nested resolution as
necessary. Currently, though, we just do a full resolution.
## Method matching
Method dispach follows a slightly different path than normal trait
selection. This is because it must account for the transformed self
type of the receiver and various other complications. The procedure is
described in `select.rs` in the "METHOD MATCHING" section.
*/

View File

@ -24,6 +24,8 @@ use syntax::codemap::{Span, DUMMY_SP};
pub use self::fulfill::FulfillmentContext;
pub use self::select::SelectionContext;
pub use self::select::SelectionCache;
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
pub use self::util::supertraits;
pub use self::util::transitive_bounds;
pub use self::util::Supertraits;
@ -219,22 +221,6 @@ pub struct VtableParamData {
pub bound: Rc<ty::TraitRef>,
}
pub fn evaluate_obligation<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment,
obligation: &Obligation,
typer: &Typer<'tcx>)
-> bool
{
/*!
* Attempts to resolve the obligation given. Returns `None` if
* we are unable to resolve, either because of ambiguity or
* due to insufficient inference.
*/
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
selcx.evaluate_obligation(obligation)
}
pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment,
typer: &Typer<'tcx>,

View File

@ -62,6 +62,23 @@ pub struct SelectionCache {
hashmap: RefCell<HashMap<Rc<ty::TraitRef>, SelectionResult<Candidate>>>,
}
pub enum MethodMatchResult {
MethodMatched(MethodMatchedData),
MethodAmbiguous(/* list of impls that could apply */ Vec<ast::DefId>),
MethodDidNotMatch,
}
#[deriving(Show)]
pub enum MethodMatchedData {
// In the case of a precise match, we don't really need to store
// how the match was found. So don't.
PreciseMethodMatch,
// In the case of a coercion, we need to know the precise impl so
// that we can determine the type to which things were coerced.
CoerciveMethodMatch(/* impl we matched */ ast::DefId)
}
/**
* The selection process begins by considering all impls, where
* clauses, and so forth that might resolve an obligation. Sometimes
@ -190,27 +207,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
///////////////////////////////////////////////////////////////////////////
// EVALUATION
//
// Tests whether an obligation can be selected or whether an impl can be
// applied to particular types. It skips the "confirmation" step and
// hence completely ignores output type parameters.
// Tests whether an obligation can be selected or whether an impl
// can be applied to particular types. It skips the "confirmation"
// step and hence completely ignores output type parameters.
//
// The result is "true" if the obliation *may* hold and "false" if
// we can be sure it does not.
pub fn evaluate_obligation(&mut self,
obligation: &Obligation)
-> bool
pub fn evaluate_obligation_intercrate(&mut self,
obligation: &Obligation)
-> bool
{
/*!
* Evaluates whether the obligation `obligation` can be
* satisfied (by any means).
* satisfied (by any means). This "intercrate" version allows
* for the possibility that unbound type variables may be
* instantiated with types from another crate. This is
* important for coherence. In practice this means that
* unbound type variables must always be considered ambiguous.
*/
debug!("evaluate_obligation({})",
debug!("evaluate_obligation_intercrate({})",
obligation.repr(self.tcx()));
let stack = self.push_stack(None, obligation);
self.evaluate_stack(&stack).may_apply()
self.evaluate_stack_intercrate(&stack).may_apply()
}
pub fn evaluate_obligation_intracrate(&mut self,
obligation: &Obligation)
-> bool
{
/*!
* Evaluates whether the obligation `obligation` can be
* satisfied (by any means). This "intracrate" version does
* not allow for the possibility that unbound type variables
* may be instantiated with types from another crate; hence,
* if there are unbound inputs but no crates locally visible,
* it considers the result to be unimplemented.
*/
debug!("evaluate_obligation_intracrate({})",
obligation.repr(self.tcx()));
let stack = self.push_stack(None, obligation);
self.evaluate_stack_intracrate(&stack).may_apply()
}
fn evaluate_builtin_bound_recursively(&mut self,
@ -246,12 +287,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.repr(self.tcx()));
let stack = self.push_stack(previous_stack.map(|x| x), obligation);
let result = self.evaluate_stack(&stack);
// FIXME(#17901) -- Intercrate vs intracrate resolution is a
// tricky question here. For coherence, we want
// intercrate. Also, there was a nasty cycle around impls like
// `impl<T:Eq> Eq for Vec<T>` (which would wind up checking
// whether `$0:Eq`, where $0 was the value substituted for
// `T`, which could then be checked against the very same
// impl). This problem is avoided by the stricter rules around
// unbound type variables by intercrate. I suspect that in the
// latter case a more fine-grained rule would suffice (i.e.,
// consider it ambiguous if even 1 impl matches, no need to
// figure out which one, but call it unimplemented if 0 impls
// match).
let result = self.evaluate_stack_intercrate(&stack);
debug!("result: {}", result);
result
}
fn evaluate_stack(&mut self,
fn evaluate_stack_intercrate(&mut self,
stack: &ObligationStack)
-> EvaluationResult
{
@ -259,13 +314,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// an impl. Even if there are no impls in this crate, perhaps
// the type would be unified with something from another crate
// that does provide an impl.
let input_types = &stack.skol_trait_ref.substs.types;
let input_types = stack.skol_trait_ref.input_types();
if input_types.iter().any(|&t| ty::type_is_skolemized(t)) {
debug!("evaluate_stack({}) --> unbound argument, must be ambiguous",
debug!("evaluate_stack_intercrate({}) --> unbound argument, must be ambiguous",
stack.skol_trait_ref.repr(self.tcx()));
return EvaluatedToAmbig;
}
self.evaluate_stack_intracrate(stack)
}
fn evaluate_stack_intracrate(&mut self,
stack: &ObligationStack)
-> EvaluationResult
{
// If there is any previous entry on the stack that precisely
// matches this obligation, then we can assume that the
// obligation is satisfied for now (still all other conditions
@ -290,7 +352,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.skip(1) // skip top-most frame
.any(|prev| stack.skol_trait_ref == prev.skol_trait_ref)
{
debug!("evaluate_stack({}) --> recursive",
debug!("evaluate_stack_intracrate({}) --> recursive",
stack.skol_trait_ref.repr(self.tcx()));
return EvaluatedToOk;
}
@ -320,7 +382,311 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx.probe(|| {
match self.match_impl(impl_def_id, obligation) {
Ok(substs) => {
let vtable_impl = self.vtable_impl(impl_def_id, substs, obligation.cause, 0);
let vtable_impl = self.vtable_impl(impl_def_id,
substs,
obligation.cause,
obligation.recursion_depth + 1);
self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
}
Err(()) => {
false
}
}
})
}
///////////////////////////////////////////////////////////////////////////
// METHOD MATCHING
//
// Method matching is a variation on the normal select/evaluation
// situation. In this scenario, rather than having a full trait
// reference to select from, we start with an expression like
// `receiver.method(...)`. This means that we have `rcvr_ty`, the
// type of the receiver, and we have a possible trait that
// supplies `method`. We must determine whether the receiver is
// applicable, taking into account the transformed self type
// declared on `method`. We also must consider the possibility
// that `receiver` can be *coerced* into a suitable type (for
// example, a receiver type like `&(Any+Send)` might be coerced
// into a receiver like `&Any` to allow for method dispatch). See
// the body of `evaluate_method_obligation()` for more details on
// the algorithm.
pub fn evaluate_method_obligation(&mut self,
rcvr_ty: ty::t,
xform_self_ty: ty::t,
obligation: &Obligation)
-> MethodMatchResult
{
/*!
* Determine whether a trait-method is applicable to a receiver of
* type `rcvr_ty`. *Does not affect the inference state.*
*
* - `rcvr_ty` -- type of the receiver
* - `xform_self_ty` -- transformed self type declared on the method, with `Self`
* to a fresh type variable
* - `obligation` -- a reference to the trait where the method is declared, with
* the input types on the trait replaced with fresh type variables
*/
// Here is the situation. We have a trait method declared (say) like so:
//
// trait TheTrait {
// fn the_method(self: Rc<Self>, ...) { ... }
// }
//
// And then we have a call looking (say) like this:
//
// let x: Rc<Foo> = ...;
// x.the_method()
//
// Now we want to decide if `TheTrait` is applicable. As a
// human, we can see that `TheTrait` is applicable if there is
// an impl for the type `Foo`. But how does the compiler know
// what impl to look for, given that our receiver has type
// `Rc<Foo>`? We need to take the method's self type into
// account.
//
// On entry to this function, we have the following inputs:
//
// - `rcvr_ty = Rc<Foo>`
// - `xform_self_ty = Rc<$0>`
// - `obligation = $0 as TheTrait`
//
// We do the match in two phases. The first is a *precise
// match*, which means that no coercion is required. This is
// the preferred way to match. It works by first making
// `rcvr_ty` a subtype of `xform_self_ty`. This unifies `$0`
// and `Foo`. We can then evaluate (roughly as normal) the
// trait reference `Foo as TheTrait`.
//
// If this fails, we fallback to a coercive match, described below.
match self.infcx.probe(|| self.match_method_precise(rcvr_ty, xform_self_ty, obligation)) {
Ok(()) => { return MethodMatched(PreciseMethodMatch); }
Err(_) => { }
}
// Coercive matches work slightly differently and cannot
// completely reuse the normal trait matching machinery
// (though they employ many of the same bits and pieces). To
// see how it works, let's continue with our previous example,
// but with the following declarations:
//
// ```
// trait Foo : Bar { .. }
// trait Bar : Baz { ... }
// trait Baz { ... }
// impl TheTrait for Bar {
// fn the_method(self: Rc<Bar>, ...) { ... }
// }
// ```
//
// Now we see that the receiver type `Rc<Foo>` is actually an
// object type. And in fact the impl we want is an impl on the
// supertrait `Rc<Bar>`. The precise matching procedure won't
// find it, however, because `Rc<Foo>` is not a subtype of
// `Rc<Bar>` -- it is *coercible* to `Rc<Bar>` (actually, such
// coercions are not yet implemented, but let's leave that
// aside for now).
//
// To handle this case, we employ a different procedure. Recall
// that our initial state is as follows:
//
// - `rcvr_ty = Rc<Foo>`
// - `xform_self_ty = Rc<$0>`
// - `obligation = $0 as TheTrait`
//
// We now go through each impl and instantiate all of its type
// variables, yielding the trait reference that the impl
// provides. In our example, the impl would provide `Bar as
// TheTrait`. Next we (try to) unify the trait reference that
// the impl provides with the input obligation. This would
// unify `$0` and `Bar`. Now we can see whether the receiver
// type (`Rc<Foo>`) is *coercible to* the transformed self
// type (`Rc<$0> == Rc<Bar>`). In this case, the answer is
// yes, so the impl is considered a candidate.
//
// Note that there is the possibility of ambiguity here, even
// when all types are known. In our example, this might occur
// if there was *also* an impl of `TheTrait` for `Baz`. In
// this case, `Rc<Foo>` would be coercible to both `Rc<Bar>`
// and `Rc<Baz>`. (Note that it is not a *coherence violation*
// to have impls for both `Bar` and `Baz`, despite this
// ambiguity). In this case, we report an error, listing all
// the applicable impls. The use can explicitly "up-coerce"
// to the type they want.
//
// Note that this coercion step only considers actual impls
// found in the source. This is because all the
// compiler-provided impls (such as those for unboxed
// closures) do not have relevant coercions. This simplifies
// life immensely.
let mut impls =
self.assemble_method_candidates_from_impls(rcvr_ty, xform_self_ty, obligation);
if impls.len() > 1 {
impls.retain(|&c| self.winnow_method_impl(c, rcvr_ty, xform_self_ty, obligation));
}
if impls.len() > 1 {
return MethodAmbiguous(impls);
}
match impls.pop() {
Some(def_id) => MethodMatched(CoerciveMethodMatch(def_id)),
None => MethodDidNotMatch
}
}
pub fn confirm_method_match(&mut self,
rcvr_ty: ty::t,
xform_self_ty: ty::t,
obligation: &Obligation,
data: MethodMatchedData)
{
/*!
* Given the successful result of a method match, this
* function "confirms" the result, which basically repeats the
* various matching operations, but outside of any snapshot so
* that their effects are committed into the inference state.
*/
let is_ok = match data {
PreciseMethodMatch => {
self.match_method_precise(rcvr_ty, xform_self_ty, obligation).is_ok()
}
CoerciveMethodMatch(impl_def_id) => {
self.match_method_coerce(impl_def_id, rcvr_ty, xform_self_ty, obligation).is_ok()
}
};
if !is_ok {
self.tcx().sess.span_bug(
obligation.cause.span,
format!("match not repeatable: {}, {}, {}, {}",
rcvr_ty.repr(self.tcx()),
xform_self_ty.repr(self.tcx()),
obligation.repr(self.tcx()),
data)[]);
}
}
fn match_method_precise(&mut self,
rcvr_ty: ty::t,
xform_self_ty: ty::t,
obligation: &Obligation)
-> Result<(),()>
{
/*!
* Implements the *precise method match* procedure described in
* `evaluate_method_obligation()`.
*/
self.infcx.commit_if_ok(|| {
match self.infcx.sub_types(false, infer::RelateSelfType(obligation.cause.span),
rcvr_ty, xform_self_ty) {
Ok(()) => { }
Err(_) => { return Err(()); }
}
if self.evaluate_obligation_intracrate(obligation) {
Ok(())
} else {
Err(())
}
})
}
fn assemble_method_candidates_from_impls(&mut self,
rcvr_ty: ty::t,
xform_self_ty: ty::t,
obligation: &Obligation)
-> Vec<ast::DefId>
{
/*!
* Assembles a list of potentially applicable impls using the
* *coercive match* procedure described in
* `evaluate_method_obligation()`.
*/
let mut candidates = Vec::new();
let all_impls = self.all_impls(obligation.trait_ref.def_id);
for &impl_def_id in all_impls.iter() {
self.infcx.probe(|| {
match self.match_method_coerce(impl_def_id, rcvr_ty, xform_self_ty, obligation) {
Ok(_) => { candidates.push(impl_def_id); }
Err(_) => { }
}
});
}
candidates
}
fn match_method_coerce(&mut self,
impl_def_id: ast::DefId,
rcvr_ty: ty::t,
xform_self_ty: ty::t,
obligation: &Obligation)
-> Result<Substs, ()>
{
/*!
* Applies the *coercive match* procedure described in
* `evaluate_method_obligation()` to a particular impl.
*/
// This is almost always expected to succeed. It
// causes the impl's self-type etc to be unified with
// the type variable that is shared between
// obligation/xform_self_ty. In our example, after
// this is done, the type of `xform_self_ty` would
// change from `Rc<$0>` to `Rc<Foo>` (because $0 is
// unified with `Foo`).
let substs = try!(self.match_impl(impl_def_id, obligation));
// Next, check whether we can coerce. For now we require
// that the coercion be a no-op.
let origin = infer::Misc(obligation.cause.span);
match infer::mk_coercety(self.infcx, true, origin,
rcvr_ty, xform_self_ty) {
Ok(None) => { /* Fallthrough */ }
Ok(Some(_)) | Err(_) => { return Err(()); }
}
Ok(substs)
}
fn winnow_method_impl(&mut self,
impl_def_id: ast::DefId,
rcvr_ty: ty::t,
xform_self_ty: ty::t,
obligation: &Obligation)
-> bool
{
/*!
* A version of `winnow_impl` applicable to coerice method
* matching. This is basically the same as `winnow_impl` but
* it uses the method matching procedure and is specific to
* impls.
*/
debug!("winnow_method_impl: impl_def_id={} rcvr_ty={} xform_self_ty={} obligation={}",
impl_def_id.repr(self.tcx()),
rcvr_ty.repr(self.tcx()),
xform_self_ty.repr(self.tcx()),
obligation.repr(self.tcx()));
self.infcx.probe(|| {
match self.match_method_coerce(impl_def_id, rcvr_ty, xform_self_ty, obligation) {
Ok(substs) => {
let vtable_impl = self.vtable_impl(impl_def_id,
substs,
obligation.cause,
obligation.recursion_depth + 1);
self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
}
Err(()) => {
@ -456,24 +822,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Ok(None);
}
// If there are *NO* candidates, that might mean either that
// there is no impl or just that we can't know anything for
// sure.
// If there are *NO* candidates, that there are no impls --
// that we know of, anyway. Note that in the case where there
// are unbound type variables within the obligation, it might
// be the case that you could still satisfy the obligation
// from another crate by instantiating the type variables with
// a type from another crate that does have an impl. This case
// is checked for in `evaluate_obligation` (and hence users
// who might care about this case, like coherence, should use
// that function).
if candidates.len() == 0 {
// Annoying edge case: if there are no impls, then there
// is no way that this trait reference is implemented,
// *unless* it contains unbound variables. In that case,
// it is possible that one of those unbound variables will
// be bound to a new type from some other crate which will
// also contain impls.
let skol_obligation_self_ty = self.infcx.skolemize(stack.obligation.self_ty());
return if !self.contains_skolemized_types(skol_obligation_self_ty) {
debug!("0 matches, unimpl");
Err(Unimplemented)
} else {
debug!("0 matches, ambig");
Ok(None)
};
return Err(Unimplemented);
}
// Just one candidate left.
@ -491,7 +850,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// scope. Otherwise, use the generic tcx cache, since the
// result holds across all environments.
if
cache_skol_trait_ref.substs.types.iter().any(
cache_skol_trait_ref.input_types().iter().any(
|&t| ty::type_has_self(t) || ty::type_has_params(t))
{
&self.param_env.selection_cache
@ -1291,8 +1650,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// it'll do for now until we get the new trait-bound
// region skolemization working.
let (_, new_signature) =
regionmanip::replace_late_bound_regions_in_fn_sig(
regionmanip::replace_late_bound_regions(
self.tcx(),
closure_type.sig.binder_id,
&closure_type.sig,
|br| self.infcx.next_region_var(
infer::LateBoundRegion(obligation.cause.span, br)));
@ -1365,6 +1725,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
trait_ref: Rc<ty::TraitRef>)
-> Result<(),()>
{
debug!("match_trait_refs: obligation={} trait_ref={}",
obligation.repr(self.tcx()),
trait_ref.repr(self.tcx()));
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
match self.infcx.sub_trait_refs(false,
origin,
@ -1648,3 +2012,13 @@ impl EvaluationResult {
}
}
}
impl MethodMatchResult {
pub fn may_apply(&self) -> bool {
match *self {
MethodMatched(_) => true,
MethodAmbiguous(_) => true,
MethodDidNotMatch => false,
}
}
}

View File

@ -120,6 +120,13 @@ impl ImplOrTraitItem {
TypeTraitItem(ref associated_type) => associated_type.container,
}
}
pub fn as_opt_method(&self) -> Option<Rc<Method>> {
match *self {
MethodTraitItem(ref m) => Some((*m).clone()),
TypeTraitItem(_) => None
}
}
}
#[deriving(Clone)]
@ -1240,9 +1247,21 @@ impl Generics {
}
impl TraitRef {
pub fn new(def_id: ast::DefId, substs: Substs) -> TraitRef {
TraitRef { def_id: def_id, substs: substs }
}
pub fn self_ty(&self) -> ty::t {
self.substs.self_ty().unwrap()
}
pub fn input_types(&self) -> &[ty::t] {
// Select only the "input types" from a trait-reference. For
// now this is all the types that appear in the
// trait-reference, but it should eventually exclude
// associated types.
self.substs.types.as_slice()
}
}
/// When type checking, we use the `ParameterEnvironment` to track

File diff suppressed because it is too large Load Diff

View File

@ -77,6 +77,7 @@ type parameter).
*/
use driver::session::Session;
use middle::const_eval;
use middle::def;
use middle::lang_items::IteratorItem;
@ -97,11 +98,8 @@ use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
use middle::typeck::astconv;
use middle::typeck::check::_match::pat_ctxt;
use middle::typeck::check::method::{AutoderefReceiver};
use middle::typeck::check::method::{AutoderefReceiverFlag};
use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
use middle::typeck::check::method::{DontAutoderefReceiver};
use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods};
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::check::regionmanip::replace_late_bound_regions;
use middle::typeck::CrateCtxt;
use middle::typeck::infer::{resolve_type, force_tvar};
use middle::typeck::infer;
@ -529,7 +527,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
// First, we have to replace any bound regions in the fn type with free ones.
// The free region references will be bound the node_id of the body block.
let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
let (_, fn_sig) = replace_late_bound_regions(tcx, fn_sig.binder_id, fn_sig, |br| {
ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
});
@ -1531,6 +1529,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self.inh.infcx
}
pub fn sess(&self) -> &Session {
&self.tcx().sess
}
pub fn err_count_since_creation(&self) -> uint {
self.ccx.tcx.sess.err_count() - self.err_count_on_creation
}
@ -2117,9 +2119,7 @@ fn try_overloaded_call<'a>(fcx: &FnCtxt,
method_name,
function_trait,
callee_type,
[],
DontAutoderefReceiver,
IgnoreStaticMethods) {
[]) {
None => continue,
Some(method_callee) => method_callee,
};
@ -2160,7 +2160,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
(PreferMutLvalue, Some(trait_did)) => {
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
token::intern("deref_mut"), trait_did,
base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
base_ty, [])
}
_ => None
};
@ -2170,7 +2170,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
(None, Some(trait_did)) => {
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
token::intern("deref"), trait_did,
base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
base_ty, [])
}
(method, _) => method
};
@ -2231,9 +2231,7 @@ fn try_overloaded_slice(fcx: &FnCtxt,
token::intern(method_name),
trait_did,
base_ty,
[],
DontAutoderefReceiver,
IgnoreStaticMethods)
[])
}
_ => None,
}
@ -2256,9 +2254,7 @@ fn try_overloaded_slice(fcx: &FnCtxt,
token::intern(method_name),
trait_did,
base_ty,
[],
DontAutoderefReceiver,
IgnoreStaticMethods)
[])
}
_ => None,
}
@ -2314,9 +2310,7 @@ fn try_overloaded_index(fcx: &FnCtxt,
token::intern("index_mut"),
trait_did,
base_ty,
[],
DontAutoderefReceiver,
IgnoreStaticMethods)
[])
}
_ => None,
};
@ -2330,9 +2324,7 @@ fn try_overloaded_index(fcx: &FnCtxt,
token::intern("index"),
trait_did,
base_ty,
[],
DontAutoderefReceiver,
IgnoreStaticMethods)
[])
}
(method, _) => method,
};
@ -2376,9 +2368,7 @@ fn lookup_method_for_for_loop(fcx: &FnCtxt,
token::intern("next"),
trait_did,
expr_type,
[],
DontAutoderefReceiver,
IgnoreStaticMethods);
[]);
// Regardless of whether the lookup succeeds, check the method arguments
// so that we have *some* type for each argument.
@ -2902,7 +2892,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
// Replace any bound regions that appear in the function
// signature with region variables
let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
let (_, fn_sig) = replace_late_bound_regions(fcx.tcx(), fn_sig.binder_id, fn_sig, |br| {
fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br))
});
@ -2935,46 +2925,24 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
fcx.expr_ty(&*rcvr));
let tps = tps.iter().map(|ast_ty| fcx.to_ty(&**ast_ty)).collect::<Vec<_>>();
let fn_ty = match method::lookup(fcx, expr, &*rcvr,
let fn_ty = match method::lookup(fcx,
expr,
&*rcvr,
method_name.node.name,
expr_t, tps.as_slice(),
expr_t,
tps.as_slice(),
DontDerefArgs,
CheckTraitsAndInherentMethods,
AutoderefReceiver, IgnoreStaticMethods) {
Some(method) => {
AutoderefReceiver) {
Ok(method) => {
let method_ty = method.ty;
let method_call = MethodCall::expr(expr.id);
fcx.inh.method_map.borrow_mut().insert(method_call, method);
method_ty
}
None => {
debug!("(checking method call) failing expr is {}", expr.id);
fcx.type_error_message(method_name.span,
|actual| {
format!("type `{}` does not implement any \
method in scope named `{}`",
actual,
token::get_ident(method_name.node))
},
expr_t,
None);
// Add error type for the result
Err(error) => {
method::report_error(fcx, method_name.span, expr_t, method_name.node.name, error);
fcx.write_error(expr.id);
// Check for potential static matches (missing self parameters)
method::lookup(fcx,
expr,
&*rcvr,
method_name.node.name,
expr_t,
tps.as_slice(),
DontDerefArgs,
CheckTraitsAndInherentMethods,
DontAutoderefReceiver,
ReportStaticMethods);
ty::mk_err()
}
};
@ -3069,13 +3037,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
trait_did: Option<ast::DefId>,
lhs: &'a ast::Expr,
rhs: Option<&P<ast::Expr>>,
autoderef_receiver: AutoderefReceiverFlag,
unbound_method: ||) -> ty::t {
let method = match trait_did {
Some(trait_did) => {
method::lookup_in_trait(fcx, op_ex.span, Some(lhs), opname,
trait_did, lhs_ty, &[], autoderef_receiver,
IgnoreStaticMethods)
trait_did, lhs_ty, &[])
}
None => None
};
@ -3249,7 +3215,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
}
};
lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
trait_did, lhs_expr, Some(rhs), DontAutoderefReceiver, || {
trait_did, lhs_expr, Some(rhs), || {
fcx.type_error_message(ex.span, |actual| {
format!("binary operation `{}` cannot be applied to type `{}`",
ast_util::binop_to_string(op),
@ -3266,7 +3232,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
rhs_expr: &ast::Expr,
rhs_t: ty::t) -> ty::t {
lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
trait_did, rhs_expr, None, DontAutoderefReceiver, || {
trait_did, rhs_expr, None, || {
fcx.type_error_message(ex.span, |actual| {
format!("cannot apply unary operator `{}` to type `{}`",
op_str, actual)
@ -3360,8 +3326,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
match expected_sty {
Some(ty::ty_closure(ref cenv)) => {
let (_, sig) =
replace_late_bound_regions_in_fn_sig(
tcx, &cenv.sig,
replace_late_bound_regions(
tcx, cenv.sig.binder_id, &cenv.sig,
|_| fcx.inh.infcx.fresh_bound_region(expr.id));
let onceness = match (&store, &cenv.store) {
// As the closure type and onceness go, only three
@ -3479,9 +3445,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
tps.as_slice(),
DontDerefArgs,
CheckTraitsAndInherentMethods,
AutoderefReceiver,
IgnoreStaticMethods) {
Some(_) => {
AutoderefReceiver) {
Ok(_) => {
fcx.type_error_message(
field.span,
|actual| {
@ -3494,7 +3459,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
"maybe a missing `()` to call it? If not, try an anonymous function.");
}
None => {
Err(_) => {
fcx.type_error_message(
expr.span,
|actual| {

View File

@ -13,7 +13,7 @@
use middle::subst::{ParamSpace, Subst, Substs};
use middle::ty;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use middle::ty_fold::{TypeFolder, TypeFoldable};
use syntax::ast;
@ -23,31 +23,34 @@ use util::ppaux::Repr;
// Helper functions related to manipulating region types.
pub fn replace_late_bound_regions_in_fn_sig(
tcx: &ty::ctxt,
fn_sig: &ty::FnSig,
mapf: |ty::BoundRegion| -> ty::Region)
-> (HashMap<ty::BoundRegion,ty::Region>, ty::FnSig) {
debug!("replace_late_bound_regions_in_fn_sig({})", fn_sig.repr(tcx));
pub fn replace_late_bound_regions<T>(
tcx: &ty::ctxt,
binder_id: ast::NodeId,
value: &T,
map_fn: |ty::BoundRegion| -> ty::Region)
-> (HashMap<ty::BoundRegion,ty::Region>, T)
where T : TypeFoldable + Repr
{
debug!("replace_late_bound_regions(binder_id={}, value={})",
binder_id, value.repr(tcx));
let mut map = HashMap::new();
let fn_sig = {
let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
debug!("region r={}", r.to_string());
let new_value = {
let mut folder = ty_fold::RegionFolder::regions(tcx, |r| {
match r {
ty::ReLateBound(s, br) if s == fn_sig.binder_id => {
* match map.entry(br) {
Vacant(entry) => entry.set(mapf(br)),
Occupied(entry) => entry.into_mut(),
ty::ReLateBound(s, br) if s == binder_id => {
match map.entry(br) {
Vacant(entry) => *entry.set(map_fn(br)),
Occupied(entry) => *entry.into_mut(),
}
}
_ => r
}
});
ty_fold::super_fold_sig(&mut f, fn_sig)
value.fold_with(&mut folder)
};
debug!("resulting map: {}", map);
(map, fn_sig)
(map, new_value)
}
pub enum WfConstraint {

View File

@ -15,7 +15,7 @@ use middle::ty;
use middle::ty_fold::{TypeFolder, TypeFoldable};
use middle::typeck::astconv::AstConv;
use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable2, regionck};
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::check::regionmanip::replace_late_bound_regions;
use middle::typeck::CrateCtxt;
use util::ppaux::Repr;
@ -373,8 +373,8 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
self.binding_count += 1;
let (_, fn_sig) =
replace_late_bound_regions_in_fn_sig(
self.fcx.tcx(), fn_sig,
replace_late_bound_regions(
self.fcx.tcx(), fn_sig.binder_id, fn_sig,
|br| ty::ReFree(ty::FreeRegion{scope_id: self.scope_id,
bound_region: br}));

View File

@ -72,7 +72,6 @@ use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
use middle::typeck::infer::combine::{CombineFields, Combine};
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
use util::common::indenter;
use util::ppaux;
use util::ppaux::Repr;
@ -93,7 +92,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
debug!("Coerce.tys({} => {})",
a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
let _indent = indenter();
// Special case: if the subtype is a sized array literal (`[T, ..n]`),
// then it would get auto-borrowed to `&[T, ..n]` and then DST-ified
@ -411,7 +409,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.unpack_actual_value(ty_b, |sty_b|
match (sty_a, sty_b) {
(&ty::ty_vec(t_a, Some(len)), _) => {
(&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
let ty = ty::mk_vec(tcx, t_a, None);
Some((ty, ty::UnsizeLength(len)))
}

View File

@ -363,28 +363,6 @@ pub fn super_fn_sigs<'tcx, C: Combine<'tcx>>(this: &C,
pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
// This is a horrible hack - historically, [T] was not treated as a type,
// so, for example, &T and &[U] should not unify. In fact the only thing
// &[U] should unify with is &[T]. We preserve that behaviour with this
// check.
fn check_ptr_to_unsized<'tcx, C: Combine<'tcx>>(this: &C,
a: ty::t,
b: ty::t,
a_inner: ty::t,
b_inner: ty::t,
result: ty::t) -> cres<ty::t> {
match (&ty::get(a_inner).sty, &ty::get(b_inner).sty) {
(&ty::ty_vec(_, None), &ty::ty_vec(_, None)) |
(&ty::ty_str, &ty::ty_str) |
(&ty::ty_trait(..), &ty::ty_trait(..)) => Ok(result),
(&ty::ty_vec(_, None), _) | (_, &ty::ty_vec(_, None)) |
(&ty::ty_str, _) | (_, &ty::ty_str) |
(&ty::ty_trait(..), _) | (_, &ty::ty_trait(..))
=> Err(ty::terr_sorts(expected_found(this, a, b))),
_ => Ok(result),
}
}
let tcx = this.infcx().tcx;
let a_sty = &ty::get(a).sty;
let b_sty = &ty::get(b).sty;
@ -402,6 +380,10 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
b.repr(this.infcx().tcx)).as_slice());
}
(&ty::ty_err, _) | (_, &ty::ty_err) => {
Ok(ty::mk_err())
}
// Relate integral variables to other types
(&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
try!(this.infcx().simple_vars(this.a_is_expected(),
@ -442,8 +424,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
(&ty::ty_bool, _) |
(&ty::ty_int(_), _) |
(&ty::ty_uint(_), _) |
(&ty::ty_float(_), _) |
(&ty::ty_err, _) => {
(&ty::ty_float(_), _) => {
if ty::get(a).sty == ty::get(b).sty {
Ok(a)
} else {
@ -494,13 +475,13 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
}
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
let typ = try!(this.tys(a_inner, b_inner));
check_ptr_to_unsized(this, a, b, a_inner, b_inner, ty::mk_uniq(tcx, typ))
let typ = try!(this.tys(a_inner, b_inner));
Ok(ty::mk_uniq(tcx, typ))
}
(&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
let mt = try!(this.mts(a_mt, b_mt));
check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_ptr(tcx, mt))
let mt = try!(this.mts(a_mt, b_mt));
Ok(ty::mk_ptr(tcx, mt))
}
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
@ -516,7 +497,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
}
_ => try!(this.mts(a_mt, b_mt))
};
check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_rptr(tcx, r, mt))
Ok(ty::mk_rptr(tcx, r, mt))
}
(&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => {

View File

@ -28,7 +28,7 @@ use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
use middle::ty;
use middle::ty_fold;
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;
use std::cell::{RefCell};
use std::collections::HashMap;
use std::rc::Rc;
@ -962,7 +962,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
HashMap<ty::BoundRegion,
ty::Region>) {
let (map, fn_sig) =
replace_late_bound_regions_in_fn_sig(self.tcx, fsig, |br| {
replace_late_bound_regions(self.tcx, fsig.binder_id, fsig, |br| {
let rvar = self.next_region_var(
BoundRegionInFnType(trace.origin.span(), br));
debug!("Bound region {} maps to {}",

View File

@ -12,7 +12,7 @@
use middle::ty::{BuiltinBounds};
use middle::ty;
use middle::ty::TyVar;
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::check::regionmanip::replace_late_bound_regions;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::{cres, CresCompare};
use middle::typeck::infer::equate::Equate;
@ -139,30 +139,21 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
.relate_vars(a_id, SubtypeOf, b_id);
Ok(a)
}
// The vec/str check here and below is so that we don't unify
// T with [T], this is necessary so we reflect subtyping of references
// (&T does not unify with &[T]) where that in turn is to reflect
// the historical non-typedness of [T].
(&ty::ty_infer(TyVar(_)), &ty::ty_str) |
(&ty::ty_infer(TyVar(_)), &ty::ty_vec(_, None)) => {
Err(ty::terr_sorts(expected_found(self, a, b)))
}
(&ty::ty_infer(TyVar(a_id)), _) => {
try!(self.fields
.switch_expected()
.instantiate(b, SupertypeOf, a_id));
Ok(a)
}
(&ty::ty_str, &ty::ty_infer(TyVar(_))) |
(&ty::ty_vec(_, None), &ty::ty_infer(TyVar(_))) => {
Err(ty::terr_sorts(expected_found(self, a, b)))
}
(_, &ty::ty_infer(TyVar(b_id))) => {
try!(self.fields.instantiate(a, SubtypeOf, b_id));
Ok(a)
}
(&ty::ty_err, _) | (_, &ty::ty_err) => {
Ok(ty::mk_err())
}
(_, &ty::ty_bot) => {
Err(ty::terr_sorts(expected_found(self, a, b)))
}
@ -198,7 +189,7 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
// Second, we instantiate each bound region in the supertype with a
// fresh concrete region.
let (skol_map, b_sig) = {
replace_late_bound_regions_in_fn_sig(self.fields.infcx.tcx, b, |br| {
replace_late_bound_regions(self.fields.infcx.tcx, b.binder_id, b, |br| {
let skol = self.fields.infcx.region_vars.new_skolemized(br);
debug!("Bound region {} skolemized to {}",
bound_region_to_string(self.fields.infcx.tcx, "", false, br),

View File

@ -536,6 +536,14 @@ impl<'ast> Map<'ast> {
.unwrap_or_else(|| fail!("AstMap.span: could not find span for id {}", id))
}
pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span {
if def_id.krate == LOCAL_CRATE {
self.span(def_id.node)
} else {
fallback
}
}
pub fn node_to_string(&self, id: NodeId) -> String {
node_id_to_string(self, id)
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
// Check that method bounds declared on traits/impls in a cross-crate
// scenario work. This is the libary portion of the test.
// scenario work. This is the library portion of the test.
pub enum MaybeOwned<'a> {
Owned(int),
@ -24,10 +24,19 @@ pub struct Inv<'a> { // invariant w/r/t 'a
// trait, so I'll use that as the template for this test.
pub trait IntoMaybeOwned<'a> {
fn into_maybe_owned(self) -> MaybeOwned<'a>;
// Note: without this `into_inv` method, the trait is
// contravariant w/r/t `'a`, since if you look strictly at the
// interface, it only returns `'a`. This complicates the
// downstream test since it wants invariance to force an error.
// Hence we add this method.
fn into_inv(self) -> Inv<'a>;
fn bigger_region<'b:'a>(self, b: Inv<'b>);
}
impl<'a> IntoMaybeOwned<'a> for Inv<'a> {
fn into_maybe_owned(self) -> MaybeOwned<'a> { fail!() }
fn into_inv(self) -> Inv<'a> { fail!() }
fn bigger_region<'b:'a>(self, b: Inv<'b>) { fail!() }
}

View File

@ -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.
use std::fmt::Show;
use std::default::Default;
// Test that two blanket impls conflict (at least without negative
// bounds). After all, some other crate could implement Even or Odd
// for the same type (though this crate doesn't).
trait MyTrait {
fn get(&self) -> uint;
}
trait Even { }
trait Odd { }
impl Even for int { }
impl Odd for uint { }
impl<T:Even> MyTrait for T { //~ ERROR E0119
fn get(&self) -> uint { 0 }
}
impl<T:Odd> MyTrait for T {
fn get(&self) -> uint { 0 }
}
fn main() { }

View File

@ -0,0 +1,34 @@
// 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 two blanket impls conflict (at least without negative
// bounds). After all, some other crate could implement Even or Odd
// for the same type (though this crate doesn't implement them at all).
trait MyTrait {
fn get(&self) -> uint;
}
trait Even { }
trait Odd { }
impl<T:Even> MyTrait for T { //~ ERROR E0119
fn get(&self) -> uint { 0 }
}
impl<T:Odd> MyTrait for T {
fn get(&self) -> uint { 0 }
}
fn main() { }

View File

@ -8,8 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(overloaded_calls)]
fn f<'r>(p: &'r mut fn(p: &mut ())) {
p(()) //~ ERROR expected function, found `&'r mut fn(&mut ())`
p(()) //~ ERROR mismatched types: expected `&mut ()`, found `()`
}
fn main() {}

View File

@ -15,5 +15,5 @@ pub fn build_archive<'a, I: MyItem<&'a (|&uint|:'a)>>(files: I) {}
fn main() {
build_archive(&(|_| { }));
//~^ ERROR unable to infer enough type information to locate the impl of the trait `MyItem<&|&uint|
//~^ ERROR not implemented
}

View File

@ -18,6 +18,7 @@ impl<A> vec_monad<A> for Vec<A> {
let mut r = fail!();
for elt in self.iter() { r = r + f(*elt); }
//~^ ERROR the type of this value must be known
//~^^ ERROR not implemented
}
}
fn main() {

View File

@ -8,17 +8,24 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test the mechanism for warning about possible missing `self` declarations.
trait CtxtFn {
fn f8(self, uint) -> uint;
fn f9(uint) -> uint; //~ NOTE candidate #
fn f9(uint) -> uint; //~ NOTE candidate
}
trait OtherTrait {
fn f9(uint) -> uint; //~ NOTE candidate #
fn f9(uint) -> uint; //~ NOTE candidate
}
trait UnusedTrait { // This should never show up as a candidate
fn f9(uint) -> uint;
// Note: this trait is not implemented, but we can't really tell
// whether or not an impl would match anyhow without a self
// declaration to match against, so we wind up printing it as a
// candidate. This seems not unreasonable -- perhaps the user meant to
// implement it, after all.
trait UnusedTrait {
fn f9(uint) -> uint; //~ NOTE candidate
}
impl CtxtFn for uint {
@ -40,13 +47,13 @@ impl OtherTrait for uint {
struct MyInt(int);
impl MyInt {
fn fff(i: int) -> int { //~ NOTE candidate #1 is `MyInt::fff`
fn fff(i: int) -> int { //~ NOTE candidate
i
}
}
trait ManyImplTrait {
fn is_str() -> bool { //~ NOTE candidate #1 is
fn is_str() -> bool { //~ NOTE candidate
false
}
}

View File

@ -0,0 +1,44 @@
// Copyright 2012 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 when we pick a trait based on coercion, versus subtyping,
// we consider all possible coercions equivalent and don't try to pick
// a best one.
trait Object { }
trait foo {
fn foo(self) -> int;
}
impl foo for Box<Object+'static> {
fn foo(self) -> int {1}
}
impl foo for Box<Object+Send> {
fn foo(self) -> int {2}
}
fn test1(x: Box<Object+Send+Sync>) {
// Ambiguous because we could coerce to either impl:
x.foo(); //~ ERROR E0034
}
fn test2(x: Box<Object+Send>) {
// Not ambiguous because it is a precise match:
x.foo();
}
fn test3(x: Box<Object+'static>) {
// Not ambiguous because it is a precise match:
x.foo();
}
fn main() { }

View File

@ -0,0 +1,45 @@
// Copyright 2012 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 invoking `foo()` successfully resolves to the trait `foo`
// (prompting the mismatched types error) but does not influence the choice
// of what kind of `Vec` we have, eventually leading to a type error.
trait foo {
fn foo(&self) -> int;
}
impl foo for Vec<uint> {
fn foo(&self) -> int {1}
}
impl foo for Vec<int> {
fn foo(&self) -> int {2}
}
// This is very hokey: we have heuristics to suppress messages about
// type annotations required. But placing these two bits of code into
// distinct functions, in this order, causes us to print out both
// errors I'd like to see.
fn m1() {
// we couldn't infer the type of the vector just based on calling foo()...
let mut x = Vec::new(); //~ ERROR type annotations required
x.foo();
}
fn m2() {
let mut x = Vec::new();
// ...but we still resolved `foo()` to the trait and hence know the return type.
let y: uint = x.foo(); //~ ERROR mismatched types
}
fn main() { }

View File

@ -8,12 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test an ambiguity scenario where one copy of the method is available
// from a trait imported from another crate.
// aux-build:ambig_impl_2_lib.rs
extern crate ambig_impl_2_lib;
use ambig_impl_2_lib::me;
trait me2 {
fn me(&self) -> uint;
}
impl me2 for uint { fn me(&self) -> uint { *self } } //~ NOTE is `uint.me2::me`
fn main() { 1u.me(); } //~ ERROR multiple applicable methods in scope
//~^ NOTE is `ambig_impl_2_lib::uint.me::me`
impl me2 for uint { fn me(&self) -> uint { *self } }
fn main() { 1u.me(); } //~ ERROR E0034

View File

@ -12,9 +12,7 @@ trait A { fn foo(&self); }
trait B { fn foo(&self); }
fn foo<T:A + B>(t: T) {
t.foo(); //~ ERROR multiple applicable methods in scope
//~^ NOTE candidate #1 derives from the bound `A`
//~^^ NOTE candidate #2 derives from the bound `B`
t.foo(); //~ ERROR E0034
}
fn main() {}

View File

@ -8,12 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait Foo { fn method(&self) {} } //~ NOTE `Foo::method`
trait Bar { fn method(&self) {} } //~ NOTE `Bar::method`
// Test that we correctly report an ambiguity where two applicable traits
// are in scope and the method being invoked is a default method not
// defined directly in the impl.
trait Foo { fn method(&self) {} }
trait Bar { fn method(&self) {} }
impl Foo for uint {}
impl Bar for uint {}
fn main() {
1u.method(); //~ ERROR multiple applicable methods in scope
1u.method(); //~ ERROR E0034
}

View File

@ -0,0 +1,33 @@
// Copyright 2012 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 pick `Foo`, and also pick the `impl`, even though in
// this case the vector type `T` is not copyable. This is because
// there is no other reasonable choice. The error you see is thus
// about `T` being non-copyable, not about `Foo` being
// unimplemented. This is better for user too, since it suggests minimal
// diff requird to fix program.
trait Object { }
trait Foo {
fn foo(self) -> int;
}
impl<T:Copy> Foo for Vec<T> {
fn foo(self) -> int {1}
}
fn test1<T>(x: Vec<T>) {
x.foo();
//~^ ERROR `core::kinds::Copy` is not implemented for the type `T`
}
fn main() { }

View File

@ -18,15 +18,15 @@ use lib::Inv;
use lib::MaybeOwned;
use lib::IntoMaybeOwned;
fn call_into_maybe_owned<'a,F:IntoMaybeOwned<'a>>(f: F) {
fn call_into_maybe_owned<'x,F:IntoMaybeOwned<'x>>(f: F) {
// Exercise a code path I found to be buggy. We were not encoding
// the region parameters from the receiver correctly on trait
// methods.
f.into_maybe_owned();
}
fn call_bigger_region<'a, 'b>(a: Inv<'a>, b: Inv<'b>) {
// Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
// Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
a.bigger_region(b) //~ ERROR cannot infer
}

View File

@ -14,7 +14,7 @@ trait add {
}
fn do_add(x: Box<add+'static>, y: Box<add+'static>) -> Box<add+'static> {
x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through an object
x.plus(y) //~ ERROR E0038
}
fn main() {}

View File

@ -19,6 +19,6 @@ impl Drop for r {
fn main() {
let i = box r { b: true };
let _j = i.clone(); //~ ERROR not implemented
let _j = i.clone(); //~ ERROR not implement
println!("{}", i);
}

View File

@ -35,8 +35,8 @@ fn main() {
let r1 = vec!(box r { i: i1 });
let r2 = vec!(box r { i: i2 });
f(r1.clone(), r2.clone());
//~^ ERROR the trait `core::clone::Clone` is not implemented
//~^^ ERROR the trait `core::clone::Clone` is not implemented
//~^ ERROR does not implement any method in scope named `clone`
//~^^ ERROR does not implement any method in scope named `clone`
println!("{}", (r2, i1.get()));
println!("{}", (r1, i2.get()));
}

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[deriving(Show)]
struct r {
i:int
}
@ -23,7 +24,6 @@ fn main() {
let i = vec!(r(0));
let j = vec!(r(1));
let k = i + j;
//~^ ERROR not implemented
//~^ ERROR binary operation `+` cannot be applied to type
println!("{}", j);
//~^ ERROR not implemented
}

View File

@ -58,7 +58,13 @@ impl Mul<f64, i32> for Vec3 {
}
pub fn main() {
Vec1 { x: 1.0 } * 2.0;
Vec2 { x: 1.0, y: 2.0 } * 2.0;
Vec3 { x: 1.0, y: 2.0, z: 3.0 } * 2.0;
// Check that the usage goes from the trait declaration:
let x: Vec1 = Vec1 { x: 1.0 } * 2.0; // this is OK
let x: Vec2 = Vec2 { x: 1.0, y: 2.0 } * 2.0; // trait had reversed order
//~^ ERROR mismatched types
//~^^ ERROR mismatched types
let x: i32 = Vec3 { x: 1.0, y: 2.0, z: 3.0 } * 2.0;
}

View File

@ -8,20 +8,36 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that we pick which version of `foo` to run based on the
// type that is (ultimately) inferred for `x`.
trait foo {
fn foo(&self) -> int;
}
impl foo for Vec<uint> {
fn foo(&self) -> int {1} //~ NOTE candidate #1 is `Vec<uint>.foo::foo`
fn foo(&self) -> int {1}
}
impl foo for Vec<int> {
fn foo(&self) -> int {2} //~ NOTE candidate #2 is `Vec<int>.foo::foo`
fn foo(&self) -> int {2}
}
fn call_foo_uint() -> int {
let mut x = Vec::new();
let y = x.foo();
x.push(0u);
y
}
fn call_foo_int() -> int {
let mut x = Vec::new();
let y = x.foo();
x.push(0i);
y
}
fn main() {
let x = Vec::new();
x.foo(); //~ ERROR multiple applicable methods in scope
assert_eq!(call_foo_uint(), 1);
assert_eq!(call_foo_int(), 2);
}

View File

@ -0,0 +1,48 @@
// Copyright 2012 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 pick which version of `Foo` to run based on whether
// the type we (ultimately) inferred for `x` is copyable or not.
//
// In this case, the two versions are both impls of same trait, and
// hence we we can resolve method even without knowing yet which
// version will run (note that the `push` occurs after the call to
// `foo()`).
trait Foo {
fn foo(&self) -> int;
}
impl<T:Copy> Foo for Vec<T> {
fn foo(&self) -> int {1}
}
impl<T> Foo for Vec<Box<T>> {
fn foo(&self) -> int {2}
}
fn call_foo_copy() -> int {
let mut x = Vec::new();
let y = x.foo();
x.push(0u);
y
}
fn call_foo_other() -> int {
let mut x = Vec::new();
let y = x.foo();
x.push(box 0i);
y
}
fn main() {
assert_eq!(call_foo_copy(), 1);
assert_eq!(call_foo_other(), 2);
}