diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 42ea138acd4dc..3dceb42e20653 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -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) } } } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 6de5f31c6d198..f6e3e7f61cf93 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -638,7 +638,7 @@ shr_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64) * ``` */ #[lang="index"] -pub trait Index { +pub trait Index { /// The method for the indexing (`Foo[Bar]`) operation fn index<'a>(&'a self, index: &Index) -> &'a Result; } diff --git a/src/librustc/middle/borrowck/graphviz.rs b/src/librustc/middle/borrowck/graphviz.rs index aab7fe8f31edc..6c6750ad24b2e 100644 --- a/src/librustc/middle/borrowck/graphviz.rs +++ b/src/librustc/middle/borrowck/graphviz.rs @@ -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) } } diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs index bc48e476aec07..fcd9a166c6ab1 100644 --- a/src/librustc/middle/cfg/graphviz.rs +++ b/src/librustc/middle/cfg/graphviz.rs @@ -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) } } diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs index 742c4cb5de031..f24121d9a3a5f 100644 --- a/src/librustc/middle/traits/doc.rs +++ b/src/librustc/middle/traits/doc.rs @@ -272,4 +272,11 @@ nested obligation `int : Bar` 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. + */ diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index f0282804540f5..76715561b0397 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -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, } -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>, diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index aca7054018dc6..f923cf1e5903b 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -62,6 +62,23 @@ pub struct SelectionCache { hashmap: RefCell, SelectionResult>>, } +pub enum MethodMatchResult { + MethodMatched(MethodMatchedData), + MethodAmbiguous(/* list of impls that could apply */ Vec), + 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 Eq for Vec` (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, ...) { ... } + // } + // + // And then we have a call looking (say) like this: + // + // let x: Rc = ...; + // 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`? We need to take the method's self type into + // account. + // + // On entry to this function, we have the following inputs: + // + // - `rcvr_ty = Rc` + // - `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, ...) { ... } + // } + // ``` + // + // Now we see that the receiver type `Rc` is actually an + // object type. And in fact the impl we want is an impl on the + // supertrait `Rc`. The precise matching procedure won't + // find it, however, because `Rc` is not a subtype of + // `Rc` -- it is *coercible* to `Rc` (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` + // - `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`) is *coercible to* the transformed self + // type (`Rc<$0> == Rc`). 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` would be coercible to both `Rc` + // and `Rc`. (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 + { + /*! + * 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 + { + /*! + * 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` (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) -> 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, + } + } +} diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index dbaebd07b0220..a7ce93279bd83 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -120,6 +120,13 @@ impl ImplOrTraitItem { TypeTraitItem(ref associated_type) => associated_type.container, } } + + pub fn as_opt_method(&self) -> Option> { + 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 diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 798e4acd2910e..4560c51946494 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -81,30 +81,31 @@ obtained the type `Foo`, we would never match this method. use middle::subst; -use middle::subst::Subst; +use middle::subst::{Subst, SelfSpace}; use middle::traits; use middle::ty::*; use middle::ty; use middle::typeck::astconv::AstConv; use middle::typeck::check::{FnCtxt, NoPreference, PreferMutLvalue}; use middle::typeck::check::{impl_self_ty}; +use middle::typeck::check::vtable2::select_fcx_obligations_where_possible; use middle::typeck::check; use middle::typeck::infer; use middle::typeck::{MethodCall, MethodCallee}; use middle::typeck::{MethodOrigin, MethodParam, MethodTypeParam}; use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject}; -use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; +use middle::typeck::check::regionmanip::replace_late_bound_regions; use middle::typeck::TypeAndSubsts; +use middle::ty_fold::TypeFoldable; use util::common::indenter; use util::ppaux; -use util::ppaux::Repr; +use util::ppaux::{Repr, UserString}; use std::collections::HashSet; use std::rc::Rc; use syntax::ast::{DefId, MutImmutable, MutMutable}; use syntax::ast; use syntax::codemap::Span; -use syntax::parse::token; #[deriving(PartialEq)] pub enum CheckTraitsFlag { @@ -118,26 +119,31 @@ pub enum AutoderefReceiverFlag { DontAutoderefReceiver, } -#[deriving(PartialEq)] -pub enum StaticMethodsFlag { - ReportStaticMethods, - IgnoreStaticMethods, +pub enum MethodError { + // Did not find an applicable method, but we did find various + // static methods that may apply. + NoMatch(Vec), + + // Multiple methods might apply. + Ambiguity(Vec), } +pub type MethodResult = Result; + pub fn lookup<'a, 'tcx>( - fcx: &'a FnCtxt<'a, 'tcx>, - - // In a call `a.b::(...)`: - expr: &ast::Expr, // The expression `a.b(...)`. - self_expr: &'a ast::Expr, // The expression `a`. - m_name: ast::Name, // The name `b`. - self_ty: ty::t, // The type of `a`. - supplied_tps: &'a [ty::t], // The list of types X, Y, ... . - deref_args: check::DerefArgs, // Whether we autopointer first. - check_traits: CheckTraitsFlag, // Whether we check traits only. - autoderef_receiver: AutoderefReceiverFlag, - report_statics: StaticMethodsFlag) - -> Option { + fcx: &'a FnCtxt<'a, 'tcx>, + + // In a call `a.b::(...)`: + expr: &ast::Expr, // The expression `a.b(...)`. + self_expr: &'a ast::Expr, // The expression `a`. + m_name: ast::Name, // The name `b`. + self_ty: ty::t, // The type of `a`. + supplied_tps: &'a [ty::t], // The list of types X, Y, ... . + deref_args: check::DerefArgs, // Whether we autopointer first. + check_traits: CheckTraitsFlag, // Whether we check traits only. + autoderef_receiver: AutoderefReceiverFlag) + -> MethodResult +{ let mut lcx = LookupContext { fcx: fcx, span: expr.span, @@ -147,10 +153,10 @@ pub fn lookup<'a, 'tcx>( impl_dups: HashSet::new(), inherent_candidates: Vec::new(), extension_candidates: Vec::new(), + static_candidates: Vec::new(), deref_args: deref_args, check_traits: check_traits, autoderef_receiver: autoderef_receiver, - report_statics: report_statics, }; debug!("method lookup(self_ty={}, expr={}, self_expr={})", @@ -166,18 +172,17 @@ pub fn lookup<'a, 'tcx>( } pub fn lookup_in_trait<'a, 'tcx>( - fcx: &'a FnCtxt<'a, 'tcx>, - - // In a call `a.b::(...)`: - span: Span, // The expression `a.b(...)`'s span. - self_expr: Option<&'a ast::Expr>, // The expression `a`, if available. - m_name: ast::Name, // The name `b`. - trait_did: DefId, // The trait to limit the lookup to. - self_ty: ty::t, // The type of `a`. - supplied_tps: &'a [ty::t], // The list of types X, Y, ... . - autoderef_receiver: AutoderefReceiverFlag, - report_statics: StaticMethodsFlag) - -> Option { + fcx: &'a FnCtxt<'a, 'tcx>, + + // In a call `a.b::(...)`: + span: Span, // The expression `a.b(...)`'s span. + self_expr: Option<&'a ast::Expr>, // The expression `a`, if available. + m_name: ast::Name, // The name `b`. + trait_did: DefId, // The trait to limit the lookup to. + self_ty: ty::t, // The type of `a`. + supplied_tps: &'a [ty::t]) // The list of types X, Y, ... . + -> Option +{ let mut lcx = LookupContext { fcx: fcx, span: span, @@ -187,18 +192,107 @@ pub fn lookup_in_trait<'a, 'tcx>( impl_dups: HashSet::new(), inherent_candidates: Vec::new(), extension_candidates: Vec::new(), + static_candidates: Vec::new(), deref_args: check::DoDerefArgs, check_traits: CheckTraitsOnly, - autoderef_receiver: autoderef_receiver, - report_statics: report_statics, + autoderef_receiver: DontAutoderefReceiver, }; - debug!("method lookup_in_trait(self_ty={}, self_expr={})", - self_ty.repr(fcx.tcx()), self_expr.map(|e| e.repr(fcx.tcx()))); + debug!("method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_did={})", + self_ty.repr(fcx.tcx()), + self_expr.repr(fcx.tcx()), + m_name.repr(fcx.tcx()), + trait_did.repr(fcx.tcx())); lcx.push_bound_candidates(self_ty, Some(trait_did)); lcx.push_extension_candidate(trait_did); - lcx.search(self_ty) + + // when doing a trait search, ambiguity can't really happen except + // as part of the trait-lookup in general + match lcx.search(self_ty) { + Ok(callee) => Some(callee), + Err(_) => None + } +} + +pub fn report_error(fcx: &FnCtxt, + span: Span, + rcvr_ty: ty::t, + method_name: ast::Name, + error: MethodError) +{ + match error { + NoMatch(static_sources) => { + fcx.type_error_message( + span, + |actual| { + format!("type `{}` does not implement any \ + method in scope named `{}`", + actual, + method_name.user_string(fcx.tcx())) + }, + rcvr_ty, + None); + + if static_sources.len() > 0 { + fcx.tcx().sess.fileline_note( + span, + "found defined static methods, maybe a `self` is missing?"); + + report_candidates(fcx, span, method_name, static_sources); + } + } + + Ambiguity(sources) => { + span_err!(fcx.sess(), span, E0034, + "multiple applicable methods in scope"); + + report_candidates(fcx, span, method_name, sources); + } + } + + fn report_candidates(fcx: &FnCtxt, + span: Span, + method_name: ast::Name, + mut sources: Vec) { + sources.sort(); + sources.dedup(); + + for (idx, source) in sources.iter().enumerate() { + match *source { + ImplSource(impl_did) => { + // Provide the best span we can. Use the method, if local to crate, else + // the impl, if local to crate (method may be defaulted), else the call site. + let method = impl_method(fcx.tcx(), impl_did, method_name).unwrap(); + let impl_span = fcx.tcx().map.def_id_span(impl_did, span); + let method_span = fcx.tcx().map.def_id_span(method.def_id, impl_span); + + let impl_ty = impl_self_ty(fcx, span, impl_did).ty; + + let insertion = match impl_trait_ref(fcx.tcx(), impl_did) { + None => format!(""), + Some(trait_ref) => format!(" of the trait `{}`", + ty::item_path_str(fcx.tcx(), + trait_ref.def_id)), + }; + + span_note!(fcx.sess(), method_span, + "candidate #{} is defined in an impl{} for the type `{}`", + idx + 1u, + insertion, + impl_ty.user_string(fcx.tcx())); + } + TraitSource(trait_did) => { + let (_, method) = trait_method(fcx.tcx(), trait_did, method_name).unwrap(); + let method_span = fcx.tcx().map.def_id_span(method.def_id, span); + span_note!(fcx.sess(), method_span, + "candidate #{} is defined in the trait `{}`", + idx + 1u, + ty::item_path_str(fcx.tcx(), trait_did)); + } + } + } + } } // Determine the index of a method in the list of all methods belonging @@ -230,75 +324,6 @@ fn get_method_index(tcx: &ty::ctxt, method_count + n_method } -fn construct_transformed_self_ty_for_object( - tcx: &ty::ctxt, - span: Span, - trait_def_id: ast::DefId, - rcvr_substs: &subst::Substs, - rcvr_bounds: ty::ExistentialBounds, - method_ty: &ty::Method) - -> ty::t -{ - /*! - * This is a bit tricky. We have a match against a trait method - * being invoked on an object, and we want to generate the - * self-type. As an example, consider a trait - * - * trait Foo { - * fn r_method<'a>(&'a self); - * fn u_method(Box); - * } - * - * Now, assuming that `r_method` is being called, we want the - * result to be `&'a Foo`. Assuming that `u_method` is being - * called, we want the result to be `Box`. Of course, - * this transformation has already been done as part of - * `method_ty.fty.sig.inputs[0]`, but there the type - * is expressed in terms of `Self` (i.e., `&'a Self`, `Box`). - * Because objects are not standalone types, we can't just substitute - * `s/Self/Foo/`, so we must instead perform this kind of hokey - * match below. - */ - - let mut obj_substs = rcvr_substs.clone(); - - // The subst we get in has Err as the "Self" type. For an object - // type, we don't put any type into the Self paramspace, so let's - // make a copy of rcvr_substs that has the Self paramspace empty. - obj_substs.types.pop(subst::SelfSpace).unwrap(); - - match method_ty.explicit_self { - StaticExplicitSelfCategory => { - tcx.sess.span_bug(span, "static method for object type receiver"); - } - ByValueExplicitSelfCategory => { - let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, rcvr_bounds); - ty::mk_uniq(tcx, tr) - } - ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => { - let transformed_self_ty = method_ty.fty.sig.inputs[0]; - match ty::get(transformed_self_ty).sty { - ty::ty_rptr(r, mt) => { // must be SelfRegion - let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime - let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, - rcvr_bounds); - ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl }) - } - ty::ty_uniq(_) => { // must be SelfUniq - let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, - rcvr_bounds); - ty::mk_uniq(tcx, tr) - } - _ => { - tcx.sess.span_bug(span, - format!("'impossible' transformed_self_ty: {}", - transformed_self_ty.repr(tcx)).as_slice()); - } - } - } - } -} - struct LookupContext<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, span: Span, @@ -313,42 +338,45 @@ struct LookupContext<'a, 'tcx: 'a> { supplied_tps: &'a [ty::t], impl_dups: HashSet, inherent_candidates: Vec, - extension_candidates: Vec, + extension_candidates: Vec, + static_candidates: Vec, deref_args: check::DerefArgs, check_traits: CheckTraitsFlag, autoderef_receiver: AutoderefReceiverFlag, - report_statics: StaticMethodsFlag, } -/** - * A potential method that might be called, assuming the receiver - * is of a suitable type. - */ +// A method that the user may be trying to invoke. Initially, we +// construct candidates only for inherent methods; for extension +// traits, we use an ExtensionCandidate. #[deriving(Clone)] struct Candidate { - rcvr_match_condition: RcvrMatchCondition, + xform_self_ty: ty::t, rcvr_substs: subst::Substs, method_ty: Rc, origin: MethodOrigin, } -/// This type represents the conditions under which the receiver is -/// considered to "match" a given method candidate. Typically the test -/// is whether the receiver is of a particular type. However, this -/// type is the type of the receiver *after accounting for the -/// method's self type* (e.g., if the method is an `Box` method, we -/// have *already verified* that the receiver is of some type `Box` and -/// now we must check that the type `T` is correct). Unfortunately, -/// because traits are not types, this is a pain to do. -#[deriving(Clone)] -pub enum RcvrMatchCondition { - RcvrMatchesIfObject(ast::DefId), - RcvrMatchesIfSubtype(ty::t), - RcvrMatchesIfEqtype(ty::t) +// A variation on a candidate that just stores the data needed +// extension trait matching. Once we pick the trait that matches, +// we'll construct a normal candidate from that. There is no deep +// reason for this, the code just worked out a bit cleaner. +struct ExtensionCandidate { + obligation: traits::Obligation, + xform_self_ty: ty::t, + method_ty: Rc, + method_num: uint, +} + +// A pared down enum describing just the places from which a method +// candidate can arise. Used for error reporting only. +#[deriving(PartialOrd, Ord, PartialEq, Eq)] +pub enum CandidateSource { + ImplSource(ast::DefId), + TraitSource(/* trait id */ ast::DefId), } impl<'a, 'tcx> LookupContext<'a, 'tcx> { - fn search(&self, self_ty: ty::t) -> Option { + fn search(self, self_ty: ty::t) -> MethodResult { let span = self.self_expr.map_or(self.span, |e| e.span); let self_expr_id = self.self_expr.map(|e| e.id); @@ -358,18 +386,33 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { |self_ty, autoderefs| self.search_step(self_ty, autoderefs)); match result { - Some(Some(result)) => { + Some(Some(Ok(result))) => { self.fixup_derefs_on_method_receiver_if_necessary(&result); - Some(result) + Ok(result) + } + Some(Some(Err(err))) => { + Err(err) + } + None | Some(None) => { + Err(NoMatch(self.static_candidates)) } - _ => None } } fn search_step(&self, self_ty: ty::t, autoderefs: uint) - -> Option> { + -> Option> + { + // Oh my, what a return type! + // + // Returning: + // - `None` => autoderef more, keep searching + // - `Some(None)` => stop searching, found nothing + // - `Some(Some(_))` => stop searching, found either callee/error + // - `Some(Some(Ok(_)))` => found a callee + // - `Some(Some(Err(_)))` => found an error (ambiguity, etc) + debug!("search_step: self_ty={} autoderefs={}", self.ty_to_string(self_ty), autoderefs); @@ -420,7 +463,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.self_expr.is_none() } - // ______________________________________________________________________ + /////////////////////////////////////////////////////////////////////////// // Candidate collection (see comment at start of file) fn push_inherent_candidates(&mut self, self_ty: ty::t) { @@ -437,8 +480,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { check::autoderef(self.fcx, span, self_ty, None, NoPreference, |self_ty, _| { match get(self_ty).sty { ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => { - self.push_inherent_candidates_from_object( - def_id, substs, bounds); + self.push_inherent_candidates_from_object(self_ty, def_id, substs, bounds); self.push_inherent_impl_candidates_for_type(def_id); } ty_enum(did, _) | @@ -467,10 +509,6 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { ty_param(p) => { self.push_inherent_candidates_from_param(self_ty, restrict_to, p); } - ty_unboxed_closure(closure_did, _) => { - self.push_unboxed_closure_call_candidates_if_applicable( - closure_did); - } _ => { /* No bound methods in these types */ } } @@ -483,131 +521,92 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { }); } - fn push_extension_candidate(&mut self, trait_did: DefId) { - ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_did); - - // Look for explicit implementations. - let impl_items = self.tcx().impl_items.borrow(); - for impl_infos in self.tcx().trait_impls.borrow().find(&trait_did).iter() { - for impl_did in impl_infos.borrow().iter() { - let items = &(*impl_items)[*impl_did]; - self.push_candidates_from_impl(*impl_did, - items.as_slice(), - true); - } - } - } - fn push_extension_candidates(&mut self, expr_id: ast::NodeId) { - // If the method being called is associated with a trait, then - // find all the impls of that trait. Each of those are - // candidates. + debug!("push_extension_candidates(expr_id={})", expr_id); + + let mut duplicates = HashSet::new(); let opt_applicable_traits = self.fcx.ccx.trait_map.find(&expr_id); for applicable_traits in opt_applicable_traits.into_iter() { - for trait_did in applicable_traits.iter() { - debug!("push_extension_candidates() found trait: {}", - if trait_did.krate == ast::LOCAL_CRATE { - self.fcx.ccx.tcx.map.node_to_string(trait_did.node) - } else { - "(external)".to_string() - }); - self.push_extension_candidate(*trait_did); + for &trait_did in applicable_traits.iter() { + if duplicates.insert(trait_did) { + self.push_extension_candidate(trait_did); + } } } } - fn push_unboxed_closure_call_candidate_if_applicable( - &mut self, - trait_did: DefId, - closure_did: DefId, - closure_function_type: &ClosureTy) { - let trait_item = (*ty::trait_items(self.tcx(), trait_did))[0] - .clone(); - let method = match trait_item { - ty::MethodTraitItem(method) => method, - ty::TypeTraitItem(_) => { - self.tcx().sess.bug( - "push_unboxed_closure_call_candidates_if_applicable(): \ - unexpected associated type in function trait") - } + fn push_extension_candidate(&mut self, trait_def_id: DefId) { + debug!("push_extension_candidates: trait_def_id={}", trait_def_id); + + // Check whether `trait_def_id` defines a method with suitable name: + let trait_items = + ty::trait_items(self.tcx(), trait_def_id); + let matching_index = + trait_items.iter() + .position(|item| item.ident().name == self.m_name); + let matching_index = match matching_index { + Some(i) => i, + None => { return; } + }; + let method = match (&*trait_items)[matching_index].as_opt_method() { + Some(m) => m, + None => { return; } }; - // Make sure it has the right name! - if method.ident.name != self.m_name { - return + // Check whether `trait_def_id` defines a method with suitable name: + if !self.has_applicable_self(&*method) { + debug!("method has inapplicable self"); + return self.record_static_candidate(TraitSource(trait_def_id)); } - // Get the tupled type of the arguments. - let arguments_type = closure_function_type.sig.inputs[0]; - let return_type = closure_function_type.sig.output; - - let closure_region = - self.fcx.infcx().next_region_var(infer::MiscVariable(self.span)); - let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(), - closure_did, - closure_region); - self.extension_candidates.push(Candidate { - rcvr_match_condition: - RcvrMatchesIfSubtype(unboxed_closure_type), - rcvr_substs: subst::Substs::new_trait( - vec![arguments_type, return_type], - vec![], - self.fcx.infcx().next_ty_vars(1)[0]), + // Otherwise, construct the receiver type. + let self_ty = + self.fcx.infcx().next_ty_var(); + let trait_def = + ty::lookup_trait_def(self.tcx(), trait_def_id); + let substs = + self.fcx.infcx().fresh_substs_for_trait(self.span, + &trait_def.generics, + self_ty); + let xform_self_ty = + self.xform_self_ty(&method, &substs); + + // Construct the obligation which must match. + let trait_ref = + Rc::new(ty::TraitRef::new(trait_def_id, substs)); + let obligation = + traits::Obligation::misc(self.span, trait_ref); + + debug!("extension-candidate(xform_self_ty={} obligation={})", + self.infcx().ty_to_string(xform_self_ty), + obligation.repr(self.tcx())); + + self.extension_candidates.push(ExtensionCandidate { + obligation: obligation, + xform_self_ty: xform_self_ty, method_ty: method, - origin: MethodStaticUnboxedClosure(closure_did), + method_num: matching_index, }); } - fn push_unboxed_closure_call_candidates_if_applicable( - &mut self, - closure_did: DefId) { - match self.tcx().unboxed_closures.borrow().find(&closure_did) { - None => {} // Fall through to try inherited. - Some(closure) => { - let tcx = self.tcx(); - self.push_unboxed_closure_call_candidate_if_applicable( - closure.kind.trait_did(tcx), - closure_did, - &closure.closure_type); - return - } - } - - match self.fcx.inh.unboxed_closures.borrow().find(&closure_did) { - Some(closure) => { - let tcx = self.tcx(); - self.push_unboxed_closure_call_candidate_if_applicable( - closure.kind.trait_did(tcx), - closure_did, - &closure.closure_type); - return - } - None => {} - } - - self.tcx().sess.bug("didn't find unboxed closure type in tcx map or \ - inherited map, so there") - } - fn push_inherent_candidates_from_object(&mut self, + self_ty: ty::t, did: DefId, substs: &subst::Substs, - bounds: ty::ExistentialBounds) { - debug!("push_inherent_candidates_from_object(did={}, substs={})", - self.did_to_string(did), - substs.repr(self.tcx())); + _bounds: ty::ExistentialBounds) { + debug!("push_inherent_candidates_from_object(self_ty={})", + self_ty.repr(self.tcx())); + let tcx = self.tcx(); - let span = self.span; // It is illegal to invoke a method on a trait instance that - // refers to the `self` type. An error will be reported by - // `enforce_object_limitations()` if the method refers - // to the `Self` type. Substituting ty_err here allows - // compiler to soldier on. - // - // `confirm_candidate()` also relies upon this substitution - // for Self. (fix) - let rcvr_substs = substs.with_self_ty(ty::mk_err()); + // refers to the `Self` type. An error will be reported by + // `enforce_object_limitations()` if the method refers to the + // `Self` type anywhere other than the receiver. Here, we use + // a substitution that replaces `Self` with the object type + // itself. Hence, a `&self` method will wind up with an + // argument type like `&Trait`. + let rcvr_substs = substs.with_self_ty(self_ty); let trait_ref = Rc::new(TraitRef { def_id: did, substs: rcvr_substs.clone() @@ -615,20 +614,35 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.push_inherent_candidates_from_bounds_inner( &[trait_ref.clone()], - |_this, new_trait_ref, m, method_num| { + |this, new_trait_ref, m, method_num| { let vtable_index = get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num); - let mut m = (*m).clone(); - // We need to fix up the transformed self type. - *m.fty.sig.inputs.get_mut(0) = - construct_transformed_self_ty_for_object( - tcx, span, did, &rcvr_substs, bounds, &m); + + // FIXME Hacky. By-value `self` methods in objects ought to be + // just a special case of passing ownership of a DST value + // as a parameter. *But* we currently hack them in and tie them to + // the particulars of the `Box` type. So basically for a `fn foo(self,...)` + // method invoked on an object, we don't want the receiver type to be + // `TheTrait`, but rather `Box`. Yuck. + let mut m = m; + match m.explicit_self { + ByValueExplicitSelfCategory => { + let mut n = (*m).clone(); + let self_ty = n.fty.sig.inputs[0]; + *n.fty.sig.inputs.get_mut(0) = ty::mk_uniq(tcx, self_ty); + m = Rc::new(n); + } + _ => { } + } + + let xform_self_ty = + this.xform_self_ty(&m, &new_trait_ref.substs); Some(Candidate { - rcvr_match_condition: RcvrMatchesIfObject(did), + xform_self_ty: xform_self_ty, rcvr_substs: new_trait_ref.substs.clone(), - method_ty: Rc::new(m), + method_ty: m, origin: MethodTraitObject(MethodObject { trait_ref: new_trait_ref, object_trait_id: did, @@ -652,9 +666,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { restrict_to); } - fn push_inherent_candidates_from_bounds(&mut self, - self_ty: ty::t, + _self_ty: ty::t, space: subst::ParamSpace, index: uint, restrict_to: Option) { @@ -672,12 +685,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { _ => {} } - let condition = match m.explicit_self { - ByReferenceExplicitSelfCategory(_, mt) if mt == MutMutable => - RcvrMatchesIfEqtype(self_ty), - _ => - RcvrMatchesIfSubtype(self_ty) - }; + let xform_self_ty = + this.xform_self_ty(&m, &trait_ref.substs); debug!("found match: trait_ref={} substs={} m={}", trait_ref.repr(this.tcx()), @@ -691,8 +700,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { trait_ref.substs.types.get_slice(subst::SelfSpace).len()); assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(), trait_ref.substs.regions().get_slice(subst::SelfSpace).len()); + Some(Candidate { - rcvr_match_condition: condition, + xform_self_ty: xform_self_ty, rcvr_substs: trait_ref.substs.clone(), method_ty: m, origin: MethodTypeParam(MethodParam { @@ -700,7 +710,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { method_num: method_num, }) }) - }) + }) } // Do a search through a list of bounds, using a callback to actually @@ -722,41 +732,24 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { continue; } - let trait_items = ty::trait_items(tcx, bound_trait_ref.def_id); - match trait_items.iter().position(|ti| { - match *ti { - ty::MethodTraitItem(ref m) => { - m.explicit_self != ty::StaticExplicitSelfCategory && - m.ident.name == self.m_name - } - ty::TypeTraitItem(_) => false, - } - }) { - Some(pos) => { - let method = match (*trait_items)[pos] { - ty::MethodTraitItem(ref method) => (*method).clone(), - ty::TypeTraitItem(_) => { - tcx.sess.bug("typechecking associated type as \ - though it were a method") - } - }; + let (pos, method) = match trait_method(tcx, bound_trait_ref.def_id, self.m_name) { + Some(v) => v, + None => { continue; } + }; - match mk_cand(self, - bound_trait_ref, - method, - pos) { - Some(cand) => { - debug!("pushing inherent candidate for param: {}", - cand.repr(self.tcx())); - self.inherent_candidates.push(cand); - } - None => {} + if !self.has_applicable_self(&*method) { + self.record_static_candidate(TraitSource(bound_trait_ref.def_id)); + } else { + match mk_cand(self, + bound_trait_ref, + method, + pos) { + Some(cand) => { + debug!("pushing inherent candidate for param: {}", + cand.repr(self.tcx())); + self.inherent_candidates.push(cand); } - } - None => { - debug!("trait doesn't contain method: {}", - bound_trait_ref.def_id); - // check next trait or bound + None => {} } } } @@ -768,83 +761,47 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { // metadata if necessary. ty::populate_implementations_for_type_if_necessary(self.tcx(), did); - let impl_items = self.tcx().impl_items.borrow(); for impl_infos in self.tcx().inherent_impls.borrow().find(&did).iter() { for impl_did in impl_infos.iter() { - let items = &(*impl_items)[*impl_did]; - self.push_candidates_from_impl(*impl_did, - items.as_slice(), - false); + self.push_candidates_from_inherent_impl(*impl_did); } } } - fn push_candidates_from_impl(&mut self, - impl_did: DefId, - impl_items: &[ImplOrTraitItemId], - is_extension: bool) { - let did = if self.report_statics == ReportStaticMethods { - // we only want to report each base trait once - match ty::impl_trait_ref(self.tcx(), impl_did) { - Some(trait_ref) => trait_ref.def_id, - None => impl_did - } - } else { - impl_did - }; - - if !self.impl_dups.insert(did) { + fn push_candidates_from_inherent_impl(&mut self, + impl_did: DefId) { + if !self.impl_dups.insert(impl_did) { return; // already visited } - debug!("push_candidates_from_impl: {} {}", - token::get_name(self.m_name), - impl_items.iter() - .map(|&did| { - ty::impl_or_trait_item(self.tcx(), - did.def_id()).ident() - }) - .collect::>() - .repr(self.tcx())); - - let method = match impl_items.iter() - .map(|&did| { - ty::impl_or_trait_item(self.tcx(), - did.def_id()) - }) - .find(|m| { - m.ident().name == self.m_name - }) { - Some(ty::MethodTraitItem(method)) => method, - Some(ty::TypeTraitItem(_)) | None => { - // No method with the right name. - return - } + let method = match impl_method(self.tcx(), impl_did, self.m_name) { + Some(m) => m, + None => { return; } // No method with correct name on this impl }; - // determine the `self` of the impl with fresh - // variables for each parameter: + debug!("push_candidates_from_inherent_impl: impl_did={} method={}", + impl_did.repr(self.tcx()), + method.repr(self.tcx())); + + if !self.has_applicable_self(&*method) { + // No receiver declared. Not a candidate. + return self.record_static_candidate(ImplSource(impl_did)); + } + + // Determine the `self` of the impl with fresh + // variables for each parameter. let span = self.self_expr.map_or(self.span, |e| e.span); let TypeAndSubsts { substs: impl_substs, - ty: impl_ty + ty: _impl_ty } = impl_self_ty(self.fcx, span, impl_did); - let condition = match method.explicit_self { - ByReferenceExplicitSelfCategory(_, mt) if mt == MutMutable => - RcvrMatchesIfEqtype(impl_ty), - _ => - RcvrMatchesIfSubtype(impl_ty) - }; - - let candidates = if is_extension { - &mut self.extension_candidates - } else { - &mut self.inherent_candidates - }; + // Determine the receiver type that the method itself expects. + let xform_self_ty = + self.xform_self_ty(&method, &impl_substs); - candidates.push(Candidate { - rcvr_match_condition: condition, + self.inherent_candidates.push(Candidate { + xform_self_ty: xform_self_ty, rcvr_substs: impl_substs, origin: MethodStatic(method.def_id), method_ty: method, @@ -857,7 +814,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { fn search_for_autoderefd_method(&self, self_ty: ty::t, autoderefs: uint) - -> Option { + -> Option { // Hacky. For overloaded derefs, there may be an adjustment // added to the expression from the outside context, so we do not store // an explicit adjustment, but rather we hardwire the single deref @@ -870,8 +827,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { let adjustment = Some((self.self_expr.unwrap().id, ty::AdjustDerefRef(auto_deref_ref))); match self.search_for_method(self_ty) { - None => None, - Some(method) => { + None => { + None + } + Some(Ok(method)) => { debug!("(searching for autoderef'd method) writing \ adjustment {} for {}", adjustment, self.ty_to_string(self_ty)); match adjustment { @@ -880,7 +839,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } None => {} } - Some(method) + Some(Ok(method)) + } + Some(Err(error)) => { + Some(Err(error)) } } } @@ -944,7 +906,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { // Takes an [T] - an unwrapped DST pointer (either ~ or &) // [T] to &[T] or &&[T] (note that we started with a &[T] or ~[T] which has // been implicitly derefed). - fn auto_slice_vec(&self, ty: ty::t, autoderefs: uint) -> Option { + fn auto_slice_vec(&self, ty: ty::t, autoderefs: uint) + -> Option + { let tcx = self.tcx(); debug!("auto_slice_vec {}", ppaux::ty_to_string(tcx, ty)); @@ -975,7 +939,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } // [T, ..len] -> [T] or &[T] or &&[T] - fn auto_unsize_vec(&self, ty: ty::t, autoderefs: uint, len: uint) -> Option { + fn auto_unsize_vec(&self, ty: ty::t, autoderefs: uint, len: uint) -> Option { let tcx = self.tcx(); debug!("auto_unsize_vec {}", ppaux::ty_to_string(tcx, ty)); @@ -1011,7 +975,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { }) } - fn auto_slice_str(&self, autoderefs: uint) -> Option { + fn auto_slice_str(&self, autoderefs: uint) -> Option { let tcx = self.tcx(); debug!("auto_slice_str"); @@ -1033,7 +997,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } // Coerce Box/&Trait instances to &Trait. - fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option { + fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option { debug!("auto_slice_trait"); match ty::get(ty).sty { ty_trait(box ty::TyTrait { @@ -1057,7 +1021,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { fn search_for_autofatptrd_method(&self, self_ty: ty::t, autoderefs: uint) - -> Option { + -> Option + { /*! * Searches for a candidate by converting things like * `~[]` to `&[]`. @@ -1084,7 +1049,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } fn search_for_autoptrd_method(&self, self_ty: ty::t, autoderefs: uint) - -> Option { + -> Option + { /*! * * Converts any type `T` to `&M T` where `M` is an @@ -1118,12 +1084,13 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } fn search_for_some_kind_of_autorefd_method( - &self, - kind: |Region, ast::Mutability| -> ty::AutoRef, - autoderefs: uint, - mutbls: &[ast::Mutability], - mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t) - -> Option { + &self, + kind: |Region, ast::Mutability| -> ty::AutoRef, + autoderefs: uint, + mutbls: &[ast::Mutability], + mk_autoref_ty: |ast::Mutability, ty::Region| -> ty::t) + -> Option + { // Hacky. For overloaded derefs, there may be an adjustment // added to the expression from the outside context, so we do not store // an explicit adjustment, but rather we hardwire the single deref @@ -1166,7 +1133,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { None } - fn search_for_method(&self, rcvr_ty: ty::t) -> Option { + fn search_for_method(&self, rcvr_ty: ty::t) -> Option { debug!("search_for_method(rcvr_ty={})", self.ty_to_string(rcvr_ty)); let _indenter = indenter(); @@ -1183,49 +1150,26 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } debug!("searching extension candidates"); - self.consider_candidates(rcvr_ty, self.extension_candidates.as_slice()) + self.consider_extension_candidates(rcvr_ty) } fn consider_candidates(&self, rcvr_ty: ty::t, candidates: &[Candidate]) - -> Option { + -> Option { let relevant_candidates = self.filter_candidates(rcvr_ty, candidates); if relevant_candidates.len() == 0 { return None; } - if self.report_statics == ReportStaticMethods { - // lookup should only be called with ReportStaticMethods if a regular lookup failed - assert!(relevant_candidates.iter() - .all(|c| { - c.method_ty.explicit_self == ty::StaticExplicitSelfCategory - })); - - self.tcx().sess.fileline_note(self.span, - "found defined static methods, maybe a `self` is missing?"); - - for (idx, candidate) in relevant_candidates.iter().enumerate() { - self.report_candidate(idx, &candidate.origin); - } - - // return something so we don't get errors for every mutability - return Some(MethodCallee { - origin: relevant_candidates[0].origin.clone(), - ty: ty::mk_err(), - substs: subst::Substs::empty() - }); - } - if relevant_candidates.len() > 1 { - span_err!(self.tcx().sess, self.span, E0034, - "multiple applicable methods in scope"); - for (idx, candidate) in relevant_candidates.iter().enumerate() { - self.report_candidate(idx, &candidate.origin); - } + let sources = relevant_candidates.iter() + .map(|candidate| candidate.to_source()) + .collect(); + return Some(Err(Ambiguity(sources))); } - Some(self.confirm_candidate(rcvr_ty, &relevant_candidates[0])) + Some(Ok(self.confirm_candidate(rcvr_ty, &relevant_candidates[0]))) } fn filter_candidates(&self, rcvr_ty: ty::t, candidates: &[Candidate]) -> Vec { @@ -1252,13 +1196,110 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { _ => false } }) { - relevant_candidates.push(candidate_a.clone()); + relevant_candidates.push((*candidate_a).clone()); } } relevant_candidates } + fn consider_extension_candidates(&self, rcvr_ty: ty::t) + -> Option + { + let mut selcx = traits::SelectionContext::new(self.infcx(), + &self.fcx.inh.param_env, + self.fcx); + + let extension_evaluations: Vec<_> = + self.extension_candidates.iter() + .map(|ext| self.probe_extension_candidate(&mut selcx, rcvr_ty, ext)) + .collect(); + + // How many traits can apply? + let applicable_evaluations_count = + extension_evaluations.iter() + .filter(|eval| eval.may_apply()) + .count(); + + // Determine whether there are multiple traits that could apply. + if applicable_evaluations_count > 1 { + let sources = + self.extension_candidates.iter() + .zip(extension_evaluations.iter()) + .filter(|&(_, eval)| eval.may_apply()) + .map(|(ext, _)| ext.to_source()) + .collect(); + return Some(Err(Ambiguity(sources))); + } + + // Determine whether there are no traits that could apply. + if applicable_evaluations_count == 0 { + return None; + } + + // Exactly one trait applies. It itself could *still* be ambiguous thanks + // to coercions. + let applicable_evaluation = extension_evaluations.iter() + .position(|eval| eval.may_apply()) + .unwrap(); + let match_data = match extension_evaluations[applicable_evaluation] { + traits::MethodMatched(data) => data, + traits::MethodAmbiguous(ref impl_def_ids) => { + let sources = impl_def_ids.iter().map(|&d| ImplSource(d)).collect(); + return Some(Err(Ambiguity(sources))); + } + traits::MethodDidNotMatch => { + self.bug("Method did not match and yet may_apply() is true") + } + }; + + let extension = &self.extension_candidates[applicable_evaluation]; + + debug!("picked extension={}", extension.repr(self.tcx())); + + // We have to confirm the method match. This will cause the type variables + // in the obligation to be appropriately unified based on the subtyping/coercion + // between `rcvr_ty` and `extension.xform_self_ty`. + selcx.confirm_method_match(rcvr_ty, extension.xform_self_ty, + &extension.obligation, match_data); + + // Finally, construct the candidate, now that everything is + // known, and confirm *that*. Note that whatever we pick + // (impl, whatever) we can always use the same kind of origin + // (trait-based method dispatch). + let candidate = Candidate { + xform_self_ty: extension.xform_self_ty, + rcvr_substs: extension.obligation.trait_ref.substs.clone(), + method_ty: extension.method_ty.clone(), + origin: MethodTypeParam(MethodParam{trait_ref: extension.obligation.trait_ref.clone(), + method_num: extension.method_num}) + }; + + // Confirming the candidate will do the final work of + // instantiating late-bound variables, unifying things, and + // registering trait obligations (including + // `extension.obligation`, which should be a requirement of + // the `Self` trait). + let callee = self.confirm_candidate(rcvr_ty, &candidate); + + select_fcx_obligations_where_possible(self.fcx); + + Some(Ok(callee)) + } + + fn probe_extension_candidate(&self, + selcx: &mut traits::SelectionContext, + rcvr_ty: ty::t, + candidate: &ExtensionCandidate) + -> traits::MethodMatchResult + { + debug!("probe_extension_candidate(rcvr_ty={}, candidate.obligation={})", + rcvr_ty.repr(self.tcx()), + candidate.obligation.repr(self.tcx())); + + selcx.evaluate_method_obligation(rcvr_ty, candidate.xform_self_ty, &candidate.obligation) + } + fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate) -> MethodCallee { @@ -1275,12 +1316,17 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.ty_to_string(rcvr_ty), candidate.repr(self.tcx())); - self.enforce_object_limitations(candidate); - self.enforce_drop_trait_limitations(candidate); + let mut rcvr_substs = candidate.rcvr_substs.clone(); - // static methods should never have gotten this far: - assert!(candidate.method_ty.explicit_self != - ty::StaticExplicitSelfCategory); + if !self.enforce_object_limitations(candidate) { + // Here we change `Self` from `Trait` to `err` in the case that + // this is an illegal object method. This is necessary to prevent + // the user from getting strange, derivative errors when the method + // takes an argument/return-type of type `Self` etc. + rcvr_substs.types.get_mut_slice(SelfSpace)[0] = ty::mk_err(); + } + + self.enforce_drop_trait_limitations(candidate); // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh @@ -1312,7 +1358,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.span, candidate.method_ty.generics.regions.get_slice(subst::FnSpace)); - let all_substs = candidate.rcvr_substs.clone().with_method(m_types, m_regions); + let all_substs = rcvr_substs.with_method(m_types, m_regions); let ref bare_fn_ty = candidate.method_ty.fty; @@ -1321,33 +1367,14 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { bare_fn_ty.repr(tcx), all_substs.repr(tcx)); - let fn_sig = &bare_fn_ty.sig; - let inputs = match candidate.origin { - MethodTraitObject(..) => { - // For annoying reasons, we've already handled the - // substitution of self for object calls. - let args = fn_sig.inputs.slice_from(1).iter().map(|t| { - t.subst(tcx, &all_substs) - }); - Some(fn_sig.inputs[0]).into_iter().chain(args).collect() - } - _ => fn_sig.inputs.subst(tcx, &all_substs) - }; - let fn_sig = ty::FnSig { - binder_id: fn_sig.binder_id, - inputs: inputs, - output: fn_sig.output.subst(tcx, &all_substs), - variadic: fn_sig.variadic - }; + let fn_sig = bare_fn_ty.sig.subst(tcx, &all_substs); debug!("after subst, fty={}", fn_sig.repr(tcx)); // Replace any bound regions that appear in the function // signature with region variables - let (_, fn_sig) = replace_late_bound_regions_in_fn_sig( - tcx, &fn_sig, - |br| self.fcx.infcx().next_region_var( - infer::LateBoundRegion(self.span, br))); + let fn_sig = + self.replace_late_bound_regions_with_fresh_var(fn_sig.binder_id, &fn_sig); let transformed_self_ty = fn_sig.inputs[0]; let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { sig: fn_sig, @@ -1373,10 +1400,35 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } } - self.fcx.add_obligations_for_parameters( - traits::ObligationCause::misc(self.span), - &all_substs, - &candidate.method_ty.generics); + // FIXME(DST). Super hack. For a method on a trait object + // `Trait`, the generic signature requires that + // `Self:Trait`. Since, for an object, we bind `Self` to the + // type `Trait`, this leads to an obligation + // `Trait:Trait`. Until such time we DST is fully implemented, + // that obligation is not necessarily satisfied. (In the + // future, it would be.) + // + // To sidestep this, we overwrite the binding for `Self` with + // `err` (just for trait objects) when we generate the + // obligations. This causes us to generate the obligation + // `err:Trait`, and the error type is considered to implement + // all traits, so we're all good. Hack hack hack. + match candidate.origin { + MethodTraitObject(..) => { + let mut temp_substs = all_substs.clone(); + temp_substs.types.get_mut_slice(SelfSpace)[0] = ty::mk_err(); + self.fcx.add_obligations_for_parameters( + traits::ObligationCause::misc(self.span), + &temp_substs, + &candidate.method_ty.generics); + } + _ => { + self.fcx.add_obligations_for_parameters( + traits::ObligationCause::misc(self.span), + &all_substs, + &candidate.method_ty.generics); + } + } MethodCallee { origin: candidate.origin.clone(), @@ -1482,7 +1534,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } } - fn enforce_object_limitations(&self, candidate: &Candidate) { + fn enforce_object_limitations(&self, candidate: &Candidate) -> bool { /*! * There are some limitations to calling functions through an * object, because (a) the self type is not known @@ -1495,7 +1547,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { MethodStatic(..) | MethodTypeParam(..) | MethodStaticUnboxedClosure(..) => { - return; // not a call to a trait instance + return true; // not a call to a trait instance } MethodTraitObject(..) => {} } @@ -1506,6 +1558,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.span, "cannot call a method without a receiver \ through an object"); + return false; } ty::ByValueExplicitSelfCategory | @@ -1514,51 +1567,50 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } // reason (a) above - let check_for_self_ty = |ty| { + let check_for_self_ty = |ty| -> bool { if ty::type_has_self(ty) { span_err!(self.tcx().sess, self.span, E0038, "cannot call a method whose type contains a \ self-type through an object"); - true - } else { false + } else { + true } }; let ref sig = candidate.method_ty.fty.sig; - let mut found_self_ty = false; - for &input_ty in sig.inputs.iter() { - if check_for_self_ty(input_ty) { - found_self_ty = true; - break; + for &input_ty in sig.inputs[1..].iter() { + if !check_for_self_ty(input_ty) { + return false; } } - if !found_self_ty { - check_for_self_ty(sig.output); + if !check_for_self_ty(sig.output) { + return false; } if candidate.method_ty.generics.has_type_params(subst::FnSpace) { // reason (b) above span_err!(self.tcx().sess, self.span, E0039, "cannot call a generic method through an object"); + return false; } + + true } fn enforce_drop_trait_limitations(&self, candidate: &Candidate) { // No code can call the finalize method explicitly. - let bad; - match candidate.origin { + let bad = match candidate.origin { MethodStatic(method_id) => { - bad = self.tcx().destructors.borrow().contains(&method_id); + self.tcx().destructors.borrow().contains(&method_id) + } + MethodStaticUnboxedClosure(_) => { + false } - MethodStaticUnboxedClosure(_) => bad = false, - // FIXME: does this properly enforce this on everything now - // that self has been merged in? -sully MethodTypeParam(MethodParam { trait_ref: ref trait_ref, .. }) | MethodTraitObject(MethodObject { trait_ref: ref trait_ref, .. }) => { - bad = self.tcx().destructor_for_type.borrow() - .contains_key(&trait_ref.def_id); + Some(trait_ref.def_id) == self.tcx().lang_items.drop_trait() } - } + }; if bad { span_err!(self.tcx().sess, self.span, E0040, @@ -1572,213 +1624,141 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { debug!("is_relevant(rcvr_ty={}, candidate={})", self.ty_to_string(rcvr_ty), candidate.repr(self.tcx())); - return match candidate.method_ty.explicit_self { - StaticExplicitSelfCategory => { - debug!("(is relevant?) explicit self is static"); - self.report_statics == ReportStaticMethods - } - - ByValueExplicitSelfCategory => { - debug!("(is relevant?) explicit self is by-value"); - match ty::get(rcvr_ty).sty { - ty::ty_uniq(typ) => { - match ty::get(typ).sty { - ty::ty_trait(box ty::TyTrait { - def_id: self_did, - .. - }) => { - rcvr_matches_object(self_did, candidate) || - rcvr_matches_ty(self.fcx, - rcvr_ty, - candidate) - } - _ => { - rcvr_matches_ty(self.fcx, rcvr_ty, candidate) - } - } - } - _ => rcvr_matches_ty(self.fcx, rcvr_ty, candidate) - } - } - - ByReferenceExplicitSelfCategory(_, m) => { - debug!("(is relevant?) explicit self is a region"); - match ty::get(rcvr_ty).sty { - ty::ty_rptr(_, mt) => { - match ty::get(mt.ty).sty { - ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => { - mutability_matches(mt.mutbl, m) && - rcvr_matches_object(self_did, candidate) - } - _ => mutability_matches(mt.mutbl, m) && - rcvr_matches_ty(self.fcx, mt.ty, candidate) - } - } - - _ => false - } - } - - ByBoxExplicitSelfCategory => { - debug!("(is relevant?) explicit self is a unique pointer"); - match ty::get(rcvr_ty).sty { - ty::ty_uniq(typ) => { - match ty::get(typ).sty { - ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => { - rcvr_matches_object(self_did, candidate) - } - _ => rcvr_matches_ty(self.fcx, typ, candidate), - } - } + infer::can_mk_subty(self.infcx(), rcvr_ty, candidate.xform_self_ty).is_ok() + } - _ => false - } - } - }; + fn infcx(&'a self) -> &'a infer::InferCtxt<'a, 'tcx> { + &self.fcx.inh.infcx + } - fn rcvr_matches_object(self_did: ast::DefId, - candidate: &Candidate) -> bool { - match candidate.rcvr_match_condition { - RcvrMatchesIfObject(desired_did) => { - self_did == desired_did - } - RcvrMatchesIfSubtype(_) | RcvrMatchesIfEqtype(_) => { - false - } - } - } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { + self.fcx.tcx() + } - fn rcvr_matches_ty(fcx: &FnCtxt, - rcvr_ty: ty::t, - candidate: &Candidate) -> bool { - match candidate.rcvr_match_condition { - RcvrMatchesIfObject(_) => { - false - } - RcvrMatchesIfSubtype(of_type) => { - fcx.can_mk_subty(rcvr_ty, of_type).is_ok() - } - RcvrMatchesIfEqtype(of_type) => { - fcx.can_mk_eqty(rcvr_ty, of_type).is_ok() - } - } - } + fn ty_to_string(&self, t: ty::t) -> String { + self.fcx.infcx().ty_to_string(t) + } - fn mutability_matches(self_mutbl: ast::Mutability, - candidate_mutbl: ast::Mutability) - -> bool { - //! True if `self_mutbl <: candidate_mutbl` - self_mutbl == candidate_mutbl - } + fn bug(&self, s: &str) -> ! { + self.tcx().sess.span_bug(self.span, s) } - fn report_candidate(&self, idx: uint, origin: &MethodOrigin) { - match *origin { - MethodStatic(impl_did) => { - let did = if self.report_statics == ReportStaticMethods { - // If we're reporting statics, we want to report the trait - // definition if possible, rather than an impl - match ty::trait_item_of_item(self.tcx(), impl_did) { - None | Some(TypeTraitItemId(_)) => { - debug!("(report candidate) No trait method \ - found"); - impl_did - } - Some(MethodTraitItemId(trait_did)) => { - debug!("(report candidate) Found trait ref"); - trait_did - } - } - } else { - // If it is an instantiated default method, use the original - // default method for error reporting. - match provided_source(self.tcx(), impl_did) { - None => impl_did, - Some(did) => did - } - }; - self.report_static_candidate(idx, did) - } - MethodStaticUnboxedClosure(did) => { - self.report_static_candidate(idx, did) - } - MethodTypeParam(ref mp) => { - self.report_param_candidate(idx, mp.trait_ref.def_id) + fn has_applicable_self(&self, method: &ty::Method) -> bool { + // "fast track" -- check for usage of sugar + match method.explicit_self { + StaticExplicitSelfCategory => { + // fallthrough } - MethodTraitObject(ref mo) => { - self.report_trait_candidate(idx, mo.trait_ref.def_id) + ByValueExplicitSelfCategory | + ByReferenceExplicitSelfCategory(..) | + ByBoxExplicitSelfCategory => { + return true; } } - } - fn report_static_candidate(&self, idx: uint, did: DefId) { - let span = if did.krate == ast::LOCAL_CRATE { - self.tcx().map.span(did.node) - } else { - self.span - }; - span_note!(self.tcx().sess, span, - "candidate #{} is `{}`", - idx + 1u, ty::item_path_str(self.tcx(), did)); - } - - fn report_param_candidate(&self, idx: uint, did: DefId) { - span_note!(self.tcx().sess, self.span, - "candidate #{} derives from the bound `{}`", - idx + 1u, ty::item_path_str(self.tcx(), did)); + // FIXME -- check for types that deref to `Self`, + // like `Rc` and so on. + // + // Note also that the current code will break if this type + // includes any of the type parameters defined on the method + // -- but this could be overcome. + return false; } - fn report_trait_candidate(&self, idx: uint, did: DefId) { - span_note!(self.tcx().sess, self.span, - "candidate #{} derives from the type of the receiver, \ - which is the trait `{}`", - idx + 1u, ty::item_path_str(self.tcx(), did)); + fn record_static_candidate(&mut self, source: CandidateSource) { + self.static_candidates.push(source); } - fn infcx(&'a self) -> &'a infer::InferCtxt<'a, 'tcx> { - &self.fcx.inh.infcx + fn xform_self_ty(&self, method: &Rc, substs: &subst::Substs) -> ty::t { + let xform_self_ty = method.fty.sig.inputs[0].subst(self.tcx(), substs); + self.replace_late_bound_regions_with_fresh_var(method.fty.sig.binder_id, &xform_self_ty) } - fn tcx(&self) -> &'a ty::ctxt<'tcx> { - self.fcx.tcx() + fn replace_late_bound_regions_with_fresh_var(&self, binder_id: ast::NodeId, value: &T) -> T + where T : TypeFoldable + Repr + { + let (_, value) = replace_late_bound_regions( + self.fcx.tcx(), + binder_id, + value, + |br| self.fcx.infcx().next_region_var(infer::LateBoundRegion(self.span, br))); + value } +} - fn ty_to_string(&self, t: ty::t) -> String { - self.fcx.infcx().ty_to_string(t) - } +fn trait_method(tcx: &ty::ctxt, + trait_def_id: ast::DefId, + method_name: ast::Name) + -> Option<(uint, Rc)> +{ + /*! + * Find method with name `method_name` defined in `trait_def_id` and return it, + * along with its index (or `None`, if no such method). + */ - fn did_to_string(&self, did: DefId) -> String { - ty::item_path_str(self.tcx(), did) - } + let trait_items = ty::trait_items(tcx, trait_def_id); + trait_items + .iter() + .enumerate() + .find(|&(_, ref item)| item.ident().name == method_name) + .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m))) +} - fn bug(&self, s: &str) -> ! { - self.tcx().sess.span_bug(self.span, s) - } +fn impl_method(tcx: &ty::ctxt, + impl_def_id: ast::DefId, + method_name: ast::Name) + -> Option> +{ + let impl_items = tcx.impl_items.borrow(); + let impl_items = impl_items.find(&impl_def_id).unwrap(); + impl_items + .iter() + .map(|&did| ty::impl_or_trait_item(tcx, did.def_id())) + .find(|m| m.ident().name == method_name) + .and_then(|item| item.as_opt_method()) } impl Repr for Candidate { fn repr(&self, tcx: &ty::ctxt) -> String { - format!("Candidate(rcvr_ty={}, rcvr_substs={}, method_ty={}, \ - origin={})", - self.rcvr_match_condition.repr(tcx), + format!("Candidate(rcvr_ty={}, rcvr_substs={}, method_ty={}, origin={})", + self.xform_self_ty.repr(tcx), self.rcvr_substs.repr(tcx), self.method_ty.repr(tcx), self.origin) } } -impl Repr for RcvrMatchCondition { +impl Repr for ExtensionCandidate { fn repr(&self, tcx: &ty::ctxt) -> String { - match *self { - RcvrMatchesIfObject(d) => { - format!("RcvrMatchesIfObject({})", d.repr(tcx)) + format!("ExtensionCandidate(obligation={}, xform_self_ty={}, method_ty={}, method_num={})", + self.obligation.repr(tcx), + self.xform_self_ty.repr(tcx), + self.method_ty.repr(tcx), + self.method_num) + } +} + +impl Candidate { + fn to_source(&self) -> CandidateSource { + match self.origin { + MethodStatic(def_id) => { + ImplSource(def_id) + } + MethodStaticUnboxedClosure(..) => { + fail!("MethodStaticUnboxedClosure only used in trans") } - RcvrMatchesIfSubtype(t) => { - format!("RcvrMatchesIfSubtype({})", t.repr(tcx)) + MethodTypeParam(ref param) => { + TraitSource(param.trait_ref.def_id) } - RcvrMatchesIfEqtype(t) => { - format!("RcvrMatchesIfEqtype({})", t.repr(tcx)) + MethodTraitObject(ref obj) => { + TraitSource(obj.trait_ref.def_id) } } } } + +impl ExtensionCandidate { + fn to_source(&self) -> CandidateSource { + TraitSource(self.obligation.trait_ref.def_id) + } +} diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 4aea9cfa293d3..5f7b31e573ade 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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::>(); - 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, lhs: &'a ast::Expr, rhs: Option<&P>, - 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| { diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 5d75d590a09f9..a448a93c5178f 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -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::FnSig) { - debug!("replace_late_bound_regions_in_fn_sig({})", fn_sig.repr(tcx)); +pub fn replace_late_bound_regions( + tcx: &ty::ctxt, + binder_id: ast::NodeId, + value: &T, + map_fn: |ty::BoundRegion| -> ty::Region) + -> (HashMap, 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 { diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs index 4c3cec1aff42f..dc79fd4aa328c 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc/middle/typeck/check/wf.rs @@ -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})); diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 9f88bec7f4225..e44aa3e8221b8 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -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))) } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 15c4830646d59..d2e062a20d2ec 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -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 { - // 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 { - 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 { + 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 { + (&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 { - 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 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)) => { diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 7c455b85707b8..a466581ef394a 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -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) { 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 {}", diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 158fda802ff00..4c04bcc5236f4 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -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), diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 60e4db405d766..b82a4a0b99718 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -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) } diff --git a/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs b/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs index 1e9fd035f44b5..000e42b970356 100644 --- a/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs +++ b/src/test/auxiliary/regions-bounded-method-type-parameters-cross-crate-lib.rs @@ -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!() } } diff --git a/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs new file mode 100644 index 0000000000000..c0d82d35e30f4 --- /dev/null +++ b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs @@ -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 or the MIT license +// , 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 MyTrait for T { //~ ERROR E0119 + fn get(&self) -> uint { 0 } +} + +impl MyTrait for T { + fn get(&self) -> uint { 0 } +} + +fn main() { } diff --git a/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs new file mode 100644 index 0000000000000..c44844bcf0b6c --- /dev/null +++ b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs @@ -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 or the MIT license +// , 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 MyTrait for T { //~ ERROR E0119 + fn get(&self) -> uint { 0 } +} + +impl MyTrait for T { + fn get(&self) -> uint { 0 } +} + +fn main() { } diff --git a/src/test/compile-fail/issue-17033.rs b/src/test/compile-fail/issue-17033.rs index 35adb29c9495d..7590546d40a7a 100644 --- a/src/test/compile-fail/issue-17033.rs +++ b/src/test/compile-fail/issue-17033.rs @@ -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() {} diff --git a/src/test/compile-fail/issue-17636.rs b/src/test/compile-fail/issue-17636.rs index 635a184a9d30c..ad2ebff59bc51 100644 --- a/src/test/compile-fail/issue-17636.rs +++ b/src/test/compile-fail/issue-17636.rs @@ -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 } diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index 81f57dd96402b..19d210f190595 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -18,6 +18,7 @@ impl vec_monad for Vec { 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() { diff --git a/src/test/compile-fail/issue-7575.rs b/src/test/compile-fail/issue-7575.rs index 768177785cfba..d5a1040d4b4d9 100644 --- a/src/test/compile-fail/issue-7575.rs +++ b/src/test/compile-fail/issue-7575.rs @@ -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 } } diff --git a/src/test/compile-fail/method-ambig-one-trait-coerce.rs b/src/test/compile-fail/method-ambig-one-trait-coerce.rs new file mode 100644 index 0000000000000..e5c3da10df8e9 --- /dev/null +++ b/src/test/compile-fail/method-ambig-one-trait-coerce.rs @@ -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 or the MIT license +// , 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 { + fn foo(self) -> int {1} +} + +impl foo for Box { + fn foo(self) -> int {2} +} + +fn test1(x: Box) { + // Ambiguous because we could coerce to either impl: + x.foo(); //~ ERROR E0034 +} + +fn test2(x: Box) { + // Not ambiguous because it is a precise match: + x.foo(); +} + +fn test3(x: Box) { + // Not ambiguous because it is a precise match: + x.foo(); +} + +fn main() { } diff --git a/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs new file mode 100644 index 0000000000000..e211db2dcd296 --- /dev/null +++ b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs @@ -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 or the MIT license +// , 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 { + fn foo(&self) -> int {1} +} + +impl foo for Vec { + 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() { } diff --git a/src/test/compile-fail/ambig_impl_2_exe.rs b/src/test/compile-fail/method-ambig-two-traits-cross-crate.rs similarity index 74% rename from src/test/compile-fail/ambig_impl_2_exe.rs rename to src/test/compile-fail/method-ambig-two-traits-cross-crate.rs index 13cceaa71ae06..30e635149c442 100644 --- a/src/test/compile-fail/ambig_impl_2_exe.rs +++ b/src/test/compile-fail/method-ambig-two-traits-cross-crate.rs @@ -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 + diff --git a/src/test/compile-fail/ambig_impl_bounds.rs b/src/test/compile-fail/method-ambig-two-traits-from-bounds.rs similarity index 76% rename from src/test/compile-fail/ambig_impl_bounds.rs rename to src/test/compile-fail/method-ambig-two-traits-from-bounds.rs index 9f26e5ae9b380..184927c01357a 100644 --- a/src/test/compile-fail/ambig_impl_bounds.rs +++ b/src/test/compile-fail/method-ambig-two-traits-from-bounds.rs @@ -12,9 +12,7 @@ trait A { fn foo(&self); } trait B { fn foo(&self); } fn foo(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() {} diff --git a/src/test/compile-fail/ambig-default-method.rs b/src/test/compile-fail/method-ambig-two-traits-with-default-method.rs similarity index 65% rename from src/test/compile-fail/ambig-default-method.rs rename to src/test/compile-fail/method-ambig-two-traits-with-default-method.rs index 56ab6d7da3f89..87efaed4e3dda 100644 --- a/src/test/compile-fail/ambig-default-method.rs +++ b/src/test/compile-fail/method-ambig-two-traits-with-default-method.rs @@ -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 } diff --git a/src/test/compile-fail/method-commit-to-trait.rs b/src/test/compile-fail/method-commit-to-trait.rs new file mode 100644 index 0000000000000..6e4b5e088c9fc --- /dev/null +++ b/src/test/compile-fail/method-commit-to-trait.rs @@ -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 or the MIT license +// , 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 Foo for Vec { + fn foo(self) -> int {1} +} + +fn test1(x: Vec) { + x.foo(); + //~^ ERROR `core::kinds::Copy` is not implemented for the type `T` +} + +fn main() { } diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs b/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs index 06f26800b5031..1705cfec6e2be 100644 --- a/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs +++ b/src/test/compile-fail/regions-bounded-method-type-parameters-cross-crate.rs @@ -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 } diff --git a/src/test/compile-fail/selftype-traittype.rs b/src/test/compile-fail/selftype-traittype.rs index bf7c3b261fd7d..44ee5002dce3d 100644 --- a/src/test/compile-fail/selftype-traittype.rs +++ b/src/test/compile-fail/selftype-traittype.rs @@ -14,7 +14,7 @@ trait add { } fn do_add(x: Box, y: Box) -> Box { - x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through an object + x.plus(y) //~ ERROR E0038 } fn main() {} diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs index c812b0d96a23d..0e1e66b40ce33 100644 --- a/src/test/compile-fail/unique-pinned-nocopy.rs +++ b/src/test/compile-fail/unique-pinned-nocopy.rs @@ -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); } diff --git a/src/test/compile-fail/unique-vec-res.rs b/src/test/compile-fail/unique-vec-res.rs index 79f29c6b359d6..62fabc0b33f3d 100644 --- a/src/test/compile-fail/unique-vec-res.rs +++ b/src/test/compile-fail/unique-vec-res.rs @@ -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())); } diff --git a/src/test/compile-fail/vec-res-add.rs b/src/test/compile-fail/vec-res-add.rs index bfd52d69cb217..6221806642c99 100644 --- a/src/test/compile-fail/vec-res-add.rs +++ b/src/test/compile-fail/vec-res-add.rs @@ -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 } diff --git a/src/test/compile-fail/wrong-mul-method-signature.rs b/src/test/compile-fail/wrong-mul-method-signature.rs index e3aed148a2390..aead739d3e01a 100644 --- a/src/test/compile-fail/wrong-mul-method-signature.rs +++ b/src/test/compile-fail/wrong-mul-method-signature.rs @@ -58,7 +58,13 @@ impl Mul 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; } diff --git a/src/test/compile-fail/ambig_impl_unify.rs b/src/test/run-pass/method-two-trait-defer-resolution-1.rs similarity index 56% rename from src/test/compile-fail/ambig_impl_unify.rs rename to src/test/run-pass/method-two-trait-defer-resolution-1.rs index 67b7a5a7f3700..e4ae33c1c5055 100644 --- a/src/test/compile-fail/ambig_impl_unify.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-1.rs @@ -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 { - fn foo(&self) -> int {1} //~ NOTE candidate #1 is `Vec.foo::foo` + fn foo(&self) -> int {1} } impl foo for Vec { - fn foo(&self) -> int {2} //~ NOTE candidate #2 is `Vec.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); } diff --git a/src/test/run-pass/method-two-trait-defer-resolution-2.rs b/src/test/run-pass/method-two-trait-defer-resolution-2.rs new file mode 100644 index 0000000000000..cae783e7ea84a --- /dev/null +++ b/src/test/run-pass/method-two-trait-defer-resolution-2.rs @@ -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 or the MIT license +// , 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 Foo for Vec { + fn foo(&self) -> int {1} +} + +impl Foo for Vec> { + 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); +}