提交 98740a59 编写于 作者: N Niko Matsakis

detect ambig. calls to iface bounds, use transactions

cc #2433
上级 93633ea7
......@@ -527,6 +527,10 @@ fn mk_subty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
infer::mk_subty(self.infcx, sub, sup)
}
fn can_mk_subty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
infer::can_mk_subty(self.infcx, sub, sup)
}
fn mk_eqty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
infer::mk_eqty(self.infcx, sub, sup)
}
......
......@@ -45,6 +45,7 @@ fn method_from_param(n: uint, did: ast::def_id) -> option<method_origin> {
let tcx = self.tcx();
let mut iface_bnd_idx = 0u; // count only iface bounds
let bounds = tcx.ty_param_bounds.get(did.node);
let mut candidates = [];
for vec::each(*bounds) {|bound|
let (iid, bound_substs) = alt bound {
ty::bound_copy | ty::bound_send | ty::bound_const {
......@@ -74,14 +75,33 @@ fn method_from_param(n: uint, did: ast::def_id) -> option<method_origin> {
// permitted).
let substs = {self_ty: some(self.self_ty)
with bound_substs};
ret some(self.write_mty_from_m(
substs, ifce_methods[pos],
method_param(iid, pos, n, iface_bnd_idx)));
candidates += [(substs, ifce_methods[pos],
iid, pos, n, iface_bnd_idx)];
}
}
}
ret none;
if candidates.len() == 0u {
ret none;
}
if candidates.len() > 1u {
self.tcx().sess.span_err(
self.expr.span,
"multiple applicable methods in scope");
for candidates.eachi { |i, candidate|
let (_, _, iid, _, _, _) = candidate;
self.tcx().sess.span_note(
self.expr.span,
#fmt["candidate #%u derives from the bound `%s`",
(i+1u), ty::item_path_str(self.tcx(), iid)]);
}
}
let (substs, mty, iid, pos, n, iface_bnd_idx) = candidates[0u];
ret some(self.write_mty_from_m(
substs, mty, method_param(iid, pos, n, iface_bnd_idx)));
}
fn method_from_iface(
......@@ -197,10 +217,11 @@ fn method_from_scope() -> option<method_origin> {
// if we can assign the caller to the callee, that's a
// potential match. Collect those in the vector.
alt self.fcx.mk_subty(ty, self_ty) {
alt self.fcx.can_mk_subty(ty, self_ty) {
result::err(_) { /* keep looking */ }
result::ok(_) {
results += [(self_substs, m.n_tps, m.did)];
results += [(ty, self_ty, self_substs,
m.n_tps, m.did)];
}
}
}
......@@ -216,7 +237,7 @@ fn method_from_scope() -> option<method_origin> {
// but I cannot for the life of me figure out how to
// annotate resolve to preserve this information.
for results.eachi { |i, result|
let (_, _, did) = result;
let (_, _, _, _, did) = result;
let span = if did.crate == ast::local_crate {
alt check self.tcx().items.get(did.node) {
ast_map::node_method(m, _, _) { m.span }
......@@ -226,13 +247,21 @@ fn method_from_scope() -> option<method_origin> {
};
self.tcx().sess.span_note(
span,
#fmt["candidate #%u is %s",
#fmt["candidate #%u is `%s`",
(i+1u),
ty::item_path_str(self.tcx(), did)]);
}
}
let (self_substs, n_tps, did) = results[0];
let (ty, self_ty, self_substs, n_tps, did) = results[0];
alt self.fcx.mk_subty(ty, self_ty) {
result::ok(_) {}
result::err(_) {
self.tcx().sess.span_bug(
self.expr.span,
"what was a subtype now is not?");
}
}
let fty = self.ty_from_did(did);
ret some(self.write_mty_from_fty(
self_substs, n_tps, fty,
......
......@@ -160,7 +160,7 @@ fn bar() {
export infer_ctxt;
export new_infer_ctxt;
export mk_subty;
export mk_subty, can_mk_subty;
export mk_subr;
export mk_eqty;
export mk_assignty;
......@@ -235,6 +235,11 @@ fn mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
indent {|| cx.commit {|| sub(cx).tys(a, b) } }.to_ures()
}
fn can_mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
#debug["can_mk_subty(%s <: %s)", a.to_str(cx), b.to_str(cx)];
indent {|| cx.probe {|| sub(cx).tys(a, b) } }.to_ures()
}
fn mk_subr(cx: infer_ctxt, a: ty::region, b: ty::region) -> ures {
#debug["mk_subr(%s <: %s)", a.to_str(cx), b.to_str(cx)];
indent {|| cx.commit {|| sub(cx).regions(a, b) } }.to_ures()
......@@ -388,7 +393,17 @@ fn uok() -> ures {
ok(())
}
fn rollback_to<V:copy vid, T:copy>(
vb: vals_and_bindings<V, T>, len: uint) {
while vb.bindings.len() != len {
let (vid, old_v) = vec::pop(vb.bindings);
vb.vals.insert(vid.to_uint(), old_v);
}
}
impl transaction_methods for infer_ctxt {
#[doc = "Execute `f` and commit the bindings if successful"]
fn commit<T,E>(f: fn() -> result<T,E>) -> result<T,E> {
assert self.vb.bindings.len() == 0u;
......@@ -404,17 +419,9 @@ fn commit<T,E>(f: fn() -> result<T,E>) -> result<T,E> {
ret r;
}
#[doc = "Execute `f`, unroll bindings on failure"]
fn try<T,E>(f: fn() -> result<T,E>) -> result<T,E> {
fn rollback_to<V:copy vid, T:copy>(
vb: vals_and_bindings<V, T>, len: uint) {
while vb.bindings.len() != len {
let (vid, old_v) = vec::pop(vb.bindings);
vb.vals.insert(vid.to_uint(), old_v);
}
}
let vbl = self.vb.bindings.len();
let rbl = self.rb.bindings.len();
#debug["try(vbl=%u, rbl=%u)", vbl, rbl];
......@@ -429,6 +436,16 @@ fn rollback_to<V:copy vid, T:copy>(
}
ret r;
}
#[doc = "Execute `f` then unroll any bindings it creates"]
fn probe<T,E>(f: fn() -> result<T,E>) -> result<T,E> {
assert self.vb.bindings.len() == 0u;
assert self.rb.bindings.len() == 0u;
let r <- f();
rollback_to(self.vb, 0u);
rollback_to(self.rb, 0u);
ret r;
}
}
impl methods for infer_ctxt {
......
impl methods1 for uint { fn me() -> uint { self } } //! NOTE candidate #1 is methods1::me
impl methods2 for uint { fn me() -> uint { self } } //! NOTE candidate #2 is methods2::me
impl methods1 for uint { fn me() -> uint { self } } //! NOTE candidate #1 is `methods1::me`
impl methods2 for uint { fn me() -> uint { self } } //! NOTE candidate #2 is `methods2::me`
fn main() { 1u.me(); } //! ERROR multiple applicable methods in scope
......@@ -2,6 +2,6 @@
// aux-build:ambig_impl_2_lib.rs
use ambig_impl_2_lib;
import ambig_impl_2_lib::methods1;
impl methods2 for uint { fn me() -> uint { self } } //! NOTE candidate #2 is methods2::me
impl methods2 for uint { fn me() -> uint { self } } //! NOTE candidate #2 is `methods2::me`
fn main() { 1u.me(); } //! ERROR multiple applicable methods in scope
//!^ NOTE candidate #1 is ambig_impl_2_lib::methods1::me
//!^ NOTE candidate #1 is `ambig_impl_2_lib::methods1::me`
iface A { fn foo(); }
iface B { fn foo(); }
fn foo<T: A B>(t: T) {
t.foo(); //! ERROR multiple applicable methods in scope
//!^ NOTE candidate #1 derives from the bound `A`
//!^^ NOTE candidate #2 derives from the bound `B`
}
fn main() {}
\ No newline at end of file
impl methods for [uint] {
fn foo() -> int {1} //! NOTE candidate #1 is `methods::foo`
}
impl methods for [int] {
fn foo() -> int {2} //! NOTE candidate #2 is `methods::foo`
}
fn main() {
let x = [];
x.foo(); //! ERROR multiple applicable methods in scope
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册