diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2012-05-25 08:42:39 -0700 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2012-05-25 17:04:05 -0700 |
| commit | 98740a59da4f73617351098c118d707134e561a8 (patch) | |
| tree | 76c8556b15f12d4f6cd0e801f0433b857cf58535 /src/rustc | |
| parent | 93633ea7343d74c6447ed814c7435e9b1a3ff67a (diff) | |
| download | rust-98740a59da4f73617351098c118d707134e561a8.tar.gz rust-98740a59da4f73617351098c118d707134e561a8.zip | |
detect ambig. calls to iface bounds, use transactions
cc #2433
Diffstat (limited to 'src/rustc')
| -rw-r--r-- | src/rustc/middle/typeck/check.rs | 4 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/check/method.rs | 49 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/infer.rs | 37 |
3 files changed, 70 insertions, 20 deletions
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 07eeada10f8..7da1f27d3da 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -527,6 +527,10 @@ impl methods for @fn_ctxt { 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) } diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs index b6f01aed1fe..af27d8d8da1 100644 --- a/src/rustc/middle/typeck/check/method.rs +++ b/src/rustc/middle/typeck/check/method.rs @@ -45,6 +45,7 @@ impl methods for lookup { 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 @@ impl methods for lookup { // 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 @@ impl methods for lookup { // 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 @@ impl methods for lookup { // 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 @@ impl methods for lookup { }; 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, diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs index f94d1656c0b..d13123496b1 100644 --- a/src/rustc/middle/typeck/infer.rs +++ b/src/rustc/middle/typeck/infer.rs @@ -160,7 +160,7 @@ import util::common::{indent, indenter}; 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 @@ impl transaction_methods for infer_ctxt { 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 @@ impl transaction_methods for infer_ctxt { } 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 { |
