auto merge of #18121 : nikomatsakis/rust/method-call-use-trait-matching-infrastructure-2, r=pcwalton
Convert trait method dispatch to use new trait matching machinery. This fixes about 90% of #17918. What remains to be done is to make inherent dispatch work with conditional dispatch as well. I plan to do this in a future patch by generalizing the "method match" code slightly to work for inherent impls as well (the basic algorithm is precisely the same). Fixes #17178. This is a [breaking-change] for two reasons: 1. The old code was a bit broken. I found various minor cases, particularly around operators, where the old code incorrectly matched, but an extra `*` or other change is now required. (See commit e8cef25 ("Correct case where the old version of method lookup...") for examples.) 2. The old code didn't type check calls against the method signature from the *trait* but rather the *impl*. The two can be different in subtle ways. This makes the new method dispatch both more liberal and more conservative than the original. (See commit 8308332 ("The new method lookup mechanism typechecks...") for examples.) r? @pcwalton since he's been reviewing most of this series of changes f? @nick29581 for commit 39df55f ("Permit DST types to unify like other types") cc @aturon as this relates to library stabilization
This commit is contained in:
commit
3d2cf60631
|
@ -1374,7 +1374,7 @@ macro_rules! checkeddiv_int_impl(
|
||||||
if *v == 0 || (*self == $min && *v == -1) {
|
if *v == 0 || (*self == $min && *v == -1) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self / *v)
|
Some(*self / *v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1395,7 +1395,7 @@ macro_rules! checkeddiv_uint_impl(
|
||||||
if *v == 0 {
|
if *v == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self / *v)
|
Some(*self / *v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -638,7 +638,7 @@ shr_impl!(uint u8 u16 u32 u64 int i8 i16 i32 i64)
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
#[lang="index"]
|
#[lang="index"]
|
||||||
pub trait Index<Index, Result> {
|
pub trait Index<Index, Sized? Result> {
|
||||||
/// The method for the indexing (`Foo[Bar]`) operation
|
/// The method for the indexing (`Foo[Bar]`) operation
|
||||||
fn index<'a>(&'a self, index: &Index) -> &'a Result;
|
fn index<'a>(&'a self, index: &Index) -> &'a Result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
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 nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.inner.nodes() }
|
||||||
fn edges(&self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() }
|
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.inner.edges() }
|
||||||
fn source(&self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) }
|
fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.source(edge) }
|
||||||
fn target(&self, edge: &Edge<'a>) -> Node<'a> { self.inner.target(edge) }
|
fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.inner.target(edge) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
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();
|
let mut v = Vec::new();
|
||||||
self.graph.each_node(|i, nd| { v.push((i, nd)); true });
|
self.graph.each_node(|i, nd| { v.push((i, nd)); true });
|
||||||
dot::maybe_owned_vec::Growable(v)
|
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()
|
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();
|
let i = edge.source();
|
||||||
(i, self.graph.node(i))
|
(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();
|
let i = edge.target();
|
||||||
(i, self.graph.node(i))
|
(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>
|
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 nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() }
|
||||||
fn edges(&self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() }
|
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() }
|
||||||
fn source(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) }
|
fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) }
|
||||||
fn target(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) }
|
fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -272,4 +272,11 @@ nested obligation `int : Bar<U>` to find out that `U=uint`.
|
||||||
It would be good to only do *just as much* nested resolution as
|
It would be good to only do *just as much* nested resolution as
|
||||||
necessary. Currently, though, we just do a full resolution.
|
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.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,6 +24,8 @@ use syntax::codemap::{Span, DUMMY_SP};
|
||||||
pub use self::fulfill::FulfillmentContext;
|
pub use self::fulfill::FulfillmentContext;
|
||||||
pub use self::select::SelectionContext;
|
pub use self::select::SelectionContext;
|
||||||
pub use self::select::SelectionCache;
|
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::supertraits;
|
||||||
pub use self::util::transitive_bounds;
|
pub use self::util::transitive_bounds;
|
||||||
pub use self::util::Supertraits;
|
pub use self::util::Supertraits;
|
||||||
|
@ -219,22 +221,6 @@ pub struct VtableParamData {
|
||||||
pub bound: Rc<ty::TraitRef>,
|
pub bound: Rc<ty::TraitRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evaluate_obligation<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
|
||||||
param_env: &ty::ParameterEnvironment,
|
|
||||||
obligation: &Obligation,
|
|
||||||
typer: &Typer<'tcx>)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
* Attempts to resolve the obligation given. Returns `None` if
|
|
||||||
* we are unable to resolve, either because of ambiguity or
|
|
||||||
* due to insufficient inference.
|
|
||||||
*/
|
|
||||||
|
|
||||||
let mut selcx = select::SelectionContext::new(infcx, param_env, typer);
|
|
||||||
selcx.evaluate_obligation(obligation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
pub fn select_inherent_impl<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||||
param_env: &ty::ParameterEnvironment,
|
param_env: &ty::ParameterEnvironment,
|
||||||
typer: &Typer<'tcx>,
|
typer: &Typer<'tcx>,
|
||||||
|
|
|
@ -62,6 +62,23 @@ pub struct SelectionCache {
|
||||||
hashmap: RefCell<HashMap<Rc<ty::TraitRef>, SelectionResult<Candidate>>>,
|
hashmap: RefCell<HashMap<Rc<ty::TraitRef>, SelectionResult<Candidate>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum MethodMatchResult {
|
||||||
|
MethodMatched(MethodMatchedData),
|
||||||
|
MethodAmbiguous(/* list of impls that could apply */ Vec<ast::DefId>),
|
||||||
|
MethodDidNotMatch,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Show)]
|
||||||
|
pub enum MethodMatchedData {
|
||||||
|
// In the case of a precise match, we don't really need to store
|
||||||
|
// how the match was found. So don't.
|
||||||
|
PreciseMethodMatch,
|
||||||
|
|
||||||
|
// In the case of a coercion, we need to know the precise impl so
|
||||||
|
// that we can determine the type to which things were coerced.
|
||||||
|
CoerciveMethodMatch(/* impl we matched */ ast::DefId)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The selection process begins by considering all impls, where
|
* The selection process begins by considering all impls, where
|
||||||
* clauses, and so forth that might resolve an obligation. Sometimes
|
* clauses, and so forth that might resolve an obligation. Sometimes
|
||||||
|
@ -190,27 +207,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// EVALUATION
|
// EVALUATION
|
||||||
//
|
//
|
||||||
// Tests whether an obligation can be selected or whether an impl can be
|
// Tests whether an obligation can be selected or whether an impl
|
||||||
// applied to particular types. It skips the "confirmation" step and
|
// can be applied to particular types. It skips the "confirmation"
|
||||||
// hence completely ignores output type parameters.
|
// step and hence completely ignores output type parameters.
|
||||||
//
|
//
|
||||||
// The result is "true" if the obliation *may* hold and "false" if
|
// The result is "true" if the obliation *may* hold and "false" if
|
||||||
// we can be sure it does not.
|
// we can be sure it does not.
|
||||||
|
|
||||||
pub fn evaluate_obligation(&mut self,
|
pub fn evaluate_obligation_intercrate(&mut self,
|
||||||
obligation: &Obligation)
|
obligation: &Obligation)
|
||||||
-> bool
|
-> bool
|
||||||
{
|
{
|
||||||
/*!
|
/*!
|
||||||
* Evaluates whether the obligation `obligation` can be
|
* 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()));
|
obligation.repr(self.tcx()));
|
||||||
|
|
||||||
let stack = self.push_stack(None, obligation);
|
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,
|
fn evaluate_builtin_bound_recursively(&mut self,
|
||||||
|
@ -246,12 +287,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
obligation.repr(self.tcx()));
|
obligation.repr(self.tcx()));
|
||||||
|
|
||||||
let stack = self.push_stack(previous_stack.map(|x| x), obligation);
|
let stack = self.push_stack(previous_stack.map(|x| x), obligation);
|
||||||
let result = self.evaluate_stack(&stack);
|
|
||||||
|
// FIXME(#17901) -- Intercrate vs intracrate resolution is a
|
||||||
|
// tricky question here. For coherence, we want
|
||||||
|
// intercrate. Also, there was a nasty cycle around impls like
|
||||||
|
// `impl<T:Eq> Eq for Vec<T>` (which would wind up checking
|
||||||
|
// whether `$0:Eq`, where $0 was the value substituted for
|
||||||
|
// `T`, which could then be checked against the very same
|
||||||
|
// impl). This problem is avoided by the stricter rules around
|
||||||
|
// unbound type variables by intercrate. I suspect that in the
|
||||||
|
// latter case a more fine-grained rule would suffice (i.e.,
|
||||||
|
// consider it ambiguous if even 1 impl matches, no need to
|
||||||
|
// figure out which one, but call it unimplemented if 0 impls
|
||||||
|
// match).
|
||||||
|
let result = self.evaluate_stack_intercrate(&stack);
|
||||||
|
|
||||||
debug!("result: {}", result);
|
debug!("result: {}", result);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_stack(&mut self,
|
fn evaluate_stack_intercrate(&mut self,
|
||||||
stack: &ObligationStack)
|
stack: &ObligationStack)
|
||||||
-> EvaluationResult
|
-> EvaluationResult
|
||||||
{
|
{
|
||||||
|
@ -259,13 +314,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// an impl. Even if there are no impls in this crate, perhaps
|
// an impl. Even if there are no impls in this crate, perhaps
|
||||||
// the type would be unified with something from another crate
|
// the type would be unified with something from another crate
|
||||||
// that does provide an impl.
|
// 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)) {
|
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()));
|
stack.skol_trait_ref.repr(self.tcx()));
|
||||||
return EvaluatedToAmbig;
|
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
|
// If there is any previous entry on the stack that precisely
|
||||||
// matches this obligation, then we can assume that the
|
// matches this obligation, then we can assume that the
|
||||||
// obligation is satisfied for now (still all other conditions
|
// 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
|
.skip(1) // skip top-most frame
|
||||||
.any(|prev| stack.skol_trait_ref == prev.skol_trait_ref)
|
.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()));
|
stack.skol_trait_ref.repr(self.tcx()));
|
||||||
return EvaluatedToOk;
|
return EvaluatedToOk;
|
||||||
}
|
}
|
||||||
|
@ -320,7 +382,311 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
self.infcx.probe(|| {
|
self.infcx.probe(|| {
|
||||||
match self.match_impl(impl_def_id, obligation) {
|
match self.match_impl(impl_def_id, obligation) {
|
||||||
Ok(substs) => {
|
Ok(substs) => {
|
||||||
let vtable_impl = self.vtable_impl(impl_def_id, substs, obligation.cause, 0);
|
let vtable_impl = self.vtable_impl(impl_def_id,
|
||||||
|
substs,
|
||||||
|
obligation.cause,
|
||||||
|
obligation.recursion_depth + 1);
|
||||||
|
self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
|
||||||
|
}
|
||||||
|
Err(()) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// METHOD MATCHING
|
||||||
|
//
|
||||||
|
// Method matching is a variation on the normal select/evaluation
|
||||||
|
// situation. In this scenario, rather than having a full trait
|
||||||
|
// reference to select from, we start with an expression like
|
||||||
|
// `receiver.method(...)`. This means that we have `rcvr_ty`, the
|
||||||
|
// type of the receiver, and we have a possible trait that
|
||||||
|
// supplies `method`. We must determine whether the receiver is
|
||||||
|
// applicable, taking into account the transformed self type
|
||||||
|
// declared on `method`. We also must consider the possibility
|
||||||
|
// that `receiver` can be *coerced* into a suitable type (for
|
||||||
|
// example, a receiver type like `&(Any+Send)` might be coerced
|
||||||
|
// into a receiver like `&Any` to allow for method dispatch). See
|
||||||
|
// the body of `evaluate_method_obligation()` for more details on
|
||||||
|
// the algorithm.
|
||||||
|
|
||||||
|
pub fn evaluate_method_obligation(&mut self,
|
||||||
|
rcvr_ty: ty::t,
|
||||||
|
xform_self_ty: ty::t,
|
||||||
|
obligation: &Obligation)
|
||||||
|
-> MethodMatchResult
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
* Determine whether a trait-method is applicable to a receiver of
|
||||||
|
* type `rcvr_ty`. *Does not affect the inference state.*
|
||||||
|
*
|
||||||
|
* - `rcvr_ty` -- type of the receiver
|
||||||
|
* - `xform_self_ty` -- transformed self type declared on the method, with `Self`
|
||||||
|
* to a fresh type variable
|
||||||
|
* - `obligation` -- a reference to the trait where the method is declared, with
|
||||||
|
* the input types on the trait replaced with fresh type variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Here is the situation. We have a trait method declared (say) like so:
|
||||||
|
//
|
||||||
|
// trait TheTrait {
|
||||||
|
// fn the_method(self: Rc<Self>, ...) { ... }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// And then we have a call looking (say) like this:
|
||||||
|
//
|
||||||
|
// let x: Rc<Foo> = ...;
|
||||||
|
// x.the_method()
|
||||||
|
//
|
||||||
|
// Now we want to decide if `TheTrait` is applicable. As a
|
||||||
|
// human, we can see that `TheTrait` is applicable if there is
|
||||||
|
// an impl for the type `Foo`. But how does the compiler know
|
||||||
|
// what impl to look for, given that our receiver has type
|
||||||
|
// `Rc<Foo>`? We need to take the method's self type into
|
||||||
|
// account.
|
||||||
|
//
|
||||||
|
// On entry to this function, we have the following inputs:
|
||||||
|
//
|
||||||
|
// - `rcvr_ty = Rc<Foo>`
|
||||||
|
// - `xform_self_ty = Rc<$0>`
|
||||||
|
// - `obligation = $0 as TheTrait`
|
||||||
|
//
|
||||||
|
// We do the match in two phases. The first is a *precise
|
||||||
|
// match*, which means that no coercion is required. This is
|
||||||
|
// the preferred way to match. It works by first making
|
||||||
|
// `rcvr_ty` a subtype of `xform_self_ty`. This unifies `$0`
|
||||||
|
// and `Foo`. We can then evaluate (roughly as normal) the
|
||||||
|
// trait reference `Foo as TheTrait`.
|
||||||
|
//
|
||||||
|
// If this fails, we fallback to a coercive match, described below.
|
||||||
|
|
||||||
|
match self.infcx.probe(|| self.match_method_precise(rcvr_ty, xform_self_ty, obligation)) {
|
||||||
|
Ok(()) => { return MethodMatched(PreciseMethodMatch); }
|
||||||
|
Err(_) => { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coercive matches work slightly differently and cannot
|
||||||
|
// completely reuse the normal trait matching machinery
|
||||||
|
// (though they employ many of the same bits and pieces). To
|
||||||
|
// see how it works, let's continue with our previous example,
|
||||||
|
// but with the following declarations:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// trait Foo : Bar { .. }
|
||||||
|
// trait Bar : Baz { ... }
|
||||||
|
// trait Baz { ... }
|
||||||
|
// impl TheTrait for Bar {
|
||||||
|
// fn the_method(self: Rc<Bar>, ...) { ... }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Now we see that the receiver type `Rc<Foo>` is actually an
|
||||||
|
// object type. And in fact the impl we want is an impl on the
|
||||||
|
// supertrait `Rc<Bar>`. The precise matching procedure won't
|
||||||
|
// find it, however, because `Rc<Foo>` is not a subtype of
|
||||||
|
// `Rc<Bar>` -- it is *coercible* to `Rc<Bar>` (actually, such
|
||||||
|
// coercions are not yet implemented, but let's leave that
|
||||||
|
// aside for now).
|
||||||
|
//
|
||||||
|
// To handle this case, we employ a different procedure. Recall
|
||||||
|
// that our initial state is as follows:
|
||||||
|
//
|
||||||
|
// - `rcvr_ty = Rc<Foo>`
|
||||||
|
// - `xform_self_ty = Rc<$0>`
|
||||||
|
// - `obligation = $0 as TheTrait`
|
||||||
|
//
|
||||||
|
// We now go through each impl and instantiate all of its type
|
||||||
|
// variables, yielding the trait reference that the impl
|
||||||
|
// provides. In our example, the impl would provide `Bar as
|
||||||
|
// TheTrait`. Next we (try to) unify the trait reference that
|
||||||
|
// the impl provides with the input obligation. This would
|
||||||
|
// unify `$0` and `Bar`. Now we can see whether the receiver
|
||||||
|
// type (`Rc<Foo>`) is *coercible to* the transformed self
|
||||||
|
// type (`Rc<$0> == Rc<Bar>`). In this case, the answer is
|
||||||
|
// yes, so the impl is considered a candidate.
|
||||||
|
//
|
||||||
|
// Note that there is the possibility of ambiguity here, even
|
||||||
|
// when all types are known. In our example, this might occur
|
||||||
|
// if there was *also* an impl of `TheTrait` for `Baz`. In
|
||||||
|
// this case, `Rc<Foo>` would be coercible to both `Rc<Bar>`
|
||||||
|
// and `Rc<Baz>`. (Note that it is not a *coherence violation*
|
||||||
|
// to have impls for both `Bar` and `Baz`, despite this
|
||||||
|
// ambiguity). In this case, we report an error, listing all
|
||||||
|
// the applicable impls. The use can explicitly "up-coerce"
|
||||||
|
// to the type they want.
|
||||||
|
//
|
||||||
|
// Note that this coercion step only considers actual impls
|
||||||
|
// found in the source. This is because all the
|
||||||
|
// compiler-provided impls (such as those for unboxed
|
||||||
|
// closures) do not have relevant coercions. This simplifies
|
||||||
|
// life immensely.
|
||||||
|
|
||||||
|
let mut impls =
|
||||||
|
self.assemble_method_candidates_from_impls(rcvr_ty, xform_self_ty, obligation);
|
||||||
|
|
||||||
|
if impls.len() > 1 {
|
||||||
|
impls.retain(|&c| self.winnow_method_impl(c, rcvr_ty, xform_self_ty, obligation));
|
||||||
|
}
|
||||||
|
|
||||||
|
if impls.len() > 1 {
|
||||||
|
return MethodAmbiguous(impls);
|
||||||
|
}
|
||||||
|
|
||||||
|
match impls.pop() {
|
||||||
|
Some(def_id) => MethodMatched(CoerciveMethodMatch(def_id)),
|
||||||
|
None => MethodDidNotMatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn confirm_method_match(&mut self,
|
||||||
|
rcvr_ty: ty::t,
|
||||||
|
xform_self_ty: ty::t,
|
||||||
|
obligation: &Obligation,
|
||||||
|
data: MethodMatchedData)
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
* Given the successful result of a method match, this
|
||||||
|
* function "confirms" the result, which basically repeats the
|
||||||
|
* various matching operations, but outside of any snapshot so
|
||||||
|
* that their effects are committed into the inference state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
let is_ok = match data {
|
||||||
|
PreciseMethodMatch => {
|
||||||
|
self.match_method_precise(rcvr_ty, xform_self_ty, obligation).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
CoerciveMethodMatch(impl_def_id) => {
|
||||||
|
self.match_method_coerce(impl_def_id, rcvr_ty, xform_self_ty, obligation).is_ok()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !is_ok {
|
||||||
|
self.tcx().sess.span_bug(
|
||||||
|
obligation.cause.span,
|
||||||
|
format!("match not repeatable: {}, {}, {}, {}",
|
||||||
|
rcvr_ty.repr(self.tcx()),
|
||||||
|
xform_self_ty.repr(self.tcx()),
|
||||||
|
obligation.repr(self.tcx()),
|
||||||
|
data)[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_method_precise(&mut self,
|
||||||
|
rcvr_ty: ty::t,
|
||||||
|
xform_self_ty: ty::t,
|
||||||
|
obligation: &Obligation)
|
||||||
|
-> Result<(),()>
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
* Implements the *precise method match* procedure described in
|
||||||
|
* `evaluate_method_obligation()`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
self.infcx.commit_if_ok(|| {
|
||||||
|
match self.infcx.sub_types(false, infer::RelateSelfType(obligation.cause.span),
|
||||||
|
rcvr_ty, xform_self_ty) {
|
||||||
|
Ok(()) => { }
|
||||||
|
Err(_) => { return Err(()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.evaluate_obligation_intracrate(obligation) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assemble_method_candidates_from_impls(&mut self,
|
||||||
|
rcvr_ty: ty::t,
|
||||||
|
xform_self_ty: ty::t,
|
||||||
|
obligation: &Obligation)
|
||||||
|
-> Vec<ast::DefId>
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
* Assembles a list of potentially applicable impls using the
|
||||||
|
* *coercive match* procedure described in
|
||||||
|
* `evaluate_method_obligation()`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
let mut candidates = Vec::new();
|
||||||
|
|
||||||
|
let all_impls = self.all_impls(obligation.trait_ref.def_id);
|
||||||
|
for &impl_def_id in all_impls.iter() {
|
||||||
|
self.infcx.probe(|| {
|
||||||
|
match self.match_method_coerce(impl_def_id, rcvr_ty, xform_self_ty, obligation) {
|
||||||
|
Ok(_) => { candidates.push(impl_def_id); }
|
||||||
|
Err(_) => { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_method_coerce(&mut self,
|
||||||
|
impl_def_id: ast::DefId,
|
||||||
|
rcvr_ty: ty::t,
|
||||||
|
xform_self_ty: ty::t,
|
||||||
|
obligation: &Obligation)
|
||||||
|
-> Result<Substs, ()>
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
* Applies the *coercive match* procedure described in
|
||||||
|
* `evaluate_method_obligation()` to a particular impl.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This is almost always expected to succeed. It
|
||||||
|
// causes the impl's self-type etc to be unified with
|
||||||
|
// the type variable that is shared between
|
||||||
|
// obligation/xform_self_ty. In our example, after
|
||||||
|
// this is done, the type of `xform_self_ty` would
|
||||||
|
// change from `Rc<$0>` to `Rc<Foo>` (because $0 is
|
||||||
|
// unified with `Foo`).
|
||||||
|
let substs = try!(self.match_impl(impl_def_id, obligation));
|
||||||
|
|
||||||
|
// Next, check whether we can coerce. For now we require
|
||||||
|
// that the coercion be a no-op.
|
||||||
|
let origin = infer::Misc(obligation.cause.span);
|
||||||
|
match infer::mk_coercety(self.infcx, true, origin,
|
||||||
|
rcvr_ty, xform_self_ty) {
|
||||||
|
Ok(None) => { /* Fallthrough */ }
|
||||||
|
Ok(Some(_)) | Err(_) => { return Err(()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(substs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn winnow_method_impl(&mut self,
|
||||||
|
impl_def_id: ast::DefId,
|
||||||
|
rcvr_ty: ty::t,
|
||||||
|
xform_self_ty: ty::t,
|
||||||
|
obligation: &Obligation)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
* A version of `winnow_impl` applicable to coerice method
|
||||||
|
* matching. This is basically the same as `winnow_impl` but
|
||||||
|
* it uses the method matching procedure and is specific to
|
||||||
|
* impls.
|
||||||
|
*/
|
||||||
|
|
||||||
|
debug!("winnow_method_impl: impl_def_id={} rcvr_ty={} xform_self_ty={} obligation={}",
|
||||||
|
impl_def_id.repr(self.tcx()),
|
||||||
|
rcvr_ty.repr(self.tcx()),
|
||||||
|
xform_self_ty.repr(self.tcx()),
|
||||||
|
obligation.repr(self.tcx()));
|
||||||
|
|
||||||
|
self.infcx.probe(|| {
|
||||||
|
match self.match_method_coerce(impl_def_id, rcvr_ty, xform_self_ty, obligation) {
|
||||||
|
Ok(substs) => {
|
||||||
|
let vtable_impl = self.vtable_impl(impl_def_id,
|
||||||
|
substs,
|
||||||
|
obligation.cause,
|
||||||
|
obligation.recursion_depth + 1);
|
||||||
self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
|
self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply()
|
||||||
}
|
}
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
|
@ -456,24 +822,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are *NO* candidates, that might mean either that
|
// If there are *NO* candidates, that there are no impls --
|
||||||
// there is no impl or just that we can't know anything for
|
// that we know of, anyway. Note that in the case where there
|
||||||
// sure.
|
// 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 {
|
if candidates.len() == 0 {
|
||||||
// Annoying edge case: if there are no impls, then there
|
return Err(Unimplemented);
|
||||||
// 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)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just one candidate left.
|
// Just one candidate left.
|
||||||
|
@ -491,7 +850,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// scope. Otherwise, use the generic tcx cache, since the
|
// scope. Otherwise, use the generic tcx cache, since the
|
||||||
// result holds across all environments.
|
// result holds across all environments.
|
||||||
if
|
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))
|
|&t| ty::type_has_self(t) || ty::type_has_params(t))
|
||||||
{
|
{
|
||||||
&self.param_env.selection_cache
|
&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
|
// it'll do for now until we get the new trait-bound
|
||||||
// region skolemization working.
|
// region skolemization working.
|
||||||
let (_, new_signature) =
|
let (_, new_signature) =
|
||||||
regionmanip::replace_late_bound_regions_in_fn_sig(
|
regionmanip::replace_late_bound_regions(
|
||||||
self.tcx(),
|
self.tcx(),
|
||||||
|
closure_type.sig.binder_id,
|
||||||
&closure_type.sig,
|
&closure_type.sig,
|
||||||
|br| self.infcx.next_region_var(
|
|br| self.infcx.next_region_var(
|
||||||
infer::LateBoundRegion(obligation.cause.span, br)));
|
infer::LateBoundRegion(obligation.cause.span, br)));
|
||||||
|
@ -1365,6 +1725,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
trait_ref: Rc<ty::TraitRef>)
|
trait_ref: Rc<ty::TraitRef>)
|
||||||
-> Result<(),()>
|
-> Result<(),()>
|
||||||
{
|
{
|
||||||
|
debug!("match_trait_refs: obligation={} trait_ref={}",
|
||||||
|
obligation.repr(self.tcx()),
|
||||||
|
trait_ref.repr(self.tcx()));
|
||||||
|
|
||||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||||
match self.infcx.sub_trait_refs(false,
|
match self.infcx.sub_trait_refs(false,
|
||||||
origin,
|
origin,
|
||||||
|
@ -1648,3 +2012,13 @@ impl EvaluationResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MethodMatchResult {
|
||||||
|
pub fn may_apply(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
MethodMatched(_) => true,
|
||||||
|
MethodAmbiguous(_) => true,
|
||||||
|
MethodDidNotMatch => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -120,6 +120,13 @@ impl ImplOrTraitItem {
|
||||||
TypeTraitItem(ref associated_type) => associated_type.container,
|
TypeTraitItem(ref associated_type) => associated_type.container,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_opt_method(&self) -> Option<Rc<Method>> {
|
||||||
|
match *self {
|
||||||
|
MethodTraitItem(ref m) => Some((*m).clone()),
|
||||||
|
TypeTraitItem(_) => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -1240,9 +1247,21 @@ impl Generics {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TraitRef {
|
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 {
|
pub fn self_ty(&self) -> ty::t {
|
||||||
self.substs.self_ty().unwrap()
|
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
|
/// When type checking, we use the `ParameterEnvironment` to track
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -77,6 +77,7 @@ type parameter).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
use driver::session::Session;
|
||||||
use middle::const_eval;
|
use middle::const_eval;
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use middle::lang_items::IteratorItem;
|
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::astconv;
|
||||||
use middle::typeck::check::_match::pat_ctxt;
|
use middle::typeck::check::_match::pat_ctxt;
|
||||||
use middle::typeck::check::method::{AutoderefReceiver};
|
use middle::typeck::check::method::{AutoderefReceiver};
|
||||||
use middle::typeck::check::method::{AutoderefReceiverFlag};
|
|
||||||
use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
|
use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
|
||||||
use middle::typeck::check::method::{DontAutoderefReceiver};
|
use middle::typeck::check::regionmanip::replace_late_bound_regions;
|
||||||
use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods};
|
|
||||||
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
|
|
||||||
use middle::typeck::CrateCtxt;
|
use middle::typeck::CrateCtxt;
|
||||||
use middle::typeck::infer::{resolve_type, force_tvar};
|
use middle::typeck::infer::{resolve_type, force_tvar};
|
||||||
use middle::typeck::infer;
|
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.
|
// 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.
|
// 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})
|
ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1531,6 +1529,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&self.inh.infcx
|
&self.inh.infcx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sess(&self) -> &Session {
|
||||||
|
&self.tcx().sess
|
||||||
|
}
|
||||||
|
|
||||||
pub fn err_count_since_creation(&self) -> uint {
|
pub fn err_count_since_creation(&self) -> uint {
|
||||||
self.ccx.tcx.sess.err_count() - self.err_count_on_creation
|
self.ccx.tcx.sess.err_count() - self.err_count_on_creation
|
||||||
}
|
}
|
||||||
|
@ -2117,9 +2119,7 @@ fn try_overloaded_call<'a>(fcx: &FnCtxt,
|
||||||
method_name,
|
method_name,
|
||||||
function_trait,
|
function_trait,
|
||||||
callee_type,
|
callee_type,
|
||||||
[],
|
[]) {
|
||||||
DontAutoderefReceiver,
|
|
||||||
IgnoreStaticMethods) {
|
|
||||||
None => continue,
|
None => continue,
|
||||||
Some(method_callee) => method_callee,
|
Some(method_callee) => method_callee,
|
||||||
};
|
};
|
||||||
|
@ -2160,7 +2160,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
|
||||||
(PreferMutLvalue, Some(trait_did)) => {
|
(PreferMutLvalue, Some(trait_did)) => {
|
||||||
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
|
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
|
||||||
token::intern("deref_mut"), trait_did,
|
token::intern("deref_mut"), trait_did,
|
||||||
base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
|
base_ty, [])
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
|
@ -2170,7 +2170,7 @@ fn try_overloaded_deref(fcx: &FnCtxt,
|
||||||
(None, Some(trait_did)) => {
|
(None, Some(trait_did)) => {
|
||||||
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
|
method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
|
||||||
token::intern("deref"), trait_did,
|
token::intern("deref"), trait_did,
|
||||||
base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
|
base_ty, [])
|
||||||
}
|
}
|
||||||
(method, _) => method
|
(method, _) => method
|
||||||
};
|
};
|
||||||
|
@ -2231,9 +2231,7 @@ fn try_overloaded_slice(fcx: &FnCtxt,
|
||||||
token::intern(method_name),
|
token::intern(method_name),
|
||||||
trait_did,
|
trait_did,
|
||||||
base_ty,
|
base_ty,
|
||||||
[],
|
[])
|
||||||
DontAutoderefReceiver,
|
|
||||||
IgnoreStaticMethods)
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -2256,9 +2254,7 @@ fn try_overloaded_slice(fcx: &FnCtxt,
|
||||||
token::intern(method_name),
|
token::intern(method_name),
|
||||||
trait_did,
|
trait_did,
|
||||||
base_ty,
|
base_ty,
|
||||||
[],
|
[])
|
||||||
DontAutoderefReceiver,
|
|
||||||
IgnoreStaticMethods)
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -2314,9 +2310,7 @@ fn try_overloaded_index(fcx: &FnCtxt,
|
||||||
token::intern("index_mut"),
|
token::intern("index_mut"),
|
||||||
trait_did,
|
trait_did,
|
||||||
base_ty,
|
base_ty,
|
||||||
[],
|
[])
|
||||||
DontAutoderefReceiver,
|
|
||||||
IgnoreStaticMethods)
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
@ -2330,9 +2324,7 @@ fn try_overloaded_index(fcx: &FnCtxt,
|
||||||
token::intern("index"),
|
token::intern("index"),
|
||||||
trait_did,
|
trait_did,
|
||||||
base_ty,
|
base_ty,
|
||||||
[],
|
[])
|
||||||
DontAutoderefReceiver,
|
|
||||||
IgnoreStaticMethods)
|
|
||||||
}
|
}
|
||||||
(method, _) => method,
|
(method, _) => method,
|
||||||
};
|
};
|
||||||
|
@ -2376,9 +2368,7 @@ fn lookup_method_for_for_loop(fcx: &FnCtxt,
|
||||||
token::intern("next"),
|
token::intern("next"),
|
||||||
trait_did,
|
trait_did,
|
||||||
expr_type,
|
expr_type,
|
||||||
[],
|
[]);
|
||||||
DontAutoderefReceiver,
|
|
||||||
IgnoreStaticMethods);
|
|
||||||
|
|
||||||
// Regardless of whether the lookup succeeds, check the method arguments
|
// Regardless of whether the lookup succeeds, check the method arguments
|
||||||
// so that we have *some* type for each argument.
|
// 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
|
// Replace any bound regions that appear in the function
|
||||||
// signature with region variables
|
// 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))
|
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));
|
fcx.expr_ty(&*rcvr));
|
||||||
|
|
||||||
let tps = tps.iter().map(|ast_ty| fcx.to_ty(&**ast_ty)).collect::<Vec<_>>();
|
let tps = tps.iter().map(|ast_ty| fcx.to_ty(&**ast_ty)).collect::<Vec<_>>();
|
||||||
let fn_ty = match method::lookup(fcx, expr, &*rcvr,
|
let fn_ty = match method::lookup(fcx,
|
||||||
|
expr,
|
||||||
|
&*rcvr,
|
||||||
method_name.node.name,
|
method_name.node.name,
|
||||||
expr_t, tps.as_slice(),
|
expr_t,
|
||||||
|
tps.as_slice(),
|
||||||
DontDerefArgs,
|
DontDerefArgs,
|
||||||
CheckTraitsAndInherentMethods,
|
CheckTraitsAndInherentMethods,
|
||||||
AutoderefReceiver, IgnoreStaticMethods) {
|
AutoderefReceiver) {
|
||||||
Some(method) => {
|
Ok(method) => {
|
||||||
let method_ty = method.ty;
|
let method_ty = method.ty;
|
||||||
let method_call = MethodCall::expr(expr.id);
|
let method_call = MethodCall::expr(expr.id);
|
||||||
fcx.inh.method_map.borrow_mut().insert(method_call, method);
|
fcx.inh.method_map.borrow_mut().insert(method_call, method);
|
||||||
method_ty
|
method_ty
|
||||||
}
|
}
|
||||||
None => {
|
Err(error) => {
|
||||||
debug!("(checking method call) failing expr is {}", expr.id);
|
method::report_error(fcx, method_name.span, expr_t, method_name.node.name, error);
|
||||||
|
|
||||||
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
|
|
||||||
fcx.write_error(expr.id);
|
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()
|
ty::mk_err()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3069,13 +3037,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
trait_did: Option<ast::DefId>,
|
trait_did: Option<ast::DefId>,
|
||||||
lhs: &'a ast::Expr,
|
lhs: &'a ast::Expr,
|
||||||
rhs: Option<&P<ast::Expr>>,
|
rhs: Option<&P<ast::Expr>>,
|
||||||
autoderef_receiver: AutoderefReceiverFlag,
|
|
||||||
unbound_method: ||) -> ty::t {
|
unbound_method: ||) -> ty::t {
|
||||||
let method = match trait_did {
|
let method = match trait_did {
|
||||||
Some(trait_did) => {
|
Some(trait_did) => {
|
||||||
method::lookup_in_trait(fcx, op_ex.span, Some(lhs), opname,
|
method::lookup_in_trait(fcx, op_ex.span, Some(lhs), opname,
|
||||||
trait_did, lhs_ty, &[], autoderef_receiver,
|
trait_did, lhs_ty, &[])
|
||||||
IgnoreStaticMethods)
|
|
||||||
}
|
}
|
||||||
None => None
|
None => None
|
||||||
};
|
};
|
||||||
|
@ -3249,7 +3215,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
|
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| {
|
fcx.type_error_message(ex.span, |actual| {
|
||||||
format!("binary operation `{}` cannot be applied to type `{}`",
|
format!("binary operation `{}` cannot be applied to type `{}`",
|
||||||
ast_util::binop_to_string(op),
|
ast_util::binop_to_string(op),
|
||||||
|
@ -3266,7 +3232,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
rhs_expr: &ast::Expr,
|
rhs_expr: &ast::Expr,
|
||||||
rhs_t: ty::t) -> ty::t {
|
rhs_t: ty::t) -> ty::t {
|
||||||
lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
|
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| {
|
fcx.type_error_message(ex.span, |actual| {
|
||||||
format!("cannot apply unary operator `{}` to type `{}`",
|
format!("cannot apply unary operator `{}` to type `{}`",
|
||||||
op_str, actual)
|
op_str, actual)
|
||||||
|
@ -3360,8 +3326,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
match expected_sty {
|
match expected_sty {
|
||||||
Some(ty::ty_closure(ref cenv)) => {
|
Some(ty::ty_closure(ref cenv)) => {
|
||||||
let (_, sig) =
|
let (_, sig) =
|
||||||
replace_late_bound_regions_in_fn_sig(
|
replace_late_bound_regions(
|
||||||
tcx, &cenv.sig,
|
tcx, cenv.sig.binder_id, &cenv.sig,
|
||||||
|_| fcx.inh.infcx.fresh_bound_region(expr.id));
|
|_| fcx.inh.infcx.fresh_bound_region(expr.id));
|
||||||
let onceness = match (&store, &cenv.store) {
|
let onceness = match (&store, &cenv.store) {
|
||||||
// As the closure type and onceness go, only three
|
// As the closure type and onceness go, only three
|
||||||
|
@ -3479,9 +3445,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
tps.as_slice(),
|
tps.as_slice(),
|
||||||
DontDerefArgs,
|
DontDerefArgs,
|
||||||
CheckTraitsAndInherentMethods,
|
CheckTraitsAndInherentMethods,
|
||||||
AutoderefReceiver,
|
AutoderefReceiver) {
|
||||||
IgnoreStaticMethods) {
|
Ok(_) => {
|
||||||
Some(_) => {
|
|
||||||
fcx.type_error_message(
|
fcx.type_error_message(
|
||||||
field.span,
|
field.span,
|
||||||
|actual| {
|
|actual| {
|
||||||
|
@ -3494,7 +3459,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
"maybe a missing `()` to call it? If not, try an anonymous function.");
|
"maybe a missing `()` to call it? If not, try an anonymous function.");
|
||||||
}
|
}
|
||||||
|
|
||||||
None => {
|
Err(_) => {
|
||||||
fcx.type_error_message(
|
fcx.type_error_message(
|
||||||
expr.span,
|
expr.span,
|
||||||
|actual| {
|
|actual| {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
use middle::subst::{ParamSpace, Subst, Substs};
|
use middle::subst::{ParamSpace, Subst, Substs};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold;
|
use middle::ty_fold;
|
||||||
use middle::ty_fold::TypeFolder;
|
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
|
@ -23,31 +23,34 @@ use util::ppaux::Repr;
|
||||||
|
|
||||||
// Helper functions related to manipulating region types.
|
// Helper functions related to manipulating region types.
|
||||||
|
|
||||||
pub fn replace_late_bound_regions_in_fn_sig(
|
pub fn replace_late_bound_regions<T>(
|
||||||
tcx: &ty::ctxt,
|
tcx: &ty::ctxt,
|
||||||
fn_sig: &ty::FnSig,
|
binder_id: ast::NodeId,
|
||||||
mapf: |ty::BoundRegion| -> ty::Region)
|
value: &T,
|
||||||
-> (HashMap<ty::BoundRegion,ty::Region>, ty::FnSig) {
|
map_fn: |ty::BoundRegion| -> ty::Region)
|
||||||
debug!("replace_late_bound_regions_in_fn_sig({})", fn_sig.repr(tcx));
|
-> (HashMap<ty::BoundRegion,ty::Region>, T)
|
||||||
|
where T : TypeFoldable + Repr
|
||||||
|
{
|
||||||
|
debug!("replace_late_bound_regions(binder_id={}, value={})",
|
||||||
|
binder_id, value.repr(tcx));
|
||||||
|
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
let fn_sig = {
|
let new_value = {
|
||||||
let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
|
let mut folder = ty_fold::RegionFolder::regions(tcx, |r| {
|
||||||
debug!("region r={}", r.to_string());
|
|
||||||
match r {
|
match r {
|
||||||
ty::ReLateBound(s, br) if s == fn_sig.binder_id => {
|
ty::ReLateBound(s, br) if s == binder_id => {
|
||||||
* match map.entry(br) {
|
match map.entry(br) {
|
||||||
Vacant(entry) => entry.set(mapf(br)),
|
Vacant(entry) => *entry.set(map_fn(br)),
|
||||||
Occupied(entry) => entry.into_mut(),
|
Occupied(entry) => *entry.into_mut(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => r
|
_ => r
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ty_fold::super_fold_sig(&mut f, fn_sig)
|
value.fold_with(&mut folder)
|
||||||
};
|
};
|
||||||
debug!("resulting map: {}", map);
|
debug!("resulting map: {}", map);
|
||||||
(map, fn_sig)
|
(map, new_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum WfConstraint {
|
pub enum WfConstraint {
|
||||||
|
|
|
@ -15,7 +15,7 @@ use middle::ty;
|
||||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||||
use middle::typeck::astconv::AstConv;
|
use middle::typeck::astconv::AstConv;
|
||||||
use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable2, regionck};
|
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 middle::typeck::CrateCtxt;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
|
@ -373,8 +373,8 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
||||||
self.binding_count += 1;
|
self.binding_count += 1;
|
||||||
|
|
||||||
let (_, fn_sig) =
|
let (_, fn_sig) =
|
||||||
replace_late_bound_regions_in_fn_sig(
|
replace_late_bound_regions(
|
||||||
self.fcx.tcx(), fn_sig,
|
self.fcx.tcx(), fn_sig.binder_id, fn_sig,
|
||||||
|br| ty::ReFree(ty::FreeRegion{scope_id: self.scope_id,
|
|br| ty::ReFree(ty::FreeRegion{scope_id: self.scope_id,
|
||||||
bound_region: br}));
|
bound_region: br}));
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,6 @@ use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
|
||||||
use middle::typeck::infer::combine::{CombineFields, Combine};
|
use middle::typeck::infer::combine::{CombineFields, Combine};
|
||||||
use middle::typeck::infer::sub::Sub;
|
use middle::typeck::infer::sub::Sub;
|
||||||
use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
|
use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
|
||||||
use util::common::indenter;
|
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
|
@ -93,7 +92,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
debug!("Coerce.tys({} => {})",
|
debug!("Coerce.tys({} => {})",
|
||||||
a.repr(self.get_ref().infcx.tcx),
|
a.repr(self.get_ref().infcx.tcx),
|
||||||
b.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]`),
|
// 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
|
// 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|
|
self.unpack_actual_value(ty_b, |sty_b|
|
||||||
match (sty_a, 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);
|
let ty = ty::mk_vec(tcx, t_a, None);
|
||||||
Some((ty, ty::UnsizeLength(len)))
|
Some((ty, ty::UnsizeLength(len)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -363,28 +363,6 @@ pub fn super_fn_sigs<'tcx, C: Combine<'tcx>>(this: &C,
|
||||||
|
|
||||||
pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
|
pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
|
||||||
|
|
||||||
// This is a horrible hack - historically, [T] was not treated as a type,
|
|
||||||
// so, for example, &T and &[U] should not unify. In fact the only thing
|
|
||||||
// &[U] should unify with is &[T]. We preserve that behaviour with this
|
|
||||||
// check.
|
|
||||||
fn check_ptr_to_unsized<'tcx, C: Combine<'tcx>>(this: &C,
|
|
||||||
a: ty::t,
|
|
||||||
b: ty::t,
|
|
||||||
a_inner: ty::t,
|
|
||||||
b_inner: ty::t,
|
|
||||||
result: ty::t) -> cres<ty::t> {
|
|
||||||
match (&ty::get(a_inner).sty, &ty::get(b_inner).sty) {
|
|
||||||
(&ty::ty_vec(_, None), &ty::ty_vec(_, None)) |
|
|
||||||
(&ty::ty_str, &ty::ty_str) |
|
|
||||||
(&ty::ty_trait(..), &ty::ty_trait(..)) => Ok(result),
|
|
||||||
(&ty::ty_vec(_, None), _) | (_, &ty::ty_vec(_, None)) |
|
|
||||||
(&ty::ty_str, _) | (_, &ty::ty_str) |
|
|
||||||
(&ty::ty_trait(..), _) | (_, &ty::ty_trait(..))
|
|
||||||
=> Err(ty::terr_sorts(expected_found(this, a, b))),
|
|
||||||
_ => Ok(result),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let tcx = this.infcx().tcx;
|
let tcx = this.infcx().tcx;
|
||||||
let a_sty = &ty::get(a).sty;
|
let a_sty = &ty::get(a).sty;
|
||||||
let b_sty = &ty::get(b).sty;
|
let b_sty = &ty::get(b).sty;
|
||||||
|
@ -402,6 +380,10 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
|
||||||
b.repr(this.infcx().tcx)).as_slice());
|
b.repr(this.infcx().tcx)).as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(&ty::ty_err, _) | (_, &ty::ty_err) => {
|
||||||
|
Ok(ty::mk_err())
|
||||||
|
}
|
||||||
|
|
||||||
// Relate integral variables to other types
|
// Relate integral variables to other types
|
||||||
(&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
|
(&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
|
||||||
try!(this.infcx().simple_vars(this.a_is_expected(),
|
try!(this.infcx().simple_vars(this.a_is_expected(),
|
||||||
|
@ -442,8 +424,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
|
||||||
(&ty::ty_bool, _) |
|
(&ty::ty_bool, _) |
|
||||||
(&ty::ty_int(_), _) |
|
(&ty::ty_int(_), _) |
|
||||||
(&ty::ty_uint(_), _) |
|
(&ty::ty_uint(_), _) |
|
||||||
(&ty::ty_float(_), _) |
|
(&ty::ty_float(_), _) => {
|
||||||
(&ty::ty_err, _) => {
|
|
||||||
if ty::get(a).sty == ty::get(b).sty {
|
if ty::get(a).sty == ty::get(b).sty {
|
||||||
Ok(a)
|
Ok(a)
|
||||||
} else {
|
} else {
|
||||||
|
@ -494,13 +475,13 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
|
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
|
||||||
let typ = try!(this.tys(a_inner, b_inner));
|
let typ = try!(this.tys(a_inner, b_inner));
|
||||||
check_ptr_to_unsized(this, a, b, a_inner, b_inner, ty::mk_uniq(tcx, typ))
|
Ok(ty::mk_uniq(tcx, typ))
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
|
(&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
|
||||||
let mt = try!(this.mts(a_mt, 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))
|
Ok(ty::mk_ptr(tcx, mt))
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
|
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
|
||||||
|
@ -516,7 +497,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
|
||||||
}
|
}
|
||||||
_ => try!(this.mts(a_mt, b_mt))
|
_ => 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)) => {
|
(&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => {
|
||||||
|
|
|
@ -28,7 +28,7 @@ use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold;
|
use middle::ty_fold;
|
||||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
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::cell::{RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -962,7 +962,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
HashMap<ty::BoundRegion,
|
HashMap<ty::BoundRegion,
|
||||||
ty::Region>) {
|
ty::Region>) {
|
||||||
let (map, fn_sig) =
|
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(
|
let rvar = self.next_region_var(
|
||||||
BoundRegionInFnType(trace.origin.span(), br));
|
BoundRegionInFnType(trace.origin.span(), br));
|
||||||
debug!("Bound region {} maps to {}",
|
debug!("Bound region {} maps to {}",
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
use middle::ty::{BuiltinBounds};
|
use middle::ty::{BuiltinBounds};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty::TyVar;
|
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::combine::*;
|
||||||
use middle::typeck::infer::{cres, CresCompare};
|
use middle::typeck::infer::{cres, CresCompare};
|
||||||
use middle::typeck::infer::equate::Equate;
|
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);
|
.relate_vars(a_id, SubtypeOf, b_id);
|
||||||
Ok(a)
|
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)), _) => {
|
(&ty::ty_infer(TyVar(a_id)), _) => {
|
||||||
try!(self.fields
|
try!(self.fields
|
||||||
.switch_expected()
|
.switch_expected()
|
||||||
.instantiate(b, SupertypeOf, a_id));
|
.instantiate(b, SupertypeOf, a_id));
|
||||||
Ok(a)
|
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))) => {
|
(_, &ty::ty_infer(TyVar(b_id))) => {
|
||||||
try!(self.fields.instantiate(a, SubtypeOf, b_id));
|
try!(self.fields.instantiate(a, SubtypeOf, b_id));
|
||||||
Ok(a)
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(&ty::ty_err, _) | (_, &ty::ty_err) => {
|
||||||
|
Ok(ty::mk_err())
|
||||||
|
}
|
||||||
|
|
||||||
(_, &ty::ty_bot) => {
|
(_, &ty::ty_bot) => {
|
||||||
Err(ty::terr_sorts(expected_found(self, a, b)))
|
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
|
// Second, we instantiate each bound region in the supertype with a
|
||||||
// fresh concrete region.
|
// fresh concrete region.
|
||||||
let (skol_map, b_sig) = {
|
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);
|
let skol = self.fields.infcx.region_vars.new_skolemized(br);
|
||||||
debug!("Bound region {} skolemized to {}",
|
debug!("Bound region {} skolemized to {}",
|
||||||
bound_region_to_string(self.fields.infcx.tcx, "", false, br),
|
bound_region_to_string(self.fields.infcx.tcx, "", false, br),
|
||||||
|
|
|
@ -536,6 +536,14 @@ impl<'ast> Map<'ast> {
|
||||||
.unwrap_or_else(|| fail!("AstMap.span: could not find span for id {}", id))
|
.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 {
|
pub fn node_to_string(&self, id: NodeId) -> String {
|
||||||
node_id_to_string(self, id)
|
node_id_to_string(self, id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// Check that method bounds declared on traits/impls in a cross-crate
|
// 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> {
|
pub enum MaybeOwned<'a> {
|
||||||
Owned(int),
|
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.
|
// trait, so I'll use that as the template for this test.
|
||||||
pub trait IntoMaybeOwned<'a> {
|
pub trait IntoMaybeOwned<'a> {
|
||||||
fn into_maybe_owned(self) -> MaybeOwned<'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>);
|
fn bigger_region<'b:'a>(self, b: Inv<'b>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoMaybeOwned<'a> for Inv<'a> {
|
impl<'a> IntoMaybeOwned<'a> for Inv<'a> {
|
||||||
fn into_maybe_owned(self) -> MaybeOwned<'a> { fail!() }
|
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!() }
|
fn bigger_region<'b:'a>(self, b: Inv<'b>) { fail!() }
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::fmt::Show;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
// Test that two blanket impls conflict (at least without negative
|
||||||
|
// bounds). After all, some other crate could implement Even or Odd
|
||||||
|
// for the same type (though this crate doesn't).
|
||||||
|
|
||||||
|
trait MyTrait {
|
||||||
|
fn get(&self) -> uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Even { }
|
||||||
|
|
||||||
|
trait Odd { }
|
||||||
|
|
||||||
|
impl Even for int { }
|
||||||
|
|
||||||
|
impl Odd for uint { }
|
||||||
|
|
||||||
|
impl<T:Even> MyTrait for T { //~ ERROR E0119
|
||||||
|
fn get(&self) -> uint { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:Odd> MyTrait for T {
|
||||||
|
fn get(&self) -> uint { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::fmt::Show;
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
// Test that two blanket impls conflict (at least without negative
|
||||||
|
// bounds). After all, some other crate could implement Even or Odd
|
||||||
|
// for the same type (though this crate doesn't implement them at all).
|
||||||
|
|
||||||
|
trait MyTrait {
|
||||||
|
fn get(&self) -> uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Even { }
|
||||||
|
|
||||||
|
trait Odd { }
|
||||||
|
|
||||||
|
impl<T:Even> MyTrait for T { //~ ERROR E0119
|
||||||
|
fn get(&self) -> uint { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:Odd> MyTrait for T {
|
||||||
|
fn get(&self) -> uint { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -8,8 +8,10 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(overloaded_calls)]
|
||||||
|
|
||||||
fn f<'r>(p: &'r mut fn(p: &mut ())) {
|
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() {}
|
fn main() {}
|
||||||
|
|
|
@ -15,5 +15,5 @@ pub fn build_archive<'a, I: MyItem<&'a (|&uint|:'a)>>(files: I) {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
build_archive(&(|_| { }));
|
build_archive(&(|_| { }));
|
||||||
//~^ ERROR unable to infer enough type information to locate the impl of the trait `MyItem<&|&uint|
|
//~^ ERROR not implemented
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ impl<A> vec_monad<A> for Vec<A> {
|
||||||
let mut r = fail!();
|
let mut r = fail!();
|
||||||
for elt in self.iter() { r = r + f(*elt); }
|
for elt in self.iter() { r = r + f(*elt); }
|
||||||
//~^ ERROR the type of this value must be known
|
//~^ ERROR the type of this value must be known
|
||||||
|
//~^^ ERROR not implemented
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -8,17 +8,24 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test the mechanism for warning about possible missing `self` declarations.
|
||||||
|
|
||||||
trait CtxtFn {
|
trait CtxtFn {
|
||||||
fn f8(self, uint) -> uint;
|
fn f8(self, uint) -> uint;
|
||||||
fn f9(uint) -> uint; //~ NOTE candidate #
|
fn f9(uint) -> uint; //~ NOTE candidate
|
||||||
}
|
}
|
||||||
|
|
||||||
trait OtherTrait {
|
trait OtherTrait {
|
||||||
fn f9(uint) -> uint; //~ NOTE candidate #
|
fn f9(uint) -> uint; //~ NOTE candidate
|
||||||
}
|
}
|
||||||
|
|
||||||
trait UnusedTrait { // This should never show up as a candidate
|
// Note: this trait is not implemented, but we can't really tell
|
||||||
fn f9(uint) -> uint;
|
// 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 {
|
impl CtxtFn for uint {
|
||||||
|
@ -40,13 +47,13 @@ impl OtherTrait for uint {
|
||||||
struct MyInt(int);
|
struct MyInt(int);
|
||||||
|
|
||||||
impl MyInt {
|
impl MyInt {
|
||||||
fn fff(i: int) -> int { //~ NOTE candidate #1 is `MyInt::fff`
|
fn fff(i: int) -> int { //~ NOTE candidate
|
||||||
i
|
i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ManyImplTrait {
|
trait ManyImplTrait {
|
||||||
fn is_str() -> bool { //~ NOTE candidate #1 is
|
fn is_str() -> bool { //~ NOTE candidate
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that when we pick a trait based on coercion, versus subtyping,
|
||||||
|
// we consider all possible coercions equivalent and don't try to pick
|
||||||
|
// a best one.
|
||||||
|
|
||||||
|
trait Object { }
|
||||||
|
|
||||||
|
trait foo {
|
||||||
|
fn foo(self) -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl foo for Box<Object+'static> {
|
||||||
|
fn foo(self) -> int {1}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl foo for Box<Object+Send> {
|
||||||
|
fn foo(self) -> int {2}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test1(x: Box<Object+Send+Sync>) {
|
||||||
|
// Ambiguous because we could coerce to either impl:
|
||||||
|
x.foo(); //~ ERROR E0034
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test2(x: Box<Object+Send>) {
|
||||||
|
// Not ambiguous because it is a precise match:
|
||||||
|
x.foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test3(x: Box<Object+'static>) {
|
||||||
|
// Not ambiguous because it is a precise match:
|
||||||
|
x.foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that we invoking `foo()` successfully resolves to the trait `foo`
|
||||||
|
// (prompting the mismatched types error) but does not influence the choice
|
||||||
|
// of what kind of `Vec` we have, eventually leading to a type error.
|
||||||
|
|
||||||
|
trait foo {
|
||||||
|
fn foo(&self) -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl foo for Vec<uint> {
|
||||||
|
fn foo(&self) -> int {1}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl foo for Vec<int> {
|
||||||
|
fn foo(&self) -> int {2}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is very hokey: we have heuristics to suppress messages about
|
||||||
|
// type annotations required. But placing these two bits of code into
|
||||||
|
// distinct functions, in this order, causes us to print out both
|
||||||
|
// errors I'd like to see.
|
||||||
|
|
||||||
|
fn m1() {
|
||||||
|
// we couldn't infer the type of the vector just based on calling foo()...
|
||||||
|
let mut x = Vec::new(); //~ ERROR type annotations required
|
||||||
|
x.foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn m2() {
|
||||||
|
let mut x = Vec::new();
|
||||||
|
|
||||||
|
// ...but we still resolved `foo()` to the trait and hence know the return type.
|
||||||
|
let y: uint = x.foo(); //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -8,12 +8,15 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// 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
|
// aux-build:ambig_impl_2_lib.rs
|
||||||
extern crate ambig_impl_2_lib;
|
extern crate ambig_impl_2_lib;
|
||||||
use ambig_impl_2_lib::me;
|
use ambig_impl_2_lib::me;
|
||||||
trait me2 {
|
trait me2 {
|
||||||
fn me(&self) -> uint;
|
fn me(&self) -> uint;
|
||||||
}
|
}
|
||||||
impl me2 for uint { fn me(&self) -> uint { *self } } //~ NOTE is `uint.me2::me`
|
impl me2 for uint { fn me(&self) -> uint { *self } }
|
||||||
fn main() { 1u.me(); } //~ ERROR multiple applicable methods in scope
|
fn main() { 1u.me(); } //~ ERROR E0034
|
||||||
//~^ NOTE is `ambig_impl_2_lib::uint.me::me`
|
|
|
@ -12,9 +12,7 @@ trait A { fn foo(&self); }
|
||||||
trait B { fn foo(&self); }
|
trait B { fn foo(&self); }
|
||||||
|
|
||||||
fn foo<T:A + B>(t: T) {
|
fn foo<T:A + B>(t: T) {
|
||||||
t.foo(); //~ ERROR multiple applicable methods in scope
|
t.foo(); //~ ERROR E0034
|
||||||
//~^ NOTE candidate #1 derives from the bound `A`
|
|
||||||
//~^^ NOTE candidate #2 derives from the bound `B`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
|
@ -8,12 +8,16 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
trait Foo { fn method(&self) {} } //~ NOTE `Foo::method`
|
// Test that we correctly report an ambiguity where two applicable traits
|
||||||
trait Bar { fn method(&self) {} } //~ NOTE `Bar::method`
|
// 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 Foo for uint {}
|
||||||
impl Bar for uint {}
|
impl Bar for uint {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
1u.method(); //~ ERROR multiple applicable methods in scope
|
1u.method(); //~ ERROR E0034
|
||||||
}
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that we pick `Foo`, and also pick the `impl`, even though in
|
||||||
|
// this case the vector type `T` is not copyable. This is because
|
||||||
|
// there is no other reasonable choice. The error you see is thus
|
||||||
|
// about `T` being non-copyable, not about `Foo` being
|
||||||
|
// unimplemented. This is better for user too, since it suggests minimal
|
||||||
|
// diff requird to fix program.
|
||||||
|
|
||||||
|
trait Object { }
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
fn foo(self) -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:Copy> Foo for Vec<T> {
|
||||||
|
fn foo(self) -> int {1}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test1<T>(x: Vec<T>) {
|
||||||
|
x.foo();
|
||||||
|
//~^ ERROR `core::kinds::Copy` is not implemented for the type `T`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -18,15 +18,15 @@ use lib::Inv;
|
||||||
use lib::MaybeOwned;
|
use lib::MaybeOwned;
|
||||||
use lib::IntoMaybeOwned;
|
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
|
// Exercise a code path I found to be buggy. We were not encoding
|
||||||
// the region parameters from the receiver correctly on trait
|
// the region parameters from the receiver correctly on trait
|
||||||
// methods.
|
// methods.
|
||||||
f.into_maybe_owned();
|
f.into_maybe_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_bigger_region<'a, 'b>(a: Inv<'a>, b: Inv<'b>) {
|
fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
|
||||||
// Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
|
// Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
|
||||||
a.bigger_region(b) //~ ERROR cannot infer
|
a.bigger_region(b) //~ ERROR cannot infer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ trait add {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_add(x: Box<add+'static>, y: Box<add+'static>) -> Box<add+'static> {
|
fn do_add(x: Box<add+'static>, y: Box<add+'static>) -> Box<add+'static> {
|
||||||
x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through an object
|
x.plus(y) //~ ERROR E0038
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -19,6 +19,6 @@ impl Drop for r {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let i = box r { b: true };
|
let i = box r { b: true };
|
||||||
let _j = i.clone(); //~ ERROR not implemented
|
let _j = i.clone(); //~ ERROR not implement
|
||||||
println!("{}", i);
|
println!("{}", i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,8 @@ fn main() {
|
||||||
let r1 = vec!(box r { i: i1 });
|
let r1 = vec!(box r { i: i1 });
|
||||||
let r2 = vec!(box r { i: i2 });
|
let r2 = vec!(box r { i: i2 });
|
||||||
f(r1.clone(), r2.clone());
|
f(r1.clone(), r2.clone());
|
||||||
//~^ ERROR the trait `core::clone::Clone` is not implemented
|
//~^ ERROR does not implement any method in scope named `clone`
|
||||||
//~^^ ERROR the trait `core::clone::Clone` is not implemented
|
//~^^ ERROR does not implement any method in scope named `clone`
|
||||||
println!("{}", (r2, i1.get()));
|
println!("{}", (r2, i1.get()));
|
||||||
println!("{}", (r1, i2.get()));
|
println!("{}", (r1, i2.get()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[deriving(Show)]
|
||||||
struct r {
|
struct r {
|
||||||
i:int
|
i:int
|
||||||
}
|
}
|
||||||
|
@ -23,7 +24,6 @@ fn main() {
|
||||||
let i = vec!(r(0));
|
let i = vec!(r(0));
|
||||||
let j = vec!(r(1));
|
let j = vec!(r(1));
|
||||||
let k = i + j;
|
let k = i + j;
|
||||||
//~^ ERROR not implemented
|
//~^ ERROR binary operation `+` cannot be applied to type
|
||||||
println!("{}", j);
|
println!("{}", j);
|
||||||
//~^ ERROR not implemented
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,13 @@ impl Mul<f64, i32> for Vec3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
Vec1 { x: 1.0 } * 2.0;
|
// Check that the usage goes from the trait declaration:
|
||||||
Vec2 { x: 1.0, y: 2.0 } * 2.0;
|
|
||||||
Vec3 { x: 1.0, y: 2.0, z: 3.0 } * 2.0;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,20 +8,36 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that we pick which version of `foo` to run based on the
|
||||||
|
// type that is (ultimately) inferred for `x`.
|
||||||
|
|
||||||
trait foo {
|
trait foo {
|
||||||
fn foo(&self) -> int;
|
fn foo(&self) -> int;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl foo for Vec<uint> {
|
impl foo for Vec<uint> {
|
||||||
fn foo(&self) -> int {1} //~ NOTE candidate #1 is `Vec<uint>.foo::foo`
|
fn foo(&self) -> int {1}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl foo for Vec<int> {
|
impl foo for Vec<int> {
|
||||||
fn foo(&self) -> int {2} //~ NOTE candidate #2 is `Vec<int>.foo::foo`
|
fn foo(&self) -> int {2}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_foo_uint() -> int {
|
||||||
|
let mut x = Vec::new();
|
||||||
|
let y = x.foo();
|
||||||
|
x.push(0u);
|
||||||
|
y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_foo_int() -> int {
|
||||||
|
let mut x = Vec::new();
|
||||||
|
let y = x.foo();
|
||||||
|
x.push(0i);
|
||||||
|
y
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = Vec::new();
|
assert_eq!(call_foo_uint(), 1);
|
||||||
x.foo(); //~ ERROR multiple applicable methods in scope
|
assert_eq!(call_foo_int(), 2);
|
||||||
}
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that we pick which version of `Foo` to run based on whether
|
||||||
|
// the type we (ultimately) inferred for `x` is copyable or not.
|
||||||
|
//
|
||||||
|
// In this case, the two versions are both impls of same trait, and
|
||||||
|
// hence we we can resolve method even without knowing yet which
|
||||||
|
// version will run (note that the `push` occurs after the call to
|
||||||
|
// `foo()`).
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
fn foo(&self) -> int;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:Copy> Foo for Vec<T> {
|
||||||
|
fn foo(&self) -> int {1}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Foo for Vec<Box<T>> {
|
||||||
|
fn foo(&self) -> int {2}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_foo_copy() -> int {
|
||||||
|
let mut x = Vec::new();
|
||||||
|
let y = x.foo();
|
||||||
|
x.push(0u);
|
||||||
|
y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_foo_other() -> int {
|
||||||
|
let mut x = Vec::new();
|
||||||
|
let y = x.foo();
|
||||||
|
x.push(box 0i);
|
||||||
|
y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(call_foo_copy(), 1);
|
||||||
|
assert_eq!(call_foo_other(), 2);
|
||||||
|
}
|
Loading…
Reference in New Issue